static int ssc_read_block_limit(int host_no, struct scsi_cmd *cmd) { uint8_t buf[READ_BLK_LIMITS_SZ]; uint8_t block_length = ssc_get_block_length(cmd->dev); memset(buf, 0, sizeof(buf)); buf[0] = GRANULARITY; if (block_length) { /* Fixed block size */ put_unaligned_be24(block_length, buf + 1); put_unaligned_be16(block_length, buf + 4); } else { /* Variable block size */ put_unaligned_be24(MAX_BLK_SIZE, buf + 1); put_unaligned_be16(MIN_BLK_SIZE, buf + 4); } memcpy(scsi_get_in_buffer(cmd), buf, READ_BLK_LIMITS_SZ); eprintf("In ssc_read_block_limit \n"); return SAM_STAT_GOOD; }
static void tape_rdwr_request(struct scsi_cmd *cmd) { struct ssc_info *ssc = dtype_priv(cmd->dev); struct blk_header_info *h = &ssc->c_blk; int ret, code; uint32_t length, i, transfer_length, residue; int result = SAM_STAT_GOOD; uint8_t *buf; int32_t count; int8_t fixed; int8_t sti; uint32_t block_length = ssc_get_block_length(cmd->dev); ret = 0; length = 0; i = 0; transfer_length = 0; residue = 0; code = 0; ssc = dtype_priv(cmd->dev); switch (cmd->scb[0]) { case REZERO_UNIT: dprintf("**** Rewind ****\n"); if (resp_rewind(cmd->dev)) { sense_data_build(cmd, MEDIUM_ERROR, ASC_SEQUENTIAL_POSITION_ERR); result = SAM_STAT_CHECK_CONDITION; } break; case WRITE_FILEMARKS: ret = get_unaligned_be24(&cmd->scb[2]); dprintf("*** Write %d filemark%s ***\n", ret, ((ret > 1) || (ret < 0)) ? "s" : ""); for (i = 0; i < ret; i++) append_blk(cmd, scsi_get_out_buffer(cmd), 0, 0, BLK_FILEMARK); fsync(cmd->dev->fd); break; case READ_6: fixed = cmd->scb[1] & 1; sti = cmd->scb[1] & 2; if (fixed && sti) { sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB); result = SAM_STAT_CHECK_CONDITION; break; } length = scsi_get_in_length(cmd); count = get_unaligned_be24(&cmd->scb[2]); buf = scsi_get_in_buffer(cmd); dprintf("*** READ_6: length %d, count %d, fixed block %s," " %" PRIu64 " %d\n", length, count, (fixed) ? "Yes" : "No", h->curr, sti); if (fixed) result = resp_fixed_read(cmd, buf, length, &ret); else result = resp_var_read(cmd, buf, length, &ret); eprintf("Executed READ_6, Read %d bytes, %" PRIu64 "\n", ret, h->curr); break; case WRITE_6: fixed = cmd->scb[1] & 1; buf = scsi_get_out_buffer(cmd); count = get_unaligned_be24(&cmd->scb[2]); length = scsi_get_out_length(cmd); if (!fixed) { block_length = length; count = 1; } for (i = 0, ret = 0; i < count; i++) { if (append_blk(cmd, buf, block_length, block_length, BLK_UNCOMPRESS_DATA)) { sense_data_build(cmd, MEDIUM_ERROR, ASC_WRITE_ERROR); result = SAM_STAT_CHECK_CONDITION; break; } buf += block_length; ret += block_length; } dprintf("*** WRITE_6 count: %d, length: %d, ret: %d, fixed: %s," " ssc->blk_sz: %d\n", count, length, ret, (fixed) ? "Yes" : "No", block_length); /* Check for end of media */ if (current_size(cmd) > ssc->mam.max_capacity) { sense_data_build(cmd, NO_SENSE|SENSE_EOM, NO_ADDITIONAL_SENSE); result = SAM_STAT_CHECK_CONDITION; break; } if (ret != length) { sense_data_build(cmd, MEDIUM_ERROR, ASC_WRITE_ERROR); result = SAM_STAT_CHECK_CONDITION; } break; case SPACE: code = cmd->scb[1] & 0xf; count = be24_to_2comp(&cmd->scb[2]); if (code == 0) { /* Logical Blocks */ result = space_blocks(cmd, count); break; } else if (code == 1) { /* Filemarks */ result = space_filemark(cmd, count); break; } else if (code == 3) { /* End of data */ while (h->blk_type != BLK_EOD) if (skip_next_header(cmd->dev)) { sense_data_build(cmd, MEDIUM_ERROR, ASC_MEDIUM_FORMAT_CORRUPT); result = SAM_STAT_CHECK_CONDITION; break; } } else { /* Unsupported */ sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB); result = SAM_STAT_CHECK_CONDITION; } break; case READ_POSITION: { int service_action = cmd->scb[1] & 0x1f; uint8_t *data = scsi_get_in_buffer(cmd); int len = scsi_get_in_length(cmd); dprintf("Size of in_buffer = %d\n", len); dprintf("Sizeof(buf): %zd\n", sizeof(buf)); dprintf("service action: 0x%02x\n", service_action); if (service_action == 0) { /* Short form - block ID */ memset(data, 0, 20); data[0] = 20; } else if (service_action == 1) { /* Short form - vendor uniq */ memset(data, 0, 20); data[0] = 20; } else if (service_action == 6) { /* Long form */ memset(data, 0, 32); data[0] = 32; } else { sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB); result = SAM_STAT_CHECK_CONDITION; } break; } default: eprintf("Unknown op code - should never see this\n"); sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE); result = SAM_STAT_CHECK_CONDITION; break; } dprintf("io done %p %x %d %u\n", cmd, cmd->scb[0], ret, length); scsi_set_result(cmd, result); if (result != SAM_STAT_GOOD) eprintf("io error %p %x %d %d %" PRIu64 ", %m\n", cmd, cmd->scb[0], ret, length, cmd->offset); }
static int resp_fixed_read(struct scsi_cmd *cmd, uint8_t *buf, uint32_t length, int *transferred) { struct ssc_info *ssc = dtype_priv(cmd->dev); struct blk_header_info *h = &ssc->c_blk; int i, ret, result = SAM_STAT_GOOD; int count; ssize_t residue; int fd; uint32_t block_length = ssc_get_block_length(cmd->dev); count = get_unaligned_be24(&cmd->scb[2]); fd = cmd->dev->fd; ret = 0; for (i = 0; i < count; i++) { if (h->blk_type == BLK_FILEMARK) { uint8_t info[4]; eprintf("Oops - found filemark\n"); put_unaligned_be32(count - i, info); ssc_sense_data_build(cmd, NO_SENSE | SENSE_FILEMARK, ASC_MARK, info, sizeof(info)); skip_next_header(cmd->dev); result = SAM_STAT_CHECK_CONDITION; goto out; } if (block_length != h->blk_sz) { eprintf("block size mismatch %d vs %d\n", block_length, h->blk_sz); sense_data_build(cmd, MEDIUM_ERROR, ASC_MEDIUM_FORMAT_CORRUPT); result = SAM_STAT_CHECK_CONDITION; goto out; } residue = pread64(fd, buf, block_length, h->curr + SSC_BLK_HDR_SIZE); if (block_length != residue) { eprintf("Could only read %d bytes, not %d\n", (int)residue, block_length); sense_data_build(cmd, MEDIUM_ERROR, ASC_READ_ERROR); result = SAM_STAT_CHECK_CONDITION; goto out; } ret += block_length; buf += block_length; if (skip_next_header(cmd->dev)) { eprintf("Could not read next header\n"); sense_data_build(cmd, MEDIUM_ERROR, ASC_MEDIUM_FORMAT_CORRUPT); result = SAM_STAT_CHECK_CONDITION; goto out; } } *transferred = ret; out: return result; }