static int read_header(uint32_t blk_number, uint8_t *sam_stat) { loff_t nread; if (blk_number > eod_blk_number) { MHVTL_ERR("Attempt to seek [%d] beyond EOD [%d]", blk_number, eod_blk_number); } else if (blk_number == eod_blk_number) mkEODHeader(eod_blk_number, eod_data_offset); else { nread = pread(indxfile, &raw_pos, sizeof(raw_pos), blk_number * sizeof(raw_pos)); if (nread < 0) { MHVTL_ERR("Medium format corrupt"); sam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat); return -1; } else if (nread != sizeof(raw_pos)) { MHVTL_ERR("Failed to read next header"); sam_medium_error(E_END_OF_DATA, sam_stat); return -1; } } MHVTL_DBG(3, "Reading header %d at offset %ld, type: %s, size: %d", raw_pos.hdr.blk_number, (unsigned long)raw_pos.data_offset, mhvtl_block_type_desc(raw_pos.hdr.blk_type), raw_pos.hdr.blk_size); return 0; }
static void init_3592_inquiry(struct lu_phy_attr *lu) { int pg; uint8_t worm; uint8_t local_TapeAlert[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; worm = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_WORM; lu->inquiry[2] = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION; /* Sequential Access device capabilities - Ref: 8.4.2 */ pg = PCODE_OFFSET(0xb0); lu->lu_vpd[pg] = alloc_vpd(VPD_B0_SZ); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_b0(lu, &worm); /* Manufacture-assigned serial number - Ref: 8.4.3 */ pg = PCODE_OFFSET(0xb1); lu->lu_vpd[pg] = alloc_vpd(VPD_B1_SZ); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_b1(lu, lu->lu_serial_no); /* TapeAlert supported flags - Ref: 8.4.4 */ pg = PCODE_OFFSET(0xb2); lu->lu_vpd[pg] = alloc_vpd(VPD_B2_SZ); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_b2(lu, &local_TapeAlert); /* VPD page 0xC0 */ pg = PCODE_OFFSET(0xc0); lu->lu_vpd[pg] = alloc_vpd(VPD_C0_SZ); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_c0(lu, "10-03-2008 19:38:00"); /* VPD page 0xC1 */ pg = PCODE_OFFSET(0xc1); lu->lu_vpd[pg] = alloc_vpd(strlen("Security")); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_c1(lu, "Security"); }
static int check_for_overwrite(uint8_t *sam_stat) { uint32_t blk_number; uint64_t data_offset; unsigned int i; if (raw_pos.hdr.blk_type == B_EOD) { return 0; } MHVTL_DBG(2, "At block %ld", (unsigned long)raw_pos.hdr.blk_number); /* We aren't at EOD so we are performing a rewrite. Truncate the data and index files back to the current length. */ blk_number = raw_pos.hdr.blk_number; data_offset = raw_pos.data_offset; if (ftruncate(indxfile, blk_number * sizeof(raw_pos))) { mkSenseBuf(MEDIUM_ERROR, E_WRITE_ERROR, sam_stat); MHVTL_ERR("Index file ftruncate failure, pos: " "%" PRId64 ": %s", (uint64_t)blk_number * sizeof(raw_pos), strerror(errno)); return -1; } if (ftruncate(datafile, data_offset)) { mkSenseBuf(MEDIUM_ERROR, E_WRITE_ERROR, sam_stat); MHVTL_ERR("Data file ftruncate failure, pos: " "%" PRId64 ": %s", data_offset, strerror(errno)); return -1; } /* Update the filemark map removing any filemarks which will be overwritten. Rewrite the filemark map so that the on-disk image of the map is consistent with the new sizes of the other two files. */ for (i = 0; i < meta.filemark_count; i++) { MHVTL_DBG(2, "filemarks[%d] %d", i, filemarks[i]); if (filemarks[i] >= blk_number) { MHVTL_DBG(2, "Setting filemark_count from %d to %d", meta.filemark_count, i); meta.filemark_count = i; return rewrite_meta_file(); } } return 0; }
static int rewrite_meta_file(void) { ssize_t io_size, nwrite; size_t io_offset; io_size = sizeof(meta); io_offset = sizeof(struct MAM); nwrite = pwrite(metafile, &meta, io_size, io_offset); if (nwrite < 0) { MHVTL_ERR("Error writing meta_header to metafile: %s", strerror(errno)); return -1; } if (nwrite != io_size) { MHVTL_ERR("Error writing meta_header map to metafile." " Expected to write %d bytes", (int)io_size); return -1; } io_size = meta.filemark_count * sizeof(*filemarks); io_offset = sizeof(struct MAM) + sizeof(meta); if (io_size) { nwrite = pwrite(metafile, filemarks, io_size, io_offset); if (nwrite < 0) { MHVTL_ERR("Error writing filemark map to metafile: %s", strerror(errno)); return -1; } if (nwrite != io_size) { MHVTL_ERR("Error writing filemark map to metafile." " Expected to write %d bytes", (int)io_size); return -1; } } /* If filemarks were overwritten, the meta file may need to be shorter than before. */ if (ftruncate(metafile, io_offset + io_size) < 0) { MHVTL_ERR("Error truncating metafile: %s", strerror(errno)); return -1; } return 0; }
static void update_scalar_vpd_83(struct lu_phy_attr *lu) { struct vpd *lu_vpd; struct smc_priv *smc_p; uint8_t *d; lu_vpd = lu->lu_vpd[PCODE_OFFSET(0x83)]; smc_p = lu->lu_private; /* Unit Serial Number */ if (lu_vpd) /* Free any earlier allocation */ dealloc_vpd(lu_vpd); lu_vpd = alloc_vpd(36); if (lu_vpd) { d = lu_vpd->data; d[0] = 0xf2; d[1] = 0x01; d[3] = 0x20; snprintf((char *)&d[4], 9, "%-8s", lu->vendor_id); snprintf((char *)&d[12], 25, "%-24s", lu->lu_serial_no); } else { MHVTL_ERR("Could not malloc(36) bytes, line %d", __LINE__); } }
uint32_t read_tape_block(uint8_t *buf, uint32_t buf_size, uint8_t *sam_stat) { loff_t nread; uint32_t iosize; if (!tape_loaded(sam_stat)) return -1; MHVTL_DBG(3, "Reading blk %ld, size: %d", (unsigned long)raw_pos.hdr.blk_number, buf_size); /* The caller should have already verified that this is a B_DATA block before issuing this read, so we shouldn't have to worry about B_EOD or B_FILEMARK here. */ if (raw_pos.hdr.blk_type == B_EOD) { mkSenseBuf(BLANK_CHECK, E_END_OF_DATA, sam_stat); MHVTL_ERR("End of data detected while reading"); return -1; } iosize = raw_pos.hdr.disk_blk_size; if (iosize > buf_size) iosize = buf_size; nread = pread(datafile, buf, iosize, raw_pos.data_offset); if (nread != iosize) { MHVTL_ERR("Failed to read %d bytes", iosize); return -1; } // Now position to the following block. if (read_header(raw_pos.hdr.blk_number + 1, sam_stat)) { MHVTL_ERR("Failed to read block header %d", raw_pos.hdr.blk_number + 1); return -1; } return nread; }
/* DLT7000 & DLT8000 */ static void init_dlt_inquiry(struct lu_phy_attr *lu) { int pg; char b[32]; int x, y, z; lu->inquiry[2] = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION; lu->inquiry[36] = get_product_family(lu); sprintf(b, "%s", MHVTL_VERSION); sscanf(b, "%d.%d.%d", &x, &y, &z); if (x) { lu->inquiry[37] = x; lu->inquiry[38] = y; } else { lu->inquiry[37] = y; lu->inquiry[38] = z; } /* VPD page 0xC0 */ pg = PCODE_OFFSET(0xc0); lu->lu_vpd[pg] = alloc_vpd(44); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_dlt_c0(lu); /* VPD page 0xC1 */ pg = PCODE_OFFSET(0xc1); lu->lu_vpd[pg] = alloc_vpd(44); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_dlt_c1(lu, lu->lu_serial_no); }
/* * Used by mode sense/mode select struct. * * Allocate 'size' bytes & init to 0 * set first 2 bytes: * byte[0] = pcode * byte[1] = size - sizeof(byte[0]) * * Return pointer to mode structure being init. or NULL if alloc failed */ struct mode *alloc_mode_page(struct list_head *m, uint8_t pcode, uint8_t subpcode, int size) { struct mode *mp; MHVTL_DBG(3, "Allocating %d bytes for (%02x/%02x)", size, pcode, subpcode); mp = lookup_pcode(m, pcode, subpcode); if (!mp) { /* Create a new entry */ mp = (struct mode *)malloc(sizeof(struct mode)); } if (mp) { mp->pcodePointer = (uint8_t *)malloc(size); if (mp->pcodePointer) { /* If ! null, set size of data */ memset(mp->pcodePointer, 0, size); mp->pcode = pcode; mp->subpcode = subpcode; mp->pcodeSize = size; /* Allocate a 'changeable bitmap' mode page info */ mp->pcodePointerBitMap = malloc(size); if (!mp->pcodePointerBitMap) { free(mp); MHVTL_ERR("Unable to malloc(%d)", size); return NULL; } memset(mp->pcodePointerBitMap, 0, size); list_add_tail(&mp->siblings, m); return mp; } else { MHVTL_ERR("Unable to malloc(%d)", size); free(mp); } } return NULL; }
uint8_t ssc_load_unload(struct scsi_cmd *cmd) { struct priv_lu_ssc *lu_priv; uint8_t *sam_stat; int load; lu_priv = cmd->lu->lu_private; sam_stat = &cmd->dbuf_p->sam_stat; load = cmd->scb[4] & 0x01; current_state = (load) ? MHVTL_STATE_LOADING : MHVTL_STATE_UNLOADING; if (cmd->scb[4] & 0x04) { /* EOT bit */ MHVTL_ERR("EOT bit set on load. Not supported"); mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_CDB, sam_stat); return SAM_STAT_CHECK_CONDITION; } MHVTL_DBG(1, "%s tape (%ld) **", (load) ? "Loading" : "Unloading", (long)cmd->dbuf_p->serialNo); switch (lu_priv->tapeLoaded) { case TAPE_UNLOADED: if (load) rewind_tape(sam_stat); else { mkSenseBuf(NOT_READY, E_MEDIUM_NOT_PRESENT, sam_stat); return SAM_STAT_CHECK_CONDITION; } break; case TAPE_LOADED: if (!load) unloadTape(sam_stat); break; default: mkSenseBuf(NOT_READY, E_MEDIUM_FMT_CORRUPT, sam_stat); return SAM_STAT_CHECK_CONDITION; break; } return SAM_STAT_GOOD; }
static void update_eml_vpd_80(struct lu_phy_attr *lu) { struct vpd **lu_vpd = lu->lu_vpd; uint8_t *d; int pg; /* Unit Serial Number */ pg = PCODE_OFFSET(0x80); if (lu_vpd[pg]) /* Free any earlier allocation */ dealloc_vpd(lu_vpd[pg]); lu_vpd[pg] = alloc_vpd(0x12); if (lu_vpd[pg]) { d = lu_vpd[pg]->data; snprintf((char *)&d[0], 11, "%-10.10s", lu->lu_serial_no); /* Unique Logical Library Identifier */ } else { MHVTL_ERR("Could not malloc(0x12) bytes, line %d", __LINE__); } }
static void update_stk_l_vpd_80(struct lu_phy_attr *lu) { struct vpd *lu_vpd; uint8_t *d; lu_vpd = lu->lu_vpd[PCODE_OFFSET(0x80)]; /* Unit Serial Number */ if (lu_vpd) /* Free any earlier allocation */ dealloc_vpd(lu_vpd); lu_vpd = alloc_vpd(0x12); if (lu_vpd) { d = lu_vpd->data; /* d[4 - 15] Serial number of device */ snprintf((char *)&d[0], 13, "%-12s", lu->lu_serial_no); /* Unique Logical Library Identifier */ } else { MHVTL_ERR("Could not malloc(0x12) bytes, line %d", __LINE__); } }
static int check_filemarks_alloc(uint32_t count) { uint32_t new_size; /* See if we have enough space allocated to hold 'count' filemarks. If not, realloc now. */ if (count > (uint32_t)filemark_alloc) { new_size = ((count + FM_DELTA - 1) / FM_DELTA) * FM_DELTA; filemarks = (uint32_t *)realloc(filemarks, new_size * sizeof(*filemarks)); if (filemarks == NULL) { MHVTL_ERR("filemark map realloc failed, %s", strerror(errno)); return -1; } filemark_alloc = new_size; } return 0; }
static void update_scalar_vpd_80(struct lu_phy_attr *lu) { struct vpd *lu_vpd; struct smc_priv *smc_p; uint8_t *d; lu_vpd = lu->lu_vpd[PCODE_OFFSET(0x80)]; smc_p = lu->lu_private; /* Unit Serial Number */ if (lu_vpd) /* Free any earlier allocation */ dealloc_vpd(lu_vpd); lu_vpd = alloc_vpd(24); if (lu_vpd) { d = lu_vpd->data; /* d[4 - 27] Serial number prefixed by Vendor ID */ snprintf((char *)&d[0], 25, "%-s%-17s", lu->vendor_id, lu->lu_serial_no); } else { MHVTL_ERR("Could not malloc(24) bytes, line %d", __LINE__); } }
static void init_9840_inquiry(struct lu_phy_attr *lu) { int pg; uint8_t worm; worm = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_WORM; lu->inquiry[2] = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION; lu->inquiry[3] = 0x42; lu->inquiry[4] = INQUIRY_LEN - 5; /* Additional Length */ lu->inquiry[54] = 0x04; /* Key Management */ lu->inquiry[55] = 0x12; /* Support Encryption & Compression */ /* Sequential Access device capabilities - Ref: 8.4.2 */ pg = PCODE_OFFSET(0xb0); lu->lu_vpd[pg] = alloc_vpd(VPD_B0_SZ); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_b0(lu, &worm); }
int load_tape(const char *pcl, uint8_t *sam_stat) { char pcl_data[1024], pcl_indx[1024], pcl_meta[1024]; struct stat data_stat, indx_stat, meta_stat; uint64_t exp_size; size_t io_size; loff_t nread; int rc = 0; int null_media_type; char touch_file[128]; uint8_t error_check; snprintf(touch_file, 127, "%s/bypass_error_check", MHVTL_HOME_PATH); error_check = (stat(touch_file, &data_stat) == -1) ? FALSE : TRUE; if (error_check) { MHVTL_LOG("WARNING - touch file %s found - bypassing sanity checks on open", touch_file); } /* KFRDEBUG - sam_stat needs updates in lots of places here. */ /* If some other PCL is already open, return. */ if (datafile >= 0) return 1; /* Open all three files and stat them to get their current sizes. */ if (strlen(home_directory)) snprintf(currentPCL, ARRAY_SIZE(currentPCL), "%s/%s", home_directory, pcl); else snprintf(currentPCL, ARRAY_SIZE(currentPCL), "%s/%s", MHVTL_HOME_PATH, pcl); snprintf(pcl_data, ARRAY_SIZE(pcl_data), "%s/data", currentPCL); snprintf(pcl_indx, ARRAY_SIZE(pcl_indx), "%s/indx", currentPCL); snprintf(pcl_meta, ARRAY_SIZE(pcl_meta), "%s/meta", currentPCL); MHVTL_DBG(2, "Opening media: %s", pcl); if (stat(pcl_data, &data_stat) == -1) { MHVTL_DBG(2, "Couldn't find %s, trying previous default: %s/%s", pcl_data, MHVTL_HOME_PATH, pcl); snprintf(currentPCL, ARRAY_SIZE(currentPCL), "%s/%s", MHVTL_HOME_PATH, pcl); snprintf(pcl_data, ARRAY_SIZE(pcl_data), "%s/data", currentPCL); snprintf(pcl_indx, ARRAY_SIZE(pcl_indx), "%s/indx", currentPCL); snprintf(pcl_meta, ARRAY_SIZE(pcl_meta), "%s/meta", currentPCL); } datafile = open(pcl_data, O_RDWR|O_LARGEFILE); if (datafile == -1) { MHVTL_ERR("open of pcl %s file %s failed, %s", pcl, pcl_data, strerror(errno)); rc = 3; goto failed; } indxfile = open(pcl_indx, O_RDWR|O_LARGEFILE); if (indxfile == -1) { MHVTL_ERR("open of pcl %s file %s failed, %s", pcl, pcl_indx, strerror(errno)); rc = 3; goto failed; } metafile = open(pcl_meta, O_RDWR|O_LARGEFILE); if (metafile == -1) { MHVTL_ERR("open of pcl %s file %s failed, %s", pcl, pcl_meta, strerror(errno)); rc = 3; goto failed; } if (fstat(datafile, &data_stat) < 0) { MHVTL_ERR("stat of pcl %s file %s failed: %s", pcl, pcl_data, strerror(errno)); rc = 3; goto failed; } if (fstat(indxfile, &indx_stat) < 0) { MHVTL_ERR("stat of pcl %s file %s failed: %s", pcl, pcl_indx, strerror(errno)); rc = 3; goto failed; } if (fstat(metafile, &meta_stat) < 0) { MHVTL_ERR("stat of pcl %s file %s failed: %s", pcl, pcl_meta, strerror(errno)); rc = 3; goto failed; } /* Verify that the metafile size is at least reasonable. */ exp_size = sizeof(mam) + sizeof(meta); if ((uint32_t)meta_stat.st_size < exp_size) { MHVTL_ERR("sizeof(mam) + sizeof(meta) - " "pcl %s file %s is not the correct length, " "expected at least %" PRId64 ", actual %" PRId64, pcl, pcl_meta, exp_size, meta_stat.st_size); if (error_check) { rc = 2; goto failed; } } /* Read in the MAM and sanity-check it. */ nread = read(metafile, &mam, sizeof(mam)); if (nread < 0) { MHVTL_ERR("Error reading pcl %s MAM from metafile: %s", pcl, strerror(errno)); if (error_check) { rc = 2; goto failed; } } else if (nread != sizeof(mam)) { MHVTL_ERR("Error reading pcl %s MAM from metafile: " "unexpected read length", pcl); if (error_check) { rc = 2; goto failed; } } null_media_type = mam.MediumType == MEDIA_TYPE_NULL ? 1 : 0; if (mam.tape_fmt_version != TAPE_FMT_VERSION) { MHVTL_ERR("pcl %s MAM contains incorrect media format", pcl); sam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat); if (error_check) { rc = 2; goto failed; } } /* Read in the meta_header structure and sanity-check it. */ nread = read(metafile, &meta, sizeof(meta)); if (nread < 0) { MHVTL_ERR("Error reading pcl %s meta_header from " "metafile: %s", pcl, strerror(errno)); rc = 2; goto failed; } else if (nread != sizeof(meta)) { MHVTL_ERR("Error reading pcl %s meta header from " "metafile: unexpected read length", pcl); rc = 2; goto failed; } /* Now recompute the correct size of the meta file. */ exp_size = sizeof(mam) + sizeof(meta) + (meta.filemark_count * sizeof(*filemarks)); if ((uint32_t)meta_stat.st_size != exp_size) { MHVTL_ERR("sizeof(mam) + sizeof(meta) + sizeof(*filemarks) - " "pcl %s file %s is not the correct length, " "expected %" PRId64 ", actual %" PRId64, pcl, pcl_meta, exp_size, meta_stat.st_size); if (error_check) { rc = 2; goto failed; } } /* See if we have allocated enough space for the actual number of filemarks on the tape. If not, realloc now. */ if (check_filemarks_alloc(meta.filemark_count)) { if (error_check) { rc = 3; goto failed; } } /* Now read in the filemark map. */ io_size = meta.filemark_count * sizeof(*filemarks); if (io_size) { nread = read(metafile, filemarks, io_size); if (nread < 0) { MHVTL_ERR("Error reading pcl %s filemark map from " "metafile: %s", pcl, strerror(errno)); rc = 2; goto failed; } else if ((size_t)nread != io_size) { MHVTL_ERR("Error reading pcl %s filemark map from " "metafile: unexpected read length", pcl); if (error_check) { rc = 2; goto failed; } } } /* Use the size of the indx file to work out where the virtual B_EOD block resides. */ if ((indx_stat.st_size % sizeof(struct raw_header)) != 0) { MHVTL_ERR("pcl %s indx file has improper length, indicating " "possible file corruption", pcl); rc = 2; goto failed; } eod_blk_number = indx_stat.st_size / sizeof(struct raw_header); /* Make sure that the filemark map is consistent with the size of the indx file. */ if (meta.filemark_count && eod_blk_number && filemarks[meta.filemark_count - 1] >= eod_blk_number) { MHVTL_ERR("pcl %s indx file has improper length as compared " "to the meta file, indicating possible file corruption", pcl); MHVTL_ERR("Filemark count: %d eod_blk_number: %d", meta.filemark_count, eod_blk_number); rc = 2; goto failed; } /* Read in the last raw_header struct from the indx file and use that to validate the correct size of the data file. */ if (eod_blk_number == 0) eod_data_offset = 0; else { if (read_header(eod_blk_number - 1, sam_stat)) { rc = 3; goto failed; } eod_data_offset = raw_pos.data_offset + raw_pos.hdr.disk_blk_size; } if (null_media_type) { MHVTL_LOG("Loaded NULL media type"); /* Skip check */ } else if ((uint64_t)data_stat.st_size != eod_data_offset) { MHVTL_ERR("st_size != eod_data_offset - " "pcl %s file %s is not the correct length, " "expected %" PRId64 ", actual %" PRId64, pcl, pcl_data, eod_data_offset, data_stat.st_size); if (error_check) { rc = 2; goto failed; } } /* Give a hint to the kernel that data, once written, tends not to be accessed again immediately. */ posix_fadvise(indxfile, 0, 0, POSIX_FADV_DONTNEED); posix_fadvise(datafile, 0, 0, POSIX_FADV_DONTNEED); /* Now initialize raw_pos by reading in the first header, if any. */ if (read_header(0, sam_stat)) { rc = 3; goto failed; } return 0; failed: if (datafile >= 0) { close(datafile); datafile = -1; } if (indxfile >= 0) { close(indxfile); indxfile = -1; } if (metafile >= 0) { close(metafile); metafile = -1; } return rc; }
int create_tape(const char *pcl, const struct MAM *mamp, uint8_t *sam_stat) { struct stat data_stat; char newMedia[1024]; char newMedia_data[1024]; char newMedia_indx[1024]; char newMedia_meta[1024]; struct passwd *pw; int rc = 0; /* Attempt to create the new PCL. This will fail if the PCL's directory or any of the PCL's three files already exist, leaving any existing files as they were. */ pw = getpwnam(USR); /* Find UID for user 'vtl' */ if (!pw) { MHVTL_ERR("Failed to get UID for user '%s': %s", USR, strerror(errno)); return 1; } snprintf(newMedia, ARRAY_SIZE(newMedia), "%s/%s", home_directory, pcl); snprintf(newMedia_data, ARRAY_SIZE(newMedia_data), "%s/data", newMedia); snprintf(newMedia_indx, ARRAY_SIZE(newMedia_indx), "%s/indx", newMedia); snprintf(newMedia_meta, ARRAY_SIZE(newMedia_meta), "%s/meta", newMedia); /* Check if data file already exists, nothing to create */ if (stat(newMedia_data, &data_stat) != -1) return 0; umask(0007); rc = mkdir(newMedia, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_ISGID); if (rc) { /* No need to fail just because the parent dir exists */ if (errno != EEXIST) { MHVTL_ERR("Failed to create directory %s: %s", newMedia, strerror(errno)); return 2; } } /* Don't really care if chown() fails or not.. * But lets try anyway */ chown(newMedia, pw->pw_uid, pw->pw_gid); datafile = creat(newMedia_data, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (datafile == -1) { MHVTL_ERR("Failed to create file %s: %s", newMedia_data, strerror(errno)); return 2; } indxfile = creat(newMedia_indx, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (indxfile == -1) { MHVTL_ERR("Failed to create file %s: %s", newMedia_indx, strerror(errno)); unlink(newMedia_data); rc = 2; goto cleanup; } metafile = creat(newMedia_meta, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (metafile == -1) { MHVTL_ERR("Failed to create file %s: %s", newMedia_meta, strerror(errno)); unlink(newMedia_data); unlink(newMedia_indx); rc = 2; goto cleanup; } chown(newMedia_data, pw->pw_uid, pw->pw_gid); chown(newMedia_indx, pw->pw_uid, pw->pw_gid); chown(newMedia_meta, pw->pw_uid, pw->pw_gid); MHVTL_LOG("%s files created", newMedia); /* Write the meta file consisting of the MAM and the meta_header structure with the filemark count initialized to zero. */ mam = *mamp; memset(&meta, 0, sizeof(meta)); meta.filemark_count = 0; if (write(metafile, &mam, sizeof(mam)) != sizeof(mam) || write(metafile, &meta, sizeof(meta)) != sizeof(meta)) { MHVTL_ERR("Failed to initialize file %s: %s", newMedia_meta, strerror(errno)); unlink(newMedia_data); unlink(newMedia_indx); unlink(newMedia_meta); rc = 1; } cleanup: if (datafile >= 0) { close(datafile); datafile = -1; } if (indxfile >= 0) { close(indxfile); indxfile = -1; } if (metafile >= 0) { close(metafile); metafile = -1; } return rc; }
/* SuperDLT range */ static void init_sdlt_inquiry(struct lu_phy_attr *lu) { int pg; uint8_t worm; uint8_t ta[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; char b[32]; int x, y, z; worm = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_supports_WORM; lu->inquiry[2] = ((struct priv_lu_ssc *)lu->lu_private)->pm->drive_ANSI_VERSION; lu->inquiry[36] = get_product_family(lu); sprintf(b, "%s", MHVTL_VERSION); sscanf(b, "%d.%d.%d", &x, &y, &z); if (x) { lu->inquiry[37] = x; lu->inquiry[38] = y; } else { lu->inquiry[37] = y; lu->inquiry[38] = z; } /* Sequential Access device capabilities - Ref: 8.4.2 */ pg = PCODE_OFFSET(0xb0); lu->lu_vpd[pg] = alloc_vpd(VPD_B0_SZ); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_b0(lu, &worm); /* Manufacture-assigned serial number - Ref: 8.4.3 */ pg = PCODE_OFFSET(0xb1); lu->lu_vpd[pg] = alloc_vpd(VPD_B1_SZ); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_b1(lu, lu->lu_serial_no); /* TapeAlert supported flags - Ref: 8.4.4 */ pg = PCODE_OFFSET(0xb2); lu->lu_vpd[pg] = alloc_vpd(VPD_B2_SZ); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_b2(lu, &ta); /* VPD page 0xC0 */ pg = PCODE_OFFSET(0xc0); lu->lu_vpd[pg] = alloc_vpd(44); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_dlt_c0(lu); /* VPD page 0xC1 */ pg = PCODE_OFFSET(0xc1); lu->lu_vpd[pg] = alloc_vpd(44); if (!lu->lu_vpd[pg]) { MHVTL_ERR("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_dlt_c1(lu, lu->lu_serial_no); }
int write_tape_block(const uint8_t *buffer, uint32_t blk_size, uint32_t comp_size, const struct encryption *encryptp, uint8_t comp_type, uint8_t null_media_type, uint8_t *sam_stat) { uint32_t blk_number, disk_blk_size; uint32_t max_blk_number; uint64_t data_offset; ssize_t nwrite; /* Medium format limits to unsigned 32bit blks */ max_blk_number = 0xfffffff0; if (!tape_loaded(sam_stat)) return -1; if (check_for_overwrite(sam_stat)) return -1; /* Preserve existing raw_pos data we need, then clear out raw_pos and fill it in with new data. */ blk_number = raw_pos.hdr.blk_number; data_offset = raw_pos.data_offset; if (blk_number > max_blk_number) { MHVTL_ERR("Too many tape blocks - 32byte overflow"); return -1; } memset(&raw_pos, 0, sizeof(raw_pos)); raw_pos.data_offset = data_offset; raw_pos.hdr.blk_type = B_DATA; /* Header type */ raw_pos.hdr.blk_flags = 0; raw_pos.hdr.blk_number = blk_number; raw_pos.hdr.blk_size = blk_size; /* Size of uncompressed data */ if (comp_size) { if (comp_type == LZO) raw_pos.hdr.blk_flags |= BLKHDR_FLG_LZO_COMPRESSED; else raw_pos.hdr.blk_flags |= BLKHDR_FLG_ZLIB_COMPRESSED; raw_pos.hdr.disk_blk_size = disk_blk_size = comp_size; } else raw_pos.hdr.disk_blk_size = disk_blk_size = blk_size; if (encryptp != NULL) { unsigned int i; raw_pos.hdr.blk_flags |= BLKHDR_FLG_ENCRYPTED; raw_pos.hdr.encryption.ukad_length = encryptp->ukad_length; for (i = 0; i < encryptp->ukad_length; ++i) raw_pos.hdr.encryption.ukad[i] = encryptp->ukad[i]; raw_pos.hdr.encryption.akad_length = encryptp->akad_length; for (i = 0; i < encryptp->akad_length; ++i) raw_pos.hdr.encryption.akad[i] = encryptp->akad[i]; raw_pos.hdr.encryption.key_length = encryptp->key_length; for (i = 0; i < encryptp->key_length; ++i) raw_pos.hdr.encryption.key[i] = encryptp->key[i]; } /* Now write out both the data and the header. */ if (null_media_type) { nwrite = disk_blk_size; } else nwrite = pwrite(datafile, buffer, disk_blk_size, data_offset); if (nwrite != disk_blk_size) { sam_medium_error(E_WRITE_ERROR, sam_stat); MHVTL_ERR("Data file write failure, pos: %" PRId64 ": %s", data_offset, strerror(errno)); /* Truncate last partital write */ MHVTL_DBG(1, "Truncating data file size: %"PRId64, data_offset); if (ftruncate(datafile, data_offset) < 0) { MHVTL_ERR("Error truncating data: %s", strerror(errno)); } mkEODHeader(blk_number, data_offset); return -1; } nwrite = pwrite(indxfile, &raw_pos, sizeof(raw_pos), blk_number * sizeof(raw_pos)); if (nwrite != sizeof(raw_pos)) { long indxsz = (blk_number - 1) * sizeof(raw_pos); sam_medium_error(E_WRITE_ERROR, sam_stat); MHVTL_ERR("Index file write failure, pos: %" PRId64 ": %s", (uint64_t)blk_number * sizeof(raw_pos), strerror(errno)); MHVTL_DBG(1, "Truncating index file size to: %ld", indxsz); if (ftruncate(indxfile, indxsz) < 0) { MHVTL_ERR("Error truncating indx: %s", strerror(errno)); } if (!null_media_type) { MHVTL_DBG(1, "Truncating data file size: %"PRId64, data_offset); if (ftruncate(datafile, data_offset) < 0) { MHVTL_ERR("Error truncating data: %s", strerror(errno)); } } mkEODHeader(blk_number, data_offset); return -1; } MHVTL_DBG(3, "Successfully wrote block: %u", blk_number); return mkEODHeader(blk_number + 1, data_offset + disk_blk_size); }
int write_filemarks(uint32_t count, uint8_t *sam_stat) { uint32_t blk_number; uint64_t data_offset; ssize_t nwrite; if (!tape_loaded(sam_stat)) return -1; /* Applications assume that writing a filemark (even writing zero filemarks) will force-flush any data buffered in the drive to media so that after the write-filemarks call returns there is no possibility that any data previously written could be lost due to a power hit. Provide a similar guarantee here. */ if (count == 0) { MHVTL_DBG(2, "Flushing data - 0 filemarks written"); fsync(datafile); fsync(indxfile); fsync(metafile); return 0; } if (check_for_overwrite(sam_stat)) return -1; /* Preserve existing raw_pos data we need, then clear raw_pos and fill it in with new data. */ blk_number = raw_pos.hdr.blk_number; data_offset = raw_pos.data_offset; memset(&raw_pos, 0, sizeof(raw_pos)); raw_pos.data_offset = data_offset; raw_pos.hdr.blk_type = B_FILEMARK; /* Header type */ raw_pos.hdr.blk_flags = 0; raw_pos.hdr.blk_number = blk_number; raw_pos.hdr.blk_size = 0; raw_pos.hdr.disk_blk_size = 0; /* Now write out one header per filemark. */ for ( ; count > 0; count--, blk_number++) { raw_pos.hdr.blk_number = blk_number; MHVTL_DBG(3, "Writing filemark: block %d", blk_number); nwrite = pwrite(indxfile, &raw_pos, sizeof(raw_pos), blk_number * sizeof(raw_pos)); if (nwrite != sizeof(raw_pos)) { sam_medium_error(E_WRITE_ERROR, sam_stat); MHVTL_ERR("Index file write failure," " pos: %" PRId64 ": %s", (uint64_t)blk_number * sizeof(raw_pos), strerror(errno)); return -1; } add_filemark(blk_number); } /* Provide the force-flush guarantee. */ fsync(datafile); fsync(indxfile); fsync(metafile); return mkEODHeader(blk_number, data_offset); }
static void update_eml_vpd_83(struct lu_phy_attr *lu) { struct vpd **lu_vpd = lu->lu_vpd; uint8_t *d; int num; char *ptr; int pg; int len, j; num = VENDOR_ID_LEN + PRODUCT_ID_LEN + 10; pg = PCODE_OFFSET(0x83); if (lu_vpd[pg]) /* Free any earlier allocation */ dealloc_vpd(lu_vpd[pg]); lu_vpd[pg] = alloc_vpd(num + 12); if (!lu_vpd[pg]) { MHVTL_ERR("Can't malloc() to setup for vpd_83"); return; } d = lu_vpd[pg]->data; d[0] = 2; d[1] = 1; d[2] = 0; d[3] = num; memcpy(&d[4], &lu->vendor_id, VENDOR_ID_LEN); memcpy(&d[12], &lu->product_id, PRODUCT_ID_LEN); memcpy(&d[28], &lu->lu_serial_no, 10); len = (int)strlen(lu->lu_serial_no); ptr = &lu->lu_serial_no[len]; num += 4; /* NAA IEEE registered identifier (faked) */ d[num] = 0x1; /* Binary */ d[num + 1] = 0x3; d[num + 2] = 0x0; d[num + 3] = 0x8; d[num + 4] = 0x51; d[num + 5] = 0x23; d[num + 6] = 0x45; d[num + 7] = 0x60; d[num + 8] = 0x3; d[num + 9] = 0x3; d[num + 10] = 0x3; d[num + 11] = 0x3; if (lu->naa) { /* If defined in config file */ sscanf((const char *)lu->naa, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &d[num + 4], &d[num + 5], &d[num + 6], &d[num + 7], &d[num + 8], &d[num + 9], &d[num + 10], &d[num + 11]); } else { /* Else munge the serial number */ ptr--; for (j = 11; j > 3; ptr--, j--) d[num + j] = *ptr; } d[num + 4] &= 0x0f; d[num + 4] |= 0x50; }
int write_tape_block(const uint8_t *buffer, uint32_t blk_size, uint32_t comp_size, const struct encryption *encryptp, uint8_t comp_type, uint8_t *sam_stat) { uint32_t blk_number, disk_blk_size; uint64_t data_offset; ssize_t nwrite; if (!tape_loaded(sam_stat)) { return -1; } if (check_for_overwrite(sam_stat)) { return -1; } /* Preserve existing raw_pos data we need, then clear out raw_pos and fill it in with new data. */ blk_number = raw_pos.hdr.blk_number; data_offset = raw_pos.data_offset; memset(&raw_pos, 0, sizeof(raw_pos)); raw_pos.data_offset = data_offset; raw_pos.hdr.blk_type = B_DATA; /* Header type */ raw_pos.hdr.blk_flags = 0; raw_pos.hdr.blk_number = blk_number; raw_pos.hdr.blk_size = blk_size; /* Size of uncompressed data */ if (comp_size) { if (comp_type == LZO) raw_pos.hdr.blk_flags |= BLKHDR_FLG_LZO_COMPRESSED; else raw_pos.hdr.blk_flags |= BLKHDR_FLG_ZLIB_COMPRESSED; raw_pos.hdr.disk_blk_size = disk_blk_size = comp_size; } else { raw_pos.hdr.disk_blk_size = disk_blk_size = blk_size; } if (encryptp != NULL) { unsigned int i; raw_pos.hdr.blk_flags |= BLKHDR_FLG_ENCRYPTED; raw_pos.hdr.encryption.ukad_length = encryptp->ukad_length; for (i = 0; i < encryptp->ukad_length; ++i) { raw_pos.hdr.encryption.ukad[i] = encryptp->ukad[i]; } raw_pos.hdr.encryption.akad_length = encryptp->akad_length; for (i = 0; i < encryptp->akad_length; ++i) { raw_pos.hdr.encryption.akad[i] = encryptp->akad[i]; } raw_pos.hdr.encryption.key_length = encryptp->key_length; for (i = 0; i < encryptp->key_length; ++i) { raw_pos.hdr.encryption.key[i] = encryptp->key[i]; } } /* Now write out both the header and the data. */ nwrite = pwrite(indxfile, &raw_pos, sizeof(raw_pos), blk_number * sizeof(raw_pos)); if (nwrite != sizeof(raw_pos)) { mkSenseBuf(MEDIUM_ERROR, E_WRITE_ERROR, sam_stat); MHVTL_ERR("Index file write failure, pos: %" PRId64 ": %s", (uint64_t)blk_number * sizeof(raw_pos), strerror(errno)); return -1; } nwrite = pwrite(datafile, buffer, disk_blk_size, data_offset); if (nwrite != disk_blk_size) { mkSenseBuf(MEDIUM_ERROR, E_WRITE_ERROR, sam_stat); MHVTL_ERR("Data file write failure, pos: %" PRId64 ": %s", data_offset, strerror(errno)); return -1; } MHVTL_DBG(3, "Successfully wrote block: %u", blk_number); return mkEODHeader(blk_number + 1, data_offset + disk_blk_size); }
uint8_t ssc_tur(struct scsi_cmd *cmd) { struct priv_lu_ssc *lu_priv; uint8_t *sam_stat; char str[64]; lu_priv = cmd->lu->lu_private; sam_stat = &cmd->dbuf_p->sam_stat; *sam_stat = SAM_STAT_GOOD; sprintf(str, "Test Unit Ready (%ld) ** : ", (long)cmd->dbuf_p->serialNo); switch (lu_priv->tapeLoaded) { case TAPE_UNLOADED: strcat(str, "No, No tape loaded"); mkSenseBuf(NOT_READY, E_MEDIUM_NOT_PRESENT, sam_stat); *sam_stat = SAM_STAT_CHECK_CONDITION; break; case TAPE_LOADED: if (mam.MediumType == MEDIA_TYPE_CLEAN) { int state; strcat(str, "No, Cleaning cart loaded"); if (lu_priv->cleaning_media_state) state = *lu_priv->cleaning_media_state; else state = 0; switch (state) { case CLEAN_MOUNT_STAGE1: mkSenseBuf(NOT_READY, E_CLEANING_CART_INSTALLED, sam_stat); break; case CLEAN_MOUNT_STAGE2: mkSenseBuf(NOT_READY, E_CAUSE_NOT_REPORTABLE, sam_stat); break; case CLEAN_MOUNT_STAGE3: mkSenseBuf(NOT_READY, E_INITIALIZING_REQUIRED, sam_stat); break; default: MHVTL_ERR("Unknown cleaning media mount state"); mkSenseBuf(NOT_READY, E_CLEANING_CART_INSTALLED, sam_stat); break; } *sam_stat = SAM_STAT_CHECK_CONDITION; } else strcat(str, "Yes"); break; default: strcat(str, "No, Media format corrupt"); mkSenseBuf(NOT_READY, E_MEDIUM_FMT_CORRUPT, sam_stat); *sam_stat = SAM_STAT_CHECK_CONDITION; break; } MHVTL_DBG(1, "%s", str); return *sam_stat; }