uint8_t ssc_erase(struct scsi_cmd *cmd) { struct priv_lu_ssc *lu_priv; uint8_t *sam_stat; lu_priv = cmd->lu->lu_private; sam_stat = &cmd->dbuf_p->sam_stat; MHVTL_DBG(1, "Erasing (%ld) **", (long)cmd->dbuf_p->serialNo); current_state = MHVTL_STATE_ERASE; if (!lu_priv->pm->check_restrictions(cmd)) return SAM_STAT_CHECK_CONDITION; if (c_pos->blk_number != 0) { MHVTL_LOG("Not at BOT.. Can't erase unless at BOT"); mkSenseBuf(NOT_READY, E_INVALID_FIELD_IN_CDB, sam_stat); return SAM_STAT_CHECK_CONDITION; } if (OK_to_write) format_tape(sam_stat); else { MHVTL_LOG("Attempt to erase Write-protected media"); mkSenseBuf(NOT_READY, E_MEDIUM_OVERWRITE_ATTEMPTED, sam_stat); return SAM_STAT_CHECK_CONDITION; } return SAM_STAT_GOOD; }
static int check_for_overwrite(uint8_t *sam_stat) { MHVTL_DBG(1, "check_for_overwrite"); #if NOTDEF uint32_t blk_number; uint64_t data_offset; 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))) { sam_medium_error(E_WRITE_ERROR, sam_stat); MHVTL_LOG("Index file ftruncate failure, pos: " "%" PRId64 ": %s", (uint64_t)blk_number * sizeof(raw_pos), strerror(errno)); return -1; } if (ftruncate(datafile, data_offset)) { sam_medium_error(E_WRITE_ERROR, sam_stat); MHVTL_LOG("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(); } } #endif return 0; }
static void init_ait_inquiry(struct lu_phy_attr *lu) { int pg; uint8_t worm = 1; /* Supports WORM */ uint8_t local_TapeAlert[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; /* 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_LOG("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_LOG("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_LOG("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_LOG("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_LOG("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_c1(lu, "Security"); }
uint8_t ssc_allow_overwrite(struct scsi_cmd *cmd) { uint8_t *cdb = cmd->scb; uint8_t allow_overwrite = cdb[2] & 0x0f; uint8_t partition = cdb[3]; uint8_t *sam_stat = &cmd->dbuf_p->sam_stat; uint8_t ret_stat = SAM_STAT_GOOD; uint64_t allow_overwrite_block; struct priv_lu_ssc *lu_ssc; lu_ssc = cmd->lu->lu_private; if (allow_overwrite > 2) /* Truncate bad values 3 to 15 -> '3' */ allow_overwrite = 3; MHVTL_DBG(1, "ALLOW OVERWRITE (%ld) : %s **", (long)cmd->dbuf_p->serialNo, allow_overwrite_desc[allow_overwrite].desc); lu_ssc->allow_overwrite = FALSE; switch (allow_overwrite) { case 0: break; case 1: /* current position */ if (partition) { /* Paritions not supported at this stage */ MHVTL_LOG("Partitions not implemented at this time"); mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_CDB, sam_stat); return SAM_STAT_CHECK_CONDITION; } allow_overwrite_block = get_unaligned_be64(&cdb[4]); MHVTL_DBG(1, "Allow overwrite block: %lld", (long long)allow_overwrite_block); if (allow_overwrite_block == current_tape_block()) { lu_ssc->allow_overwrite_block = allow_overwrite_block; lu_ssc->allow_overwrite = TRUE; } else { /* Set allow_overwrite position to an invalid number */ lu_ssc->allow_overwrite_block = 0; lu_ssc->allow_overwrite_block--; mkSenseBuf(ILLEGAL_REQUEST, E_SEQUENTIAL_POSITIONING_ERROR, sam_stat); ret_stat = SAM_STAT_CHECK_CONDITION; } break; case 2: lu_ssc->allow_overwrite = 2; break; default: mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_CDB, sam_stat); ret_stat = SAM_STAT_CHECK_CONDITION; break; } return ret_stat; }
/* 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_LOG("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_LOG("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_dlt_c1(lu, lu->lu_serial_no); }
static void update_hp_vpd_cx(struct lu_phy_attr *lu, uint8_t pg, char *comp, char *vers, char *date, char *variant) { struct vpd *vpd_p; char *data; vpd_p = lu->lu_vpd[PCODE_OFFSET(pg)]; if (!vpd_p) { MHVTL_LOG("Arrhhh... vpd pg %d not defined...", pg); } data = (char *)vpd_p->data; data[3] = 0x5c; snprintf(&data[4], 24, "%-24s", comp); snprintf(&data[30], 18, "%-18s", vers); snprintf(&data[49], 24, "%-24s", date); snprintf(&data[73], 22, "%-22s", variant); }
static void init_t10k_inquiry(struct lu_phy_attr *lu) { int pg; uint8_t worm = 1; /* Supports WORM */ 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_LOG("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; }
static void init_ult_inquiry(struct lu_phy_attr *lu) { int pg; uint8_t worm = 1; /* Supports WORM */ uint8_t local_TapeAlert[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; pg = PCODE_OFFSET(0x86); lu->lu_vpd[pg] = alloc_vpd(VPD_86_SZ); if (!lu->lu_vpd[pg]) { MHVTL_LOG("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } /* 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_LOG("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_LOG("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_LOG("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_b2(lu, &local_TapeAlert); /* VPD page 0xC0 - Firmware revision page */ pg = PCODE_OFFSET(0xc0); lu->lu_vpd[pg] = alloc_vpd(0x60); if (!lu->lu_vpd[pg]) { MHVTL_LOG("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_hp_vpd_cx(lu, pg, "Firmware", MHVTL_VERSION, "2012/04/18 19:38", "6"); /* VPD page 0xC1 - Hardware */ pg = PCODE_OFFSET(0xc1); lu->lu_vpd[pg] = alloc_vpd(0x60); if (!lu->lu_vpd[pg]) { MHVTL_LOG("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_hp_vpd_cx(lu, pg, "Hardware", MHVTL_VERSION, "2012/04/18 06:53", "5"); /* VPD page 0xC2 - PCA */ pg = PCODE_OFFSET(0xc2); lu->lu_vpd[pg] = alloc_vpd(0x60); if (!lu->lu_vpd[pg]) { MHVTL_LOG("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_hp_vpd_cx(lu, pg, "PCA", MHVTL_VERSION, "1996/11/29 10:00", "4"); /* VPD page 0xC3 - Mechanism */ pg = PCODE_OFFSET(0xc3); lu->lu_vpd[pg] = alloc_vpd(0x60); if (!lu->lu_vpd[pg]) { MHVTL_LOG("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_hp_vpd_cx(lu, pg, "Mechanism", MHVTL_VERSION, "1992/08/11 10:00", "3"); /* VPD page 0xC4 - Head Assembly */ pg = PCODE_OFFSET(0xc4); lu->lu_vpd[pg] = alloc_vpd(0x60); if (!lu->lu_vpd[pg]) { MHVTL_LOG("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_hp_vpd_cx(lu, pg, "Head Assy", MHVTL_VERSION, "1966/07/28 10:00", "2"); /* VPD page 0xC5 - ACI */ pg = PCODE_OFFSET(0xc5); lu->lu_vpd[pg] = alloc_vpd(0x60); if (!lu->lu_vpd[pg]) { MHVTL_LOG("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_hp_vpd_cx(lu, pg, "ACI", MHVTL_VERSION, "1960/03/10 10:00", "1"); }
/* 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_LOG("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_LOG("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_LOG("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_LOG("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_LOG("Failed to malloc(): Line %d", __LINE__); exit(-ENOMEM); } update_vpd_dlt_c1(lu, lu->lu_serial_no); }
/* * Process the MODE_SELECT command */ uint8_t ssc_mode_select(struct scsi_cmd *cmd) { uint8_t *sam_stat = &cmd->dbuf_p->sam_stat; uint8_t *buf = cmd->dbuf_p->data; int block_descriptor_sz; int page_len; uint8_t *bdb = NULL; int i; int long_lba = 0; int count; int save_page; save_page = cmd->scb[1] & 0x01; switch (cmd->scb[0]) { case MODE_SELECT: cmd->dbuf_p->sz = cmd->scb[4]; break; case MODE_SELECT_10: cmd->dbuf_p->sz = get_unaligned_be16(&cmd->scb[7]); break; default: cmd->dbuf_p->sz = 0; } count = retrieve_CDB_data(cmd->cdev, cmd->dbuf_p); MHVTL_DBG(1, "MODE SELECT (%ld) **", (long)cmd->dbuf_p->serialNo); if (!(cmd->scb[1] & 0x10)) { /* Page Format: 1 - SPC, 0 - vendor uniq */ mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_CDB, sam_stat); return SAM_STAT_CHECK_CONDITION; } switch (cmd->scb[0]) { case MODE_SELECT: block_descriptor_sz = buf[3]; if (block_descriptor_sz) bdb = &buf[4]; i = 4 + block_descriptor_sz; break; case MODE_SELECT_10: block_descriptor_sz = get_unaligned_be16(&buf[6]); long_lba = buf[4] & 1; if (block_descriptor_sz) bdb = &buf[8]; i = 8 + block_descriptor_sz; break; default: mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_OP_CODE, sam_stat); return SAM_STAT_CHECK_CONDITION; } if (bdb) { if (long_lba) { mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_CDB, sam_stat); MHVTL_DBG(1, "Warning can not " "handle long descriptor block (long_lba bit)"); return SAM_STAT_CHECK_CONDITION; } memcpy(modeBlockDescriptor, bdb, block_descriptor_sz); } /* Ignore mode pages if 'save page' bit not set */ if (!save_page) { MHVTL_DBG(1, "Save page bit not set. Ignoring page data"); return SAM_STAT_GOOD; } #ifdef MHVTL_DEBUG if (debug) hex_dump(buf, cmd->dbuf_p->sz); #endif MHVTL_DBG(3, "count: %d, i: %d", count, i); if (i == 4) { MHVTL_DBG(3, "Offset 0: %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3]); } else { MHVTL_DBG(3, "Offset 0: %02x %02x %02x %02x %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); } count -= i; while (i < count) { MHVTL_DBG(3, " %02d: %02x %02x %02x %02x %02x %02x %02x %02x", i, buf[i+0], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7]); MHVTL_DBG(3, " %02d: %02x %02x %02x %02x %02x %02x %02x %02x", i+8, buf[i+8], buf[i+9], buf[i+10], buf[i+11], buf[i+12], buf[i+13], buf[i+14], buf[i+15]); MHVTL_DBG(3, " %02d: %02x %02x %02x %02x %02x %02x %02x %02x", i+16, buf[i+16], buf[i+17], buf[i+18], buf[i+19], buf[i+20], buf[i+21], buf[i+22], buf[i+23]); MHVTL_DBG(3, " %02d: %02x %02x %02x %02x %02x %02x %02x %02x", i+24, buf[i+24], buf[i+25], buf[i+26], buf[i+27], buf[i+28], buf[i+29], buf[i+30], buf[i+31]); /* Default page len is, override if sub-pages */ page_len = buf[i + 1]; switch (buf[i]) { case MODE_DATA_COMPRESSION: set_mode_compression(cmd, &buf[i]); break; case MODE_DEVICE_CONFIGURATION: /* If this is '01' it's a subpage value * i.e. DEVICE CONFIGURATION EXTENSION * If it's 0x0e, it indicates a page length * for MODE DEVICE CONFIGURATION */ if (buf[i + 1] == 0x01) { if (set_device_configuration_extension(cmd, &buf[i])) return SAM_STAT_CHECK_CONDITION; /* Subpage 1 - override default page length */ page_len = get_unaligned_be16(&buf[i + 2]); } else set_device_configuration(cmd, &buf[i]); break; default: MHVTL_DBG_PRT_CDB(1, cmd); MHVTL_DBG(1, "Mode page 0x%02x not handled", buf[i]); break; } if (page_len == 0) { /* Something wrong with data structure */ page_len = cmd->dbuf_p->sz; MHVTL_LOG("Problem with mode select data structure"); } i += page_len; /* Next mode page */ } return SAM_STAT_GOOD; }
static uint8_t set_device_configuration_extension(struct scsi_cmd *cmd, uint8_t *p) { uint8_t *sam_stat = &cmd->dbuf_p->sam_stat; struct lu_phy_attr *lu = cmd->lu; struct priv_lu_ssc *lu_priv = cmd->lu->lu_private; struct ssc_personality_template *pm; struct mode *mp; int page_code_len; int write_mode; int pews; /* Programable Early Warning Size */ pm = lu_priv->pm; mp = lookup_pcode(&lu->mode_pg, MODE_DEVICE_CONFIGURATION, 1); /* Code error * Any device supporting this should have this mode page defined */ if (!mp) { mkSenseBuf(HARDWARE_ERROR, E_INTERNAL_TARGET_FAILURE, sam_stat); return SAM_STAT_CHECK_CONDITION; } page_code_len = get_unaligned_be16(&p[2]); if (page_code_len != 0x1c) { MHVTL_LOG("Unexpected page code length.. Unexpected results"); mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_PARMS, sam_stat); return SAM_STAT_CHECK_CONDITION; } write_mode = (p[5] & 0xf0) >> 4; if (write_mode > 1) { mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_PARMS, sam_stat); return SAM_STAT_CHECK_CONDITION; } MHVTL_DBG(2, "%s mode", write_mode ? "Append-only" : "Write-anywhere"); pews = get_unaligned_be16(&p[6]); if (pm->drive_supports_prog_early_warning) { MHVTL_DBG(2, "Set Programable Early Warning Size: %d", pews); lu_priv->prog_early_warning_sz = pews; update_prog_early_warning(lu); } else { MHVTL_DBG(2, "Programable Early Warning Size not supported" " by this device"); } MHVTL_DBG(2, "Volume containing encrypted logical blocks " "requires encryption: %d", p[8] & 0x01); if (pm->drive_supports_append_only_mode) { /* Can't reset append-only mode via mode page ssc4 8.3.8 */ if (lu_priv->append_only_mode && write_mode == 0) { MHVTL_LOG("Can't reset append only mode via mode page"); mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_PARMS, sam_stat); return SAM_STAT_CHECK_CONDITION; } if (write_mode) { lu_priv->append_only_mode = write_mode; lu_priv->allow_overwrite = FALSE; } } /* Now update our copy of this mode page */ mp->pcodePointer[5] &= 0x0f; mp->pcodePointer[5] |= write_mode << 4; return SAM_STAT_GOOD; }
int load_tape(const char *pcl, uint8_t *sam_stat) { loff_t nread; uint32_t version = 0; MHVTL_DBG(1, "load_tape"); /* KFRDEBUG - sam_stat needs updates in lots of places here. */ #if NOTDEF if (datafile == -1) /* return 1; */ /* don't return 1 here */ return 0; #endif sprintf(currentMedia, "%s/%s", MHVTL_HOME_PATH, pcl); /* MHVTL_DBG(2, "Opening file/media %s", currentMedia); */ MHVTL_LOG("Opening file/media %s", currentMedia); datafile = open(currentMedia, O_RDWR|O_LARGEFILE); if (datafile == -1) { MHVTL_DBG(1, "%s: open file/media failed, %s", currentMedia, strerror(errno)); return 3; /* Unsuccessful load */ } /* Now read in header information from just opened datafile */ nread = read(datafile, &raw_pos, sizeof(raw_pos)); if (nread < 0) { MHVTL_LOG("%s: %s", "Error reading header in datafile, load failed", strerror(errno)); close(datafile); datafile = -1; return 4; /* Unsuccessful load */ } else if (nread < sizeof(raw_pos)) { /* Did not read anything... */ MHVTL_LOG("%s: %s", "Error: Not a tape format, load failed", strerror(errno)); close(datafile); datafile = -1; return 5; } if (raw_pos.hdr.blk_type != B_BOT) { MHVTL_LOG("Header type: %d not valid, load failed", raw_pos.hdr.blk_type); close(datafile); datafile = -1; return 6; } /* FIXME: Need better validation checking here !! */ if (raw_pos.next_blk != (sizeof(raw_pos) + sizeof(mam))) { MHVTL_LOG("MAM size incorrect, load failed" " - Expected size: %d, size found: %" PRId64, (int)(sizeof(raw_pos) + sizeof(mam)), raw_pos.next_blk); close(datafile); datafile = -1; return 7; /* Unsuccessful load */ } nread = read(datafile, &mam, sizeof(mam)); if (nread < 0) { MHVTL_LOG("Can not read MAM from mounted media, %s", strerror(errno)); close(datafile); datafile = -1; return 8; /* Unsuccessful load */ } if (nread != sizeof(mam)) { MHVTL_LOG("Can not read MAM from mounted media, " "insufficient data"); close(datafile); datafile = -1; return 9; /* Unsuccessful load */ } version = mam.tape_fmt_version; if (version != TAPE_FMT_VERSION) { MHVTL_LOG("Incorrect media format %lu", version); sam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat); close(datafile); datafile = -1; return 10; } MediumType = mam.MediumType; c_pos = &raw_pos.hdr; return 0; }