Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
	}
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}
Beispiel #10
0
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++;
	}
Beispiel #11
0
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);
	}
}
Beispiel #12
0
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);
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
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;
}
Beispiel #16
0
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;
}