static int skip_to_next_header(uint8_t *sam_stat) { MHVTL_DBG(1, "skip_to_next_header"); if (raw_pos.hdr.blk_type == B_EOD) { sam_blank_check(E_END_OF_DATA, sam_stat); MHVTL_DBG(1, "End of data detected while forward SPACEing!!"); return -1; } if (raw_pos.next_blk != lseek64(datafile, raw_pos.next_blk, SEEK_SET)) { sam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat); MHVTL_DBG(1, "Unable to seek to next block header"); return -1; } if (read_header(&raw_pos, sam_stat)) { sam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat); MHVTL_DBG(1, "Unable to read next block header"); return -1; } /* Position to start of header (rewind over header) */ if (raw_pos.curr_blk != position_to_curr_header(sam_stat)) { sam_medium_error(E_SEQUENTIAL_POSITION_ERR, sam_stat); MHVTL_DBG(1, "Error position in datafile. Offset: %" PRId64, raw_pos.curr_blk); return -1; } return 0; }
int position_to_block(uint32_t blk_number, uint8_t *sam_stat) { if (!tape_loaded(sam_stat)) return -1; MHVTL_DBG(2, "Position to block %d", blk_number); if (mam.MediumType == MEDIA_TYPE_WORM) OK_to_write = 0; if (blk_number > eod_blk_number) { sam_blank_check(E_END_OF_DATA, sam_stat); MHVTL_DBG(1, "End of data detected while positioning"); return position_to_eod(sam_stat); } /* Treat a position to block zero specially, as it has different semantics than other blocks when the tape is WORM. */ if (blk_number == 0) return rewind_tape(sam_stat); else return read_header(blk_number, sam_stat); }
uint8_t ssc_write_attributes(struct scsi_cmd *cmd) { int sz; 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, "Write Attributes (%ld) **", (long)cmd->dbuf_p->serialNo); switch (lu_priv->tapeLoaded) { case TAPE_UNLOADED: mkSenseBuf(NOT_READY, E_MEDIUM_NOT_PRESENT, sam_stat); return SAM_STAT_CHECK_CONDITION; break; case TAPE_LOADED: cmd->dbuf_p->sz = get_unaligned_be32(&cmd->scb[10]); sz = retrieve_CDB_data(cmd->cdev, cmd->dbuf_p); MHVTL_DBG(1, " --> Expected to read %d bytes" ", read %d", cmd->dbuf_p->sz, sz); if (resp_write_attribute(cmd) > 0) rewriteMAM(sam_stat); break; default: mkSenseBuf(NOT_READY, E_MEDIUM_FMT_CORRUPT, sam_stat); return SAM_STAT_CHECK_CONDITION; break; } return SAM_STAT_GOOD; }
uint8_t ssc_report_density_support(struct scsi_cmd *cmd) { struct priv_lu_ssc *lu_priv; uint8_t *sam_stat; uint8_t media; lu_priv = cmd->lu->lu_private; sam_stat = &cmd->dbuf_p->sam_stat; media = cmd->scb[1] & 0x01; cmd->dbuf_p->sz = 0; MHVTL_DBG(1, "Report %s Density Support (%ld) **", (media) ? "mounted Media" : "Drive", (long)cmd->dbuf_p->serialNo); if (cmd->scb[1] & 0x02) { /* Don't support Medium Type (yet) */ MHVTL_DBG(1, "Medium Type - not currently supported"); mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_CDB, sam_stat); return SAM_STAT_CHECK_CONDITION; } if (media == 1 && lu_priv->tapeLoaded != TAPE_LOADED) { MHVTL_DBG(1, "Media has to be mounted to return media density"); mkSenseBuf(NOT_READY, E_MEDIUM_NOT_PRESENT, sam_stat); return SAM_STAT_CHECK_CONDITION; } cmd->dbuf_p->sz = get_unaligned_be16(&cmd->scb[7]); cmd->dbuf_p->sz = resp_report_density(lu_priv, media, cmd->dbuf_p); return SAM_STAT_GOOD; }
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; }
/* * Rewind to beginning of data file and the position to first data header. * * Return 0 -> Not loaded. * 1 -> Load OK * 2 -> format corrupt. */ int rewind_tape(uint8_t *sam_stat) { MHVTL_DBG(1, "rewind_tape"); if (rawRewind(sam_stat)) { sam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat); return 2; } if (raw_pos.hdr.blk_type != B_BOT) { sam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat); return 2; } if (skip_to_next_header(sam_stat)) return 2; switch (MediumType) { case MEDIA_TYPE_CLEAN: OK_to_write = 0; break; case MEDIA_TYPE_WORM: /* Special condition... * If we * - rewind, * - write filemark * - EOD * We set this as writable media as the tape is blank. */ if (raw_pos.hdr.blk_type != B_EOD) OK_to_write = 0; /* Check that this header is a filemark and the next header * is End of Data. If it is, we are OK to write */ if (raw_pos.hdr.blk_type == B_FILEMARK) { skip_to_next_header(sam_stat); if (raw_pos.hdr.blk_type == B_EOD) OK_to_write = 1; } /* Now we have to go thru thru the rewind again.. */ if (rawRewind(sam_stat)) { sam_medium_error(E_MEDIUM_FMT_CORRUPT, sam_stat); return 2; } /* No need to do all previous error checking... */ skip_to_next_header(sam_stat); break; case MEDIA_TYPE_DATA: OK_to_write = 1; /* Reset flag to OK. */ break; } MHVTL_DBG(1, "Media is %s", (OK_to_write) ? "writable" : "not writable"); return 1; }
/* * Initialise structure data for mode pages. * - Allocate memory for each mode page & init to 0 * - Set up size of mode page * - Set initial values of mode pages * * Return void - Nothing */ static void init_ult_mode_pages(struct lu_phy_attr *lu, struct mode *m) { struct mode *mp; MHVTL_DBG(3, "+++ Trace mode pages at %p +++", sm); mp = alloc_mode_page(m, 0x24, 0, 6); MHVTL_DBG(3, "smp: %p", mp); }
int position_blocks_forw(uint32_t count, uint8_t *sam_stat) { uint32_t residual; uint32_t blk_target; unsigned int i; if (!tape_loaded(sam_stat)) { return -1; } if (mam.MediumType == MEDIA_TYPE_WORM) OK_to_write = 0; blk_target = raw_pos.hdr.blk_number + count; /* Find the first filemark forward from our current position, if any. */ for (i = 0; i < meta.filemark_count; i++) { MHVTL_DBG(3, "filemark at %ld", (unsigned long)filemarks[i]); if (filemarks[i] >= raw_pos.hdr.blk_number) { break; } } /* If there is one, see if it is between our current position and our desired destination. */ if (i < meta.filemark_count) { if (filemarks[i] >= blk_target) { return position_to_block(blk_target, sam_stat); } residual = blk_target - raw_pos.hdr.blk_number + 1; if (read_header(filemarks[i] + 1, sam_stat)) { return -1; } MHVTL_DBG(1, "Filemark encountered: block %d", filemarks[i]); mkSenseBuf(NO_SENSE | SD_FILEMARK, E_MARK, sam_stat); put_unaligned_be32(residual, &sense[3]); return -1; } if (blk_target > eod_blk_number) { residual = blk_target - eod_blk_number; if (read_header(eod_blk_number, sam_stat)) { return -1; } MHVTL_DBG(1, "EOD encountered"); mkSenseBuf(BLANK_CHECK, E_END_OF_DATA, sam_stat); put_unaligned_be32(residual, &sense[3]); return -1; } return position_to_block(blk_target, sam_stat); }
uint8_t ssc_write_6(struct scsi_cmd *cmd) { uint8_t *cdb = cmd->scb; struct vtl_ds *dbuf_p; struct priv_lu_ssc *lu_ssc; int count; int sz; int k; int retval = 0; lu_ssc = cmd->lu->lu_private; dbuf_p = cmd->dbuf_p; current_state = MHVTL_STATE_WRITING; if (cdb[1] & FIXED) { /* If Fixed block writes */ count = get_unaligned_be24(&cdb[2]); sz = get_unaligned_be24(&modeBlockDescriptor[5]); MHVTL_DBG(last_cmd == WRITE_6 ? 2 : 1, "WRITE_6: %d blks of %d bytes (%ld) **", count, sz, (long)dbuf_p->serialNo); } else { /* else - Variable Block writes */ count = 1; sz = get_unaligned_be24(&cdb[2]); MHVTL_DBG(last_cmd == WRITE_6 ? 2 : 1, "WRITE_6: %d bytes (%ld) **", sz, (long)dbuf_p->serialNo); } /* FIXME: Should handle this instead of 'check & warn' */ if ((sz * count) > lu_ssc->bufsize) MHVTL_DBG(1, "Fatal: bufsize %d, requested write of %d bytes", lu_ssc->bufsize, sz); /* Retrieve data from kernel */ dbuf_p->sz = sz * count; retrieve_CDB_data(cmd->cdev, dbuf_p); if (!lu_ssc->pm->check_restrictions(cmd)) return SAM_STAT_CHECK_CONDITION; if (OK_to_write) { for (k = 0; k < count; k++) { retval = writeBlock(cmd, sz); dbuf_p->data += retval; /* If sam_stat != SAM_STAT_GOOD, return */ if (cmd->dbuf_p->sam_stat) return cmd->dbuf_p->sam_stat; } } return SAM_STAT_GOOD; }
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; }
uint8_t ssc_spin(struct scsi_cmd *cmd) { MHVTL_DBG(1, "Security Protocol In (%ld) **", (long)cmd->dbuf_p->serialNo); return resp_spin(cmd); }
/* * Transport Geometry Parameters mode page * SMC-3 7.3.4 */ int add_mode_transport_geometry(struct lu_phy_attr *lu) { struct list_head *mode_pg; struct mode *mp; uint8_t pcode; uint8_t subpcode; uint8_t size; mode_pg = &lu->mode_pg; pcode = MODE_TRANSPORT_GEOMETRY; subpcode = 0; size = 4; MHVTL_DBG(3, "Adding mode page %s (%02x/%02x)", mode_transport_geometry, pcode, subpcode); mp = alloc_mode_page(mode_pg, pcode, subpcode, size); if (!mp) return -ENOMEM; mp->pcodePointer[0] = pcode; mp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]); /* And copy pcode/size into bitmap structure */ mp->pcodePointerBitMap[0] = mp->pcodePointer[0]; mp->pcodePointerBitMap[1] = mp->pcodePointer[1]; mp->description = mode_transport_geometry; return 0; }
int add_mode_power_condition(struct lu_phy_attr *lu) { struct list_head *mode_pg; struct mode *mp; uint8_t pcode; uint8_t subpcode; uint8_t size; mode_pg = &lu->mode_pg; pcode = MODE_POWER_CONDITION; subpcode = 0; size = 0x26; MHVTL_DBG(3, "Adding mode page %s (%02x/%02x)", mode_power_condition, pcode, subpcode); mp = alloc_mode_page(mode_pg, pcode, subpcode, size); if (!mp) return -ENOMEM; mp->pcodePointer[0] = pcode; mp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]); /* And copy pcode/size into bitmap structure */ mp->pcodePointerBitMap[0] = mp->pcodePointer[0]; mp->pcodePointerBitMap[1] = mp->pcodePointer[1]; mp->description = mode_power_condition; return 0; }
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; }
uint8_t ssc_read_media_sn(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, "Read Medium Serial No. (%ld) **", (long)cmd->dbuf_p->serialNo); switch (lu_priv->tapeLoaded) { case TAPE_LOADED: cmd->dbuf_p->sz = resp_read_media_serial(lu_priv->mediaSerialNo, cmd->dbuf_p->data, sam_stat); break; case TAPE_UNLOADED: mkSenseBuf(NOT_READY, E_MEDIUM_NOT_PRESENT, sam_stat); return SAM_STAT_CHECK_CONDITION; break; default: mkSenseBuf(NOT_READY, E_MEDIUM_FMT_CORRUPT, sam_stat); return SAM_STAT_CHECK_CONDITION; break; } return *sam_stat; }
uint8_t ssc_read_position(struct scsi_cmd *cmd) { struct priv_lu_ssc *lu_priv; uint8_t *sam_stat; int service_action; lu_priv = cmd->lu->lu_private; sam_stat = &cmd->dbuf_p->sam_stat; MHVTL_DBG(1, "Read Position (%ld) **", (long)cmd->dbuf_p->serialNo); service_action = cmd->scb[1] & 0x1f; /* service_action == 0 or 1 -> Returns 20 bytes of data (short) */ *sam_stat = SAM_STAT_GOOD; switch (lu_priv->tapeLoaded) { case TAPE_LOADED: if ((service_action == 0) || (service_action == 1)) cmd->dbuf_p->sz = resp_read_position(c_pos->blk_number, cmd->dbuf_p->data, sam_stat); break; case TAPE_UNLOADED: mkSenseBuf(NOT_READY, E_MEDIUM_NOT_PRESENT, sam_stat); return SAM_STAT_CHECK_CONDITION; break; default: mkSenseBuf(NOT_READY, E_MEDIUM_FMT_CORRUPT, sam_stat); return SAM_STAT_CHECK_CONDITION; break; } return *sam_stat; }
uint8_t ssc_read_block_limits(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, "Read block limits (%ld) **", (long)cmd->dbuf_p->serialNo); switch (lu_priv->tapeLoaded) { case TAPE_LOADED: case TAPE_UNLOADED: cmd->dbuf_p->sz = resp_read_block_limits(cmd->dbuf_p, lu_priv->bufsize); break; default: mkSenseBuf(NOT_READY, E_MEDIUM_FMT_CORRUPT, sam_stat); return SAM_STAT_CHECK_CONDITION; break; } return SAM_STAT_GOOD; }
uint8_t ssc_rewind(struct scsi_cmd *cmd) { struct priv_lu_ssc *lu_priv; uint8_t *sam_stat; int retval; lu_priv = cmd->lu->lu_private; sam_stat = &cmd->dbuf_p->sam_stat; MHVTL_DBG(1, "Rewinding (%ld) **", (long)cmd->dbuf_p->serialNo); current_state = MHVTL_STATE_REWIND; switch (lu_priv->tapeLoaded) { case TAPE_UNLOADED: mkSenseBuf(NOT_READY, E_MEDIUM_NOT_PRESENT, sam_stat); return SAM_STAT_CHECK_CONDITION; break; case TAPE_LOADED: retval = rewind_tape(sam_stat); if (retval < 0) { mkSenseBuf(NOT_READY, E_MEDIUM_FMT_CORRUPT, sam_stat); return SAM_STAT_CHECK_CONDITION; } break; default: mkSenseBuf(NOT_READY, E_MEDIUM_FMT_CORRUPT, sam_stat); return SAM_STAT_CHECK_CONDITION; break; } return SAM_STAT_GOOD; }
void init_ait3_ssc(struct lu_phy_attr *lu) { MHVTL_DBG(3, "+++ Trace mode pages at %p +++", &lu->mode_pg); ssc_pm.name = name_ait_3; ssc_pm.lu = lu; personality_module_register(&ssc_pm); /* Drive capabilities need to be defined before mode pages */ ssc_pm.drive_supports_append_only_mode = FALSE; ssc_pm.drive_supports_early_warning = TRUE; ssc_pm.drive_supports_prog_early_warning = FALSE; init_ait_inquiry(lu); init_ait_mode_pages(lu); add_log_write_err_counter(lu); add_log_read_err_counter(lu); add_log_sequential_access(lu); add_log_temperature_page(lu); add_log_tape_alert(lu); add_log_tape_usage(lu); add_log_tape_capacity(lu); add_log_data_compression(lu); ssc_pm.native_drive_density = &density_ait3; add_density_support(&lu->den_list, &density_ait1, 0); add_density_support(&lu->den_list, &density_ait2, 1); add_density_support(&lu->den_list, &density_ait3, 1); add_drive_media_list(lu, LOAD_RO, "AIT1"); add_drive_media_list(lu, LOAD_RO, "AIT1 Clean"); add_drive_media_list(lu, LOAD_RW, "AIT2"); add_drive_media_list(lu, LOAD_RO, "AIT2 Clean"); add_drive_media_list(lu, LOAD_RW, "AIT3"); add_drive_media_list(lu, LOAD_RO, "AIT3 Clean"); }
int position_blocks(int32_t count, uint8_t *sam_stat) { MHVTL_DBG(1, "position_blocks"); if (!tape_loaded(sam_stat)) return -1; if (MediumType == MEDIA_TYPE_WORM) OK_to_write = 0; if (count < 0) { for (; count < 0; count++) { if (skip_to_prev_header(sam_stat)) return -1; if (raw_pos.hdr.blk_type == B_FILEMARK) { sam_no_sense(SD_FILEMARK, E_MARK, sam_stat); return -1; } } } else { for (; count > 0; count--) { if (skip_to_next_header(sam_stat)) return -1; if (raw_pos.hdr.blk_type == B_FILEMARK) { sam_no_sense(SD_FILEMARK, E_MARK, sam_stat); return -1; } } } return 0; }
int position_to_block(uint32_t blk_no, uint8_t *sam_stat) { MHVTL_DBG(1, "position_to_block"); if (!tape_loaded(sam_stat)) return -1; if (MediumType == MEDIA_TYPE_WORM) OK_to_write = 0; if (blk_no < raw_pos.hdr.blk_number && raw_pos.hdr.blk_number - blk_no > blk_no) { if (rewind_tape(sam_stat)) return -1; } while (raw_pos.hdr.blk_number != blk_no) { if (raw_pos.hdr.blk_number > blk_no) { if (skip_to_prev_header(sam_stat) == -1) return -1; } else { if (skip_to_next_header(sam_stat) == -1) return -1; } } return 0; }
static void update_stk_l_vpd_80(struct lu_phy_attr *lu) { struct vpd **lu_vpd = lu->lu_vpd; struct smc_priv *smc_p = lu->lu_private; uint8_t *d; int pg; smc_p = lu->lu_private; /* 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; d[0] = lu->ptype; d[1] = 0x80; /* Page code */ d[3] = 0x0b; /* Page length */ /* d[4 - 15] Serial number of device */ snprintf((char *)&d[4], 10, "%-10s", lu->lu_serial_no); /* Unique Logical Library Identifier */ } else { MHVTL_DBG(1, "Could not malloc(0x12) bytes, line %d", __LINE__); } }
/* * READ/WRITE Error Recovery * SSC3-8.3.5 */ int add_mode_page_rw_err_recovery(struct lu_phy_attr *lu) { struct list_head *mode_pg; struct mode *mp; uint8_t pcode; uint8_t subpcode; uint8_t size; pcode = MODE_RW_ERROR_RECOVER; subpcode = 0; size = 12; mode_pg = &lu->mode_pg; MHVTL_DBG(3, "Adding mode page %s (%02x/%02x)", mode_rw_error_recover, pcode, subpcode); mp = alloc_mode_page(mode_pg, pcode, subpcode, size); if (!mp) return -ENOMEM; mp->pcodePointer[0] = pcode; mp->pcodePointer[1] = size - sizeof(mp->pcodePointer[0]) - sizeof(mp->pcodePointer[1]); /* And copy pcode/size into bitmap structure */ mp->pcodePointerBitMap[0] = mp->pcodePointer[0]; mp->pcodePointerBitMap[1] = mp->pcodePointer[1]; mp->description = mode_rw_error_recover; return 0; }
int rewind_tape(uint8_t *sam_stat) { if (!tape_loaded(sam_stat)) return -1; if (read_header(0, sam_stat)) return -1; switch (mam.MediumType) { case MEDIA_TYPE_CLEAN: OK_to_write = 0; break; case MEDIA_TYPE_WORM: /* Check if this header is a filemark and the next header * is End of Data. If it is, we are OK to write */ if (raw_pos.hdr.blk_type == B_EOD || (raw_pos.hdr.blk_type == B_FILEMARK && eod_blk_number == 1)) OK_to_write = 1; else OK_to_write = 0; break; case MEDIA_TYPE_DATA: OK_to_write = 1; /* Reset flag to OK. */ break; } MHVTL_DBG(1, "Media is%s writable", (OK_to_write) ? "" : " not"); return 1; }
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; }
void init_t10kA_ssc(struct lu_phy_attr *lu) { MHVTL_DBG(3, "+++ Trace mode pages at %p +++", &lu->mode_pg); ssc_pm.name = pm_name_t10kA; ssc_pm.lu = lu; personality_module_register(&ssc_pm); /* Drive capabilities need to be defined before mode pages */ ssc_pm.drive_supports_append_only_mode = FALSE; ssc_pm.drive_supports_early_warning = TRUE; ssc_pm.drive_supports_prog_early_warning = FALSE; init_t10k_mode_pages(lu); add_log_write_err_counter(lu); add_log_read_err_counter(lu); add_log_sequential_access(lu); add_log_temperature_page(lu); add_log_tape_alert(lu); add_log_tape_usage(lu); add_log_tape_capacity(lu); add_log_data_compression(lu); ssc_pm.native_drive_density = &density_t10kA; register_ops(lu, SECURITY_PROTOCOL_IN, ssc_spin); register_ops(lu, SECURITY_PROTOCOL_OUT, ssc_spout); register_ops(lu, LOAD_DISPLAY, ssc_load_display); init_t10k_inquiry(lu); add_density_support(&lu->den_list, &density_t10kA, 1); add_drive_media_list(lu, LOAD_RW, "T10KA"); add_drive_media_list(lu, LOAD_RO, "T10KA Clean"); }
static int skip_prev_filemark(uint8_t *sam_stat) { MHVTL_DBG(1, "skip_prev_filemark"); if (raw_pos.hdr.blk_type == B_FILEMARK) raw_pos.hdr.blk_type = B_NOOP; while (raw_pos.hdr.blk_type != B_FILEMARK) { if (raw_pos.hdr.blk_type == B_BOT) { sam_no_sense(NO_SENSE, E_BOM, sam_stat); MHVTL_DBG(2, "Found Beginning of tape"); return -1; } if (skip_to_prev_header(sam_stat)) return -1; } return 0; }
void unload_tape(uint8_t *sam_stat) { MHVTL_DBG(1, "unload_tape"); if (datafile >= 0) { close(datafile); datafile = -1; } }
uint8_t ssc_allow_prevent_removal(struct scsi_cmd *cmd) { /* FIXME: Currently does nothing... */ MHVTL_DBG(1, "%s MEDIA removal (%ld) **", (cmd->scb[4]) ? "Prevent" : "Allow", (long)cmd->dbuf_p->serialNo); return SAM_STAT_GOOD; }
uint8_t ssc_load_display(struct scsi_cmd *cmd) { unsigned char *d; char str1[9]; char str2[9]; MHVTL_DBG(1, "LOAD DISPLAY (%ld) - T10000 specific **", (long)cmd->dbuf_p->serialNo); cmd->dbuf_p->sz = cmd->scb[4]; retrieve_CDB_data(cmd->cdev, cmd->dbuf_p); d = cmd->dbuf_p->data; memcpy(str1, &d[1], 8); str1[8] = 0; memcpy(str2, &d[9], 8); str2[8] = 0; MHVTL_DBG(3, "Raw data: %02x " "%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x", d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15], d[16]); switch (d[0] >> 5) { /* Bits 5, 6 & 7 are overlay */ case 0: MHVTL_DBG(1, "Display \'%s\' until next" " command that initiates tape motion", /* Low/High bit */ (d[0] & 2) ? str2 : str1); break; case 1: MHVTL_DBG(1, "Maintain \'%s\' until the" " cartridge is unloaded", /* Low/High bit */ (d[0] & 2) ? str2 : str1); break; case 2: MHVTL_DBG(1, "Maintain \'%s\' until the drive" " is next loaded", str1); break; case 3: MHVTL_DBG(1, "Physically access tape drive with" "out changing the msg"); break; case 7: MHVTL_DBG(1, "Display \'%s\' until the tape" " drive is unloaded then \'%s\'", str1, str2); break; } MHVTL_DBG(2, "Load display: msg1: %s msg2: %s", str1, str2); cmd->dbuf_p->sz = 0; return SAM_STAT_GOOD; }