static int space_filemark_forward(struct scsi_cmd *cmd, int32_t count) { struct ssc_info *ssc = dtype_priv(cmd->dev); struct blk_header_info *h = &ssc->c_blk; again: if (h->blk_type == BLK_EOD) { sense_data_build(cmd, NO_SENSE, ASC_END_OF_DATA); return SAM_STAT_CHECK_CONDITION; } if (h->blk_type == BLK_FILEMARK) count--; if (skip_next_header(cmd->dev)) { sense_data_build(cmd, MEDIUM_ERROR, ASC_MEDIUM_FORMAT_CORRUPT); return SAM_STAT_CHECK_CONDITION; } if (count > 0) goto again; return SAM_STAT_GOOD; }
static int resp_var_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 ret = 0, result = SAM_STAT_GOOD; length = min(length, get_unaligned_be24(&cmd->scb[2])); *transferred = 0; if (length != h->blk_sz) { uint8_t info[4]; int val = length - h->blk_sz; put_unaligned_be32(val, info); if (h->blk_type == BLK_EOD) sense_data_build(cmd, 0x40 | BLANK_CHECK, NO_ADDITIONAL_SENSE); else ssc_sense_data_build(cmd, NO_SENSE | 0x20, NO_ADDITIONAL_SENSE, info, sizeof(info)); if (length > h->blk_sz) scsi_set_in_resid_by_actual(cmd, length - h->blk_sz); else scsi_set_in_resid_by_actual(cmd, 0); length = min(length, h->blk_sz); result = SAM_STAT_CHECK_CONDITION; if (!length) goto out; } ret = pread64(cmd->dev->fd, buf, length, h->curr + SSC_BLK_HDR_SIZE); if (ret != length) { sense_data_build(cmd, MEDIUM_ERROR, ASC_READ_ERROR); result = SAM_STAT_CHECK_CONDITION; goto out; } *transferred = length; ret = skip_next_header(cmd->dev); if (ret) { sense_data_build(cmd, MEDIUM_ERROR, ASC_MEDIUM_FORMAT_CORRUPT); result = SAM_STAT_CHECK_CONDITION; } out: return result; }
static int bs_paio_cmd_submit(struct scsi_cmd *cmd) { struct scsi_lu *lu = cmd->dev; struct aiocb *io=NULL; int ret = 0; switch (cmd->scb[0]) { case SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE_16: break; case WRITE_6: case WRITE_10: case WRITE_12: case WRITE_16: io=calloc(1, sizeof(*io)+sizeof(cmd)); io->aio_fildes=lu->fd; io->aio_buf=scsi_get_out_buffer(cmd); io->aio_offset=cmd->offset; io->aio_nbytes=scsi_get_out_length(cmd); io->aio_sigevent.sigev_notify=SIGEV_THREAD; io->aio_sigevent.sigev_notify_function=paio_done; io->aio_sigevent.sigev_notify_attributes=NULL; io->aio_sigevent.sigev_value.sival_ptr=io; *(struct scsi_cmd **)(io+1)=cmd; ret=aio_write(io); if(ret==0){ set_cmd_async(cmd); return 0; } break; case READ_6: case READ_10: case READ_12: case READ_16: io=calloc(1, sizeof(*io)+sizeof(cmd)); io->aio_fildes=lu->fd; io->aio_buf=scsi_get_in_buffer(cmd); io->aio_offset=cmd->offset; io->aio_nbytes=scsi_get_in_length(cmd); io->aio_sigevent.sigev_notify=SIGEV_THREAD; io->aio_sigevent.sigev_notify_function=paio_done; io->aio_sigevent.sigev_notify_attributes=NULL; io->aio_sigevent.sigev_value.sival_ptr=io; *(struct scsi_cmd **)(io+1)=cmd; ret=aio_read(io); if(ret==0){ set_cmd_async(cmd); return 0; } break; default: break; } if(ret!=0){ sense_data_build(cmd, MEDIUM_ERROR, 0); ret = SAM_STAT_CHECK_CONDITION; } return ret; }
static int ssc_rw(int host_no, struct scsi_cmd *cmd) { int ret; unsigned char key = ILLEGAL_REQUEST; uint16_t asc = ASC_LUN_NOT_SUPPORTED; ret = device_reserved(cmd); if (ret) return SAM_STAT_RESERVATION_CONFLICT; cmd->scsi_cmd_done = target_cmd_io_done; ret = cmd->dev->bst->bs_cmd_submit(cmd); if (ret) { key = HARDWARE_ERROR; asc = ASC_INTERNAL_TGT_FAILURE; } else { set_cmd_mmapio(cmd); return SAM_STAT_GOOD; } cmd->offset = 0; scsi_set_in_resid_by_actual(cmd, 0); scsi_set_out_resid_by_actual(cmd, 0); sense_data_build(cmd, key, asc); return SAM_STAT_CHECK_CONDITION; }
static int ibmvio_inquiry(int host_no, struct scsi_cmd *cmd) { uint8_t *data, *scb = cmd->scb; unsigned char key = ILLEGAL_REQUEST; uint16_t asc = ASC_INVALID_FIELD_IN_CDB; uint32_t len; if (((scb[1] & 0x3) == 0x3) || (!(scb[1] & 0x3) && scb[2])) goto sense; dprintf("%x %x\n", scb[1], scb[2]); if (scb[1] & 0x3) return spc_inquiry(host_no, cmd); data = scsi_get_in_buffer(cmd); len = __ibmvio_inquiry(host_no, cmd, data); len = min_t(int, len, scb[4]); scsi_set_in_resid_by_actual(cmd, len); if (cmd->dev->lun != cmd->dev_id) data[0] = TYPE_NO_LUN; return SAM_STAT_GOOD; sense: scsi_set_in_resid_by_actual(cmd, 0); sense_data_build(cmd, key, asc); return SAM_STAT_CHECK_CONDITION; }
static int mode_sense(struct tgt_device *dev, uint8_t *scb, uint8_t *data, int *len) { int result = SAM_STAT_GOOD; uint8_t pcode = scb[2] & 0x3f; uint64_t size; *len = 4; size = dev->size >> BLK_SHIFT; if ((scb[1] & 0x8)) data[3] = 0; else { data[3] = 8; *len += 8; *(uint32_t *)(data + 4) = (size >> 32) ? __cpu_to_be32(0xffffffff) : __cpu_to_be32(size); *(uint32_t *)(data + 8) = __cpu_to_be32(1 << BLK_SHIFT); } switch (pcode) { case 0x0: break; case 0x2: *len += insert_disconnect_pg(data + *len); break; case 0x3: *len += insert_format_m_pg(data + *len); break; case 0x4: *len += insert_geo_m_pg(data + *len, size); break; case 0x8: *len += insert_caching_pg(data + *len); break; case 0xa: *len += insert_ctrl_m_pg(data + *len); break; case 0x1c: *len += insert_iec_m_pg(data + *len); break; case 0x3f: *len += insert_disconnect_pg(data + *len); *len += insert_format_m_pg(data + *len); *len += insert_geo_m_pg(data + *len, size); *len += insert_caching_pg(data + *len); *len += insert_ctrl_m_pg(data + *len); *len += insert_iec_m_pg(data + *len); break; default: result = SAM_STAT_CHECK_CONDITION; *len = sense_data_build(data, 0x70, ILLEGAL_REQUEST, 0x24, 0); } data[0] = *len - 1; return result; }
static void ssc_sense_data_build(struct scsi_cmd *cmd, uint8_t key, uint16_t asc, uint8_t *info, int info_len) { /* TODO: support descriptor format */ sense_data_build(cmd, key, asc); if (info_len) { memcpy(cmd->sense_buffer + 3, info, 4); cmd->sense_buffer[0] |= 0x80; } }
static int space_blocks(struct scsi_cmd *cmd, int32_t count) { struct ssc_info *ssc = dtype_priv(cmd->dev); struct blk_header_info *h = &ssc->c_blk; dprintf("*** space %d blocks, %" PRIu64 "\n", count, h->curr); while (count != 0) { if (count > 0) { if (skip_next_header(cmd->dev)) { sense_data_build(cmd, MEDIUM_ERROR, ASC_MEDIUM_FORMAT_CORRUPT); return SAM_STAT_CHECK_CONDITION; } if (h->blk_type == BLK_EOD) { sense_data_build(cmd, NO_SENSE, ASC_END_OF_DATA); return SAM_STAT_CHECK_CONDITION; } count--; } else { if (skip_prev_header(cmd->dev)) { sense_data_build(cmd, MEDIUM_ERROR, ASC_MEDIUM_FORMAT_CORRUPT); return SAM_STAT_CHECK_CONDITION; } if (h->blk_type == BLK_BOT) { /* Can't leave at BOT */ skip_next_header(cmd->dev); sense_data_build(cmd, NO_SENSE, ASC_BOM); return SAM_STAT_CHECK_CONDITION; } count++; } } dprintf("%" PRIu64 "\n", h->curr); return SAM_STAT_GOOD; }
static int spt_cmd_perform(int host_no, struct scsi_cmd *cmd) { int ret; struct device_type_operations *ops; if (!cmd->dev) { ops = cmd->c_target->dev_type_template.ops; return ops[cmd->scb[0]].cmd_perform(host_no, cmd); } ret = spt_sg_perform(cmd); if (ret) { cmd->len = 0; sense_data_build(cmd, ILLEGAL_REQUEST, 0x25, 0); return SAM_STAT_CHECK_CONDITION; } else return SAM_STAT_GOOD; }
static int __report_luns(struct list_head *dev_list, uint8_t *lun_buf, uint8_t *scb, uint8_t *p, int *len) { struct tgt_device *dev; uint64_t lun, *data = (uint64_t *) p; int idx, alen, oalen, nr_luns, rbuflen = 4096; int result = SAM_STAT_GOOD; memset(data, 0, rbuflen); alen = __be32_to_cpu(*(uint32_t *)&scb[6]); if (alen < 16) { *len = sense_data_build(p, 0x70, ILLEGAL_REQUEST, 0x24, 0); return SAM_STAT_CHECK_CONDITION; } alen &= ~(8 - 1); oalen = alen; alen -= 8; rbuflen -= 8; /* FIXME */ idx = 1; nr_luns = 0; list_for_each_entry(dev, dev_list, d_list) { lun = dev->lun; lun = ((lun > 0xff) ? (0x1 << 30) : 0) | ((0x3ff & lun) << 16); data[idx++] = __cpu_to_be64(lun << 32); if (!(alen -= 8)) break; if (!(rbuflen -= 8)) { fprintf(stderr, "FIXME: too many luns\n"); exit(-1); } nr_luns++; }
static void bs_rbd_request(struct scsi_cmd *cmd) { int ret; uint32_t length; int result = SAM_STAT_GOOD; uint8_t key; uint16_t asc; #if 0 /* * This should go in the sense data on error for COMPARE_AND_WRITE, but * there doesn't seem to be any attempt to do so... */ uint32_t info = 0; #endif char *tmpbuf; size_t blocksize; uint64_t offset = cmd->offset; uint32_t tl = cmd->tl; int do_verify = 0; int i; char *ptr; const char *write_buf = NULL; ret = length = 0; key = asc = 0; struct active_rbd *rbd = RBDP(cmd->dev->fd); switch (cmd->scb[0]) { case ORWRITE_16: length = scsi_get_out_length(cmd); tmpbuf = malloc(length); if (!tmpbuf) { result = SAM_STAT_CHECK_CONDITION; key = HARDWARE_ERROR; asc = ASC_INTERNAL_TGT_FAILURE; break; } ret = rbd_read(rbd->rbd_image, offset, length, tmpbuf); if (ret != length) { set_medium_error(&result, &key, &asc); free(tmpbuf); break; } ptr = scsi_get_out_buffer(cmd); for (i = 0; i < length; i++) ptr[i] |= tmpbuf[i]; free(tmpbuf); write_buf = scsi_get_out_buffer(cmd); goto write; case COMPARE_AND_WRITE: /* Blocks are transferred twice, first the set that * we compare to the existing data, and second the set * to write if the compare was successful. */ length = scsi_get_out_length(cmd) / 2; if (length != cmd->tl) { result = SAM_STAT_CHECK_CONDITION; key = ILLEGAL_REQUEST; asc = ASC_INVALID_FIELD_IN_CDB; break; } tmpbuf = malloc(length); if (!tmpbuf) { result = SAM_STAT_CHECK_CONDITION; key = HARDWARE_ERROR; asc = ASC_INTERNAL_TGT_FAILURE; break; } ret = rbd_read(rbd->rbd_image, offset, length, tmpbuf); if (ret != length) { set_medium_error(&result, &key, &asc); free(tmpbuf); break; } if (memcmp(scsi_get_out_buffer(cmd), tmpbuf, length)) { uint32_t pos = 0; char *spos = scsi_get_out_buffer(cmd); char *dpos = tmpbuf; /* * Data differed, this is assumed to be 'rare' * so use a much more expensive byte-by-byte * comparasion to find out at which offset the * data differs. */ for (pos = 0; pos < length && *spos++ == *dpos++; pos++) ; #if 0 /* See comment above at declaration */ info = pos; #endif result = SAM_STAT_CHECK_CONDITION; key = MISCOMPARE; asc = ASC_MISCOMPARE_DURING_VERIFY_OPERATION; free(tmpbuf); break; } /* no DPO bit (cache retention advice) support */ free(tmpbuf); write_buf = scsi_get_out_buffer(cmd) + length; goto write; case SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE_16: /* TODO */ length = (cmd->scb[0] == SYNCHRONIZE_CACHE) ? 0 : 0; if (cmd->scb[1] & 0x2) { result = SAM_STAT_CHECK_CONDITION; key = ILLEGAL_REQUEST; asc = ASC_INVALID_FIELD_IN_CDB; } else bs_sync_sync_range(cmd, length, &result, &key, &asc); break; case WRITE_VERIFY: case WRITE_VERIFY_12: case WRITE_VERIFY_16: do_verify = 1; case WRITE_6: case WRITE_10: case WRITE_12: case WRITE_16: length = scsi_get_out_length(cmd); write_buf = scsi_get_out_buffer(cmd); write: ret = rbd_write(rbd->rbd_image, offset, length, write_buf); if (ret == length) { struct mode_pg *pg; /* * it would be better not to access to pg * directy. */ pg = find_mode_page(cmd->dev, 0x08, 0); if (pg == NULL) { result = SAM_STAT_CHECK_CONDITION; key = ILLEGAL_REQUEST; asc = ASC_INVALID_FIELD_IN_CDB; break; } if (((cmd->scb[0] != WRITE_6) && (cmd->scb[1] & 0x8)) || !(pg->mode_data[0] & 0x04)) bs_sync_sync_range(cmd, length, &result, &key, &asc); } else set_medium_error(&result, &key, &asc); if (do_verify) goto verify; break; case WRITE_SAME: case WRITE_SAME_16: /* WRITE_SAME used to punch hole in file */ if (cmd->scb[1] & 0x08) { ret = rbd_discard(rbd->rbd_image, offset, tl); if (ret != 0) { eprintf("Failed to punch hole for WRITE_SAME" " command\n"); result = SAM_STAT_CHECK_CONDITION; key = HARDWARE_ERROR; asc = ASC_INTERNAL_TGT_FAILURE; break; } break; } while (tl > 0) { blocksize = 1 << cmd->dev->blk_shift; tmpbuf = scsi_get_out_buffer(cmd); switch (cmd->scb[1] & 0x06) { case 0x02: /* PBDATA==0 LBDATA==1 */ put_unaligned_be32(offset, tmpbuf); break; case 0x04: /* PBDATA==1 LBDATA==0 */ /* physical sector format */ put_unaligned_be64(offset, tmpbuf); break; } ret = rbd_write(rbd->rbd_image, offset, blocksize, tmpbuf); if (ret != blocksize) set_medium_error(&result, &key, &asc); offset += blocksize; tl -= blocksize; } break; case READ_6: case READ_10: case READ_12: case READ_16: length = scsi_get_in_length(cmd); ret = rbd_read(rbd->rbd_image, offset, length, scsi_get_in_buffer(cmd)); if (ret != length) set_medium_error(&result, &key, &asc); break; case PRE_FETCH_10: case PRE_FETCH_16: break; case VERIFY_10: case VERIFY_12: case VERIFY_16: verify: length = scsi_get_out_length(cmd); tmpbuf = malloc(length); if (!tmpbuf) { result = SAM_STAT_CHECK_CONDITION; key = HARDWARE_ERROR; asc = ASC_INTERNAL_TGT_FAILURE; break; } ret = rbd_read(rbd->rbd_image, offset, length, tmpbuf); if (ret != length) set_medium_error(&result, &key, &asc); else if (memcmp(scsi_get_out_buffer(cmd), tmpbuf, length)) { result = SAM_STAT_CHECK_CONDITION; key = MISCOMPARE; asc = ASC_MISCOMPARE_DURING_VERIFY_OPERATION; } free(tmpbuf); break; case UNMAP: if (!cmd->dev->attrs.thinprovisioning) { result = SAM_STAT_CHECK_CONDITION; key = ILLEGAL_REQUEST; asc = ASC_INVALID_FIELD_IN_CDB; break; } length = scsi_get_out_length(cmd); tmpbuf = scsi_get_out_buffer(cmd); if (length < 8) break; length -= 8; tmpbuf += 8; while (length >= 16) { offset = get_unaligned_be64(&tmpbuf[0]); offset = offset << cmd->dev->blk_shift; tl = get_unaligned_be32(&tmpbuf[8]); tl = tl << cmd->dev->blk_shift; if (offset + tl > cmd->dev->size) { eprintf("UNMAP beyond EOF\n"); result = SAM_STAT_CHECK_CONDITION; key = ILLEGAL_REQUEST; asc = ASC_LBA_OUT_OF_RANGE; break; } if (tl > 0) { if (rbd_discard(rbd->rbd_image, offset, tl) != 0) { eprintf("Failed to punch hole for" " UNMAP at offset:%" PRIu64 " length:%d\n", offset, tl); result = SAM_STAT_CHECK_CONDITION; key = HARDWARE_ERROR; asc = ASC_INTERNAL_TGT_FAILURE; break; } } length -= 16; tmpbuf += 16; } break; default: 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, offset); sense_data_build(cmd, key, asc); } }
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; }
static int append_blk(struct scsi_cmd *cmd, uint8_t *data, int size, int orig_sz, int type) { int fd; struct ssc_info *ssc = dtype_priv(cmd->dev); struct blk_header_info c, *curr = &c; struct blk_header_info e, *eod = &e; ssize_t ret; fd = cmd->dev->fd; *curr = ssc->c_blk; dprintf("B4 update : prev/curr/next" " <%" PRId64 "/%" PRId64 "/%" PRId64 "> type: %d," " num: %" PRIx64 ", ondisk sz: %d, about to write %d\n", curr->prev, curr->curr, curr->next, curr->blk_type, curr->blk_num, curr->ondisk_sz, size); curr->next = curr->curr + size + SSC_BLK_HDR_SIZE; curr->blk_type = type; curr->ondisk_sz = size; curr->blk_sz = orig_sz; eod->prev = curr->curr; eod->curr = curr->next; eod->next = curr->next; eod->ondisk_sz = 0; eod->blk_sz = 0; eod->blk_type = BLK_EOD; eod->blk_num = curr->blk_num + 1; memcpy(&ssc->c_blk, eod, sizeof(*eod)); dprintf("After update : prev/curr/next <%" PRId64 "/%" PRId64 "/%" PRId64 "> type: %d, num: %" PRIx64 ", ondisk sz: %d\n", curr->prev, curr->curr, curr->next, curr->blk_type, curr->blk_num, curr->ondisk_sz); dprintf("EOD blk header: prev/curr/next <%" PRId64 "/%" PRId64 "/%" PRId64 "> type: %d, num: %" PRIx64 ", ondisk sz: %d\n", eod->prev, eod->curr, eod->next, eod->blk_type, eod->blk_num, eod->ondisk_sz); /* Rewrite previous header with updated positioning info */ ret = ssc_write_blkhdr(fd, curr, curr->curr); if (ret) { eprintf("Rewrite of blk header failed: %m\n"); sense_data_build(cmd, MEDIUM_ERROR, ASC_WRITE_ERROR); return SAM_STAT_CHECK_CONDITION; } /* Write new EOD blk header */ ret = ssc_write_blkhdr(fd, eod, eod->curr); if (ret) { eprintf("Write of EOD blk header failed: %m\n"); sense_data_build(cmd, MEDIUM_ERROR, ASC_WRITE_ERROR); return SAM_STAT_CHECK_CONDITION; } /* Write any data */ if (size) { ret = pwrite64(fd, data, size, curr->curr + SSC_BLK_HDR_SIZE); if (ret != size) { eprintf("Write of data failed: %m\n"); sense_data_build(cmd, MEDIUM_ERROR, ASC_WRITE_ERROR); return SAM_STAT_CHECK_CONDITION; } } /* Write new EOD blk header */ return SAM_STAT_GOOD; }
int spc_inquiry(int host_no, struct scsi_cmd *cmd) { int len, ret = SAM_STAT_CHECK_CONDITION; uint8_t *data; uint8_t *scb = cmd->scb; unsigned char device_type = cmd->c_target->dev_type_template.type; char *product_id = cmd->c_target->dev_type_template.pid; unsigned char key = ILLEGAL_REQUEST, asc = 0x24; if (((scb[1] & 0x3) == 0x3) || (!(scb[1] & 0x3) && scb[2])) goto sense; data = valloc(pagesize); if (!data) { key = HARDWARE_ERROR; asc = 0; goto sense; } memset(data, 0, pagesize); dprintf("%x %x\n", scb[1], scb[2]); if (!(scb[1] & 0x3)) { data[0] = device_type; data[2] = 4; data[3] = 0x42; data[4] = 59; data[7] = 0x02; memset(data + 8, 0x20, 28); strncpy(data + 8, VENDOR_ID, 8); strncpy(data + 16, product_id, 16); strncpy(data + 32, PRODUCT_REV, 4); data[58] = 0x03; data[59] = 0x20; data[60] = 0x09; data[61] = 0x60; data[62] = 0x03; data[63] = 0x00; len = 64; ret = SAM_STAT_GOOD; } else if (scb[1] & 0x2) { /* CmdDt bit is set */ /* We do not support it now. */ data[1] = 0x1; data[5] = 0; len = 6; ret = SAM_STAT_GOOD; } else if (scb[1] & 0x1) { /* EVPD bit set */ if (scb[2] == 0x0) { data[0] = device_type; data[1] = 0x0; data[3] = 3; data[4] = 0x0; data[5] = 0x80; data[6] = 0x83; len = 7; ret = SAM_STAT_GOOD; } else if (scb[2] == 0x80) { int tmp = SCSI_SN_LEN; data[1] = 0x80; data[3] = SCSI_SN_LEN; memset(data + 4, 0x20, 4); len = 4 + SCSI_SN_LEN; ret = SAM_STAT_GOOD; if (cmd->dev && strlen(cmd->dev->scsi_sn)) { uint8_t *p; char *q; p = data + 4 + tmp - 1; q = cmd->dev->scsi_sn + SCSI_SN_LEN - 1; for (; tmp > 0; tmp--, q) *(p--) = *(q--); } } else if (scb[2] == 0x83) { int tmp = SCSI_ID_LEN; data[1] = 0x83; data[3] = tmp + 4; data[4] = 0x1; data[5] = 0x1; data[7] = tmp; if (cmd->dev) strncpy((char *) data + 8, cmd->dev->scsi_id, SCSI_ID_LEN); len = tmp + 8; ret = SAM_STAT_GOOD; } } if (ret != SAM_STAT_GOOD) goto sense; cmd->len = min_t(int, len, scb[4]); cmd->uaddr = (unsigned long) data; if (!cmd->dev) data[0] = TYPE_NO_LUN; return SAM_STAT_GOOD; sense: cmd->len = 0; sense_data_build(cmd, key, asc, 0); return SAM_STAT_CHECK_CONDITION; }
static int __inquiry(struct tgt_device *dev, int host_no, uint8_t *lun_buf, uint8_t *scb, uint8_t *data, int *len) { int result = SAM_STAT_CHECK_CONDITION; if (((scb[1] & 0x3) == 0x3) || (!(scb[1] & 0x3) && scb[2])) goto err; dprintf("%x %x\n", scb[1], scb[2]); if (!(scb[1] & 0x3)) { data[2] = 4; data[3] = 0x42; data[4] = 59; data[7] = 0x02; memset(data + 8, 0x20, 28); memcpy(data + 8, VENDOR_ID, min_t(size_t, strlen(VENDOR_ID), 8)); memcpy(data + 16, PRODUCT_ID, min_t(size_t, strlen(PRODUCT_ID), 16)); memcpy(data + 32, PRODUCT_REV, min_t(size_t, strlen(PRODUCT_REV), 4)); data[58] = 0x03; data[59] = 0x20; data[60] = 0x09; data[61] = 0x60; data[62] = 0x03; data[63] = 0x00; *len = 64; result = SAM_STAT_GOOD; } else if (scb[1] & 0x2) { /* CmdDt bit is set */ /* We do not support it now. */ data[1] = 0x1; data[5] = 0; *len = 6; result = SAM_STAT_GOOD; } else if (scb[1] & 0x1) { /* EVPD bit set */ if (scb[2] == 0x0) { data[1] = 0x0; data[3] = 3; data[4] = 0x0; data[5] = 0x80; data[6] = 0x83; *len = 7; result = SAM_STAT_GOOD; } else if (scb[2] == 0x80) { data[1] = 0x80; data[3] = 4; memset(data + 4, 0x20, 4); *len = 8; result = SAM_STAT_GOOD; } else if (scb[2] == 0x83) { uint32_t tmp = SCSI_ID_LEN * sizeof(uint8_t); data[1] = 0x83; data[3] = tmp + 4; data[4] = 0x1; data[5] = 0x1; data[7] = tmp; if (dev) strncpy(data + 8, dev->scsi_id, SCSI_ID_LEN); *len = tmp + 8; result = SAM_STAT_GOOD; } } if (result != SAM_STAT_GOOD) goto err; *len = min_t(int, *len, scb[4]); if (!dev) data[0] = TYPE_NO_LUN; return SAM_STAT_GOOD; err: *len = sense_data_build(data, 0x70, ILLEGAL_REQUEST, 0x24, 0); return SAM_STAT_CHECK_CONDITION; }