Commit 0244b5d7 authored by Pawel Wodkowski's avatar Pawel Wodkowski Committed by Jim Harris
Browse files

scsi_bdev: respect allocation length in MODE SENSE 6 and 10



This refactor MODE SENSE 6 and 10 related functions to respect buffer
size parameter.

Change-Id: I03bad456bac0554a8bf7b56f69d1f9cf5b1991f6
Signed-off-by: default avatarPawel Wodkowski <pawelx.wodkowski@intel.com>
parent f30f0c76
Loading
Loading
Loading
Loading
+93 −140
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@

#include "scsi_internal.h"

#include "spdk/env.h"
#include "spdk/bdev.h"
#include "spdk/endian.h"
#include "spdk/string.h"
@@ -783,6 +784,9 @@ inq_error:
static void
mode_sense_page_init(uint8_t *buf, int len, int page, int subpage)
{
	if (!buf)
		return;

	memset(buf, 0, len);
	if (subpage != 0) {
		buf[0] = page | 0x40; /* PAGE + SPF=1 */
@@ -797,9 +801,9 @@ mode_sense_page_init(uint8_t *buf, int len, int page, int subpage)
static int
spdk_bdev_scsi_mode_sense_page(struct spdk_bdev *bdev,
			       uint8_t *cdb, int pc, int page, int subpage,
			       uint8_t *data, int alloc_len)
			       uint8_t *data)
{
	uint8_t *cp;
	uint8_t *cp = data;
	int len = 0;
	int plen;
	int i;
@@ -816,7 +820,6 @@ spdk_bdev_scsi_mode_sense_page(struct spdk_bdev *bdev,
		return -1;
	}

	cp = &data[len];
	switch (page) {
	case 0x00:
		/* Vendor specific */
@@ -874,17 +877,11 @@ spdk_bdev_scsi_mode_sense_page(struct spdk_bdev *bdev,
		plen = 0x12 + 2;
		mode_sense_page_init(cp, plen, page, subpage);

		if (bdev->write_cache)
		if (cp && bdev->write_cache)
			cp[2] |= 0x4; /* WCE */
		// TODO:
		//fd = bdev->fd;
		//rc = fcntl(fd , F_GETFL, 0);
		//if (rc != -1 && !(rc & O_FSYNC))
		//	cp[2] |= 0x4; /* WCE=1 */
		//else
		//	cp[2] &= 0xfb; /* WCE = 0 */

		/* Read Cache Disable (RCD) = 1 */
		if (cp)
			cp[2] |= 0x1;

		len += plen;
@@ -916,13 +913,11 @@ spdk_bdev_scsi_mode_sense_page(struct spdk_bdev *bdev,
			len += spdk_bdev_scsi_mode_sense_page(bdev,
							      cdb, pc, page,
							      0x00,
							      &data[len],
							      alloc_len);
							      cp ? &cp[len] : NULL);
			len += spdk_bdev_scsi_mode_sense_page(bdev,
							      cdb, pc, page,
							      0x01,
							      &data[len],
							      alloc_len);
							      cp ? &cp[len] : NULL);
			break;
		default:
			/* 0x02-0x3e: Reserved */
@@ -1039,7 +1034,7 @@ spdk_bdev_scsi_mode_sense_page(struct spdk_bdev *bdev,
			for (i = 0x00; i < 0x3e; i ++) {
				len += spdk_bdev_scsi_mode_sense_page(
					       bdev, cdb, pc, i, 0x00,
					       &cp[len], alloc_len);
					       cp ? &cp[len] : NULL);
			}
			break;
		case 0xff:
@@ -1047,12 +1042,12 @@ spdk_bdev_scsi_mode_sense_page(struct spdk_bdev *bdev,
			for (i = 0x00; i < 0x3e; i ++) {
				len += spdk_bdev_scsi_mode_sense_page(
					       bdev, cdb, pc, i, 0x00,
					       &cp[len], alloc_len);
					       cp ? &cp[len] : NULL);
			}
			for (i = 0x00; i < 0x3e; i ++) {
				len += spdk_bdev_scsi_mode_sense_page(
					       bdev, cdb, pc, i, 0xff,
					       &cp[len], alloc_len);
					       cp ? &cp[len] : NULL);
			}
			break;
		default:
@@ -1065,124 +1060,75 @@ spdk_bdev_scsi_mode_sense_page(struct spdk_bdev *bdev,
}

static int
spdk_bdev_scsi_mode_sense6(struct spdk_bdev *bdev,
			   uint8_t *cdb, int dbd, int pc, int page,
			   int subpage, uint8_t *data, int alloc_len)
spdk_bdev_scsi_mode_sense(struct spdk_bdev *bdev, int md,
			  uint8_t *cdb, int dbd, int llbaa, int pc,
			  int page, int subpage, uint8_t *data)
{
	uint8_t *cp;
	int hlen, len = 0, plen;
	int total;
	int llbaa = 0;

	data[0] = 0;                    /* Mode Data Length */
	data[1] = 0;                    /* Medium Type */
	data[2] = 0;                    /* Device-Specific Parameter */
	data[3] = 0;                    /* Block Descripter Length */
	hlen = 4;
	uint8_t *hdr, *bdesc, *pages;
	int hlen;
	int blen;
	int plen, total;

	cp = &data[4];
	if (dbd) {                      /* Disable Block Descripters */
		len = 0;
	} else {
		if (llbaa) {
			/* Number of Blocks */
			to_be64(cp, bdev->blockcnt);
			/* Reserved */
			memset(&cp[8], 0, 4);
			/* Block Length */
			to_be32(&cp[12], bdev->blocklen);
			len = 16;
		} else {
			/* Number of Blocks */
			if (bdev->blockcnt > 0xffffffffULL)
				memset(cp, 0xff, 4);
			else
				to_be32(cp, bdev->blockcnt);
	assert(md == 6 || md == 10);

			/* Block Length */
			to_be32(&cp[4], bdev->blocklen);
			len = 8;
	if (md == 6) {
		hlen = 4;
		blen = 8; /* For MODE SENSE 6 only short LBA */
	} else {
		hlen = 8;
		blen = llbaa ? 16 : 8;
	}

		cp += len;
	if (dbd) {
		blen = 0;
	}

	data[3] = len;                  /* Block Descripter Length */

	pages = data ? &data[hlen + blen] : NULL;
	plen = spdk_bdev_scsi_mode_sense_page(bdev, cdb, pc, page,
					      subpage, &cp[0], alloc_len);
					      subpage,
					      pages);
	if (plen < 0) {
		return -1;
	}

	total = hlen + len + plen;
	data[0] = total - 1;            /* Mode Data Length */

	total = hlen + blen + plen;
	if (data == NULL)
		return total;
}

static int
spdk_bdev_scsi_mode_sense10(struct spdk_bdev *bdev,
			    uint8_t *cdb, int dbd, int llbaa, int pc,
			    int page, int subpage, uint8_t *data,
			    int alloc_len)
{
	uint8_t *cp;
	int hlen, len = 0, plen;
	int total;

	/* Mode Data Length */
	/* Medium Type */
	/* Device-Specific Parameter */
	memset(data, 0, 4);

	if (llbaa) {
		data[4] = 0x1; /* Long LBA */
	hdr = &data[0];
	if (hlen == 4) {
		hdr[0] = total - 1;            /* Mode Data Length */
		hdr[1] = 0;                    /* Medium Type */
		hdr[2] = 0;                    /* Device-Specific Parameter */
		hdr[3] = blen;                 /* Block Descripter Length */
	} else {
		data[4] = 0; /* Short LBA */
		to_be16(&hdr[0], total - 2);   /* Mode Data Length */
		hdr[2] = 0;                    /* Medium Type */
		hdr[3] = 0;                    /* Device-Specific Parameter */
		hdr[4] = llbaa ? 0x1 : 0;      /* Long/short LBA */
		hdr[5] = 0;                    /* Reserved */
		to_be16(&hdr[6], blen);        /* Block Descripter Length */
	}

	/* Reserved */
	/* Block Descripter Length */
	memset(&data[5], 0, 3);
	hlen = 8;

	cp = &data[8];
	if (dbd) { /* Disable Block Descripters */
		len = 0;
	} else {
		if (llbaa) {
	bdesc = &data[hlen];
	if (blen == 16) {
		/* Number of Blocks */
			to_be64(cp, bdev->blockcnt);
		to_be64(&bdesc[0], bdev->blockcnt);
		/* Reserved */
			memset(&cp[8], 0, 4);
		memset(&bdesc[8], 0, 4);
		/* Block Length */
			to_be32(&cp[12], bdev->blocklen);
			len = 16;
		} else {
		to_be32(&bdesc[12], bdev->blocklen);
	} else if (blen == 8) {
		/* Number of Blocks */
		if (bdev->blockcnt > 0xffffffffULL)
				memset(cp, 0xff, 4);
			memset(&bdesc[0], 0xff, 4);
		else
				to_be32(cp, bdev->blockcnt);
			to_be32(&bdesc[0], bdev->blockcnt);

		/* Block Length */
			to_be32(&cp[4], bdev->blocklen);
			len = 8;
		}
		cp += len;
		to_be32(&bdesc[4], bdev->blocklen);
	}

	to_be16(&data[6], len);	/* Block Descripter Length */

	plen = spdk_bdev_scsi_mode_sense_page(bdev, cdb, pc, page,
					      subpage, &cp[0], alloc_len);
	if (plen < 0)
		return -1;

	total = hlen + len + plen;
	to_be16(data, total - 2);	/* Mode Data Length */

	return total;
}

@@ -1657,7 +1603,7 @@ static int
spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
			       struct spdk_scsi_task *task)
{
	uint32_t alloc_len;
	int alloc_len;
	int data_len;
	uint8_t *cdb = task->cdb;
	uint8_t *data;
@@ -1793,24 +1739,11 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
		page = cdb[2] & 0x3f;
		subpage = cdb[3];

		data = spdk_scsi_task_alloc_data(task, alloc_len);

		if (md == 6) {
			data_len = spdk_bdev_scsi_mode_sense6(bdev,
							      cdb, dbd, pc,
		/* First call with no buffer to discover needed buffer size */
		data_len = spdk_bdev_scsi_mode_sense(bdev, md,
						     cdb, dbd, llba, pc,
						     page, subpage,
							      data,
							      alloc_len);
		} else {
			data_len = spdk_bdev_scsi_mode_sense10(bdev,
							       cdb, dbd,
							       llba, pc,
							       page,
							       subpage,
							       data,
							       alloc_len);
		}

						     NULL);
		if (data_len < 0) {
			/* INVALID FIELD IN CDB */
			spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
@@ -1820,6 +1753,26 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
			break;
		}

		if (alloc_len > data_len)
			alloc_len = data_len;

		if (alloc_len) {
			uint8_t *buffer;

			data = spdk_scsi_task_alloc_data(task, alloc_len);
			buffer = alloc_len < data_len ? spdk_zmalloc(data_len, 0, NULL) : data;

			data_len = spdk_bdev_scsi_mode_sense(bdev, md,
							     cdb, dbd, llba, pc,
							     page, subpage,
							     buffer);
			assert(data_len >= 0);
			if (buffer != data) {
				memcpy(data, buffer, alloc_len);
				spdk_free(buffer);
			}
		}

		task->data_transferred = (uint64_t)data_len;
		task->status = SPDK_SCSI_STATUS_GOOD;
		break;
+14 −0
Original line number Diff line number Diff line
@@ -43,6 +43,20 @@ SPDK_LOG_REGISTER_TRACE_FLAG("scsi", SPDK_TRACE_SCSI)

struct spdk_scsi_globals g_spdk_scsi;

void *
spdk_zmalloc(size_t size, size_t align, uint64_t *phys_addr)
{
	void *buf = calloc(size, 1);
	if (phys_addr)
		*phys_addr = (uint64_t)buf;
	return buf;
}

void
spdk_free(void *buf)
{
	free(buf);
}
void
spdk_scsi_lun_clear_all(struct spdk_scsi_lun *lun)
{