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: Pawel Wodkowski <pawelx.wodkowski@intel.com>
This commit is contained in:
parent
f30f0c76f1
commit
0244b5d78d
@ -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,18 +877,12 @@ 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 */
|
||||
cp[2] |= 0x1;
|
||||
if (cp)
|
||||
cp[2] |= 0x1;
|
||||
|
||||
len += plen;
|
||||
break;
|
||||
@ -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;
|
||||
uint8_t *hdr, *bdesc, *pages;
|
||||
int hlen;
|
||||
int blen;
|
||||
int plen, total;
|
||||
|
||||
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;
|
||||
assert(md == 6 || md == 10);
|
||||
|
||||
cp = &data[4];
|
||||
if (dbd) { /* Disable Block Descripters */
|
||||
len = 0;
|
||||
if (md == 6) {
|
||||
hlen = 4;
|
||||
blen = 8; /* For MODE SENSE 6 only short LBA */
|
||||
} 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);
|
||||
|
||||
/* Block Length */
|
||||
to_be32(&cp[4], bdev->blocklen);
|
||||
len = 8;
|
||||
}
|
||||
|
||||
cp += len;
|
||||
hlen = 8;
|
||||
blen = llbaa ? 16 : 8;
|
||||
}
|
||||
|
||||
data[3] = len; /* Block Descripter Length */
|
||||
if (dbd) {
|
||||
blen = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
bdesc = &data[hlen];
|
||||
if (blen == 16) {
|
||||
/* Number of Blocks */
|
||||
to_be64(&bdesc[0], bdev->blockcnt);
|
||||
/* Reserved */
|
||||
memset(&bdesc[8], 0, 4);
|
||||
/* Block Length */
|
||||
to_be32(&bdesc[12], bdev->blocklen);
|
||||
} else if (blen == 8) {
|
||||
/* Number of Blocks */
|
||||
if (bdev->blockcnt > 0xffffffffULL)
|
||||
memset(&bdesc[0], 0xff, 4);
|
||||
else
|
||||
to_be32(&bdesc[0], bdev->blockcnt);
|
||||
|
||||
cp = &data[8];
|
||||
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);
|
||||
|
||||
/* Block Length */
|
||||
to_be32(&cp[4], bdev->blocklen);
|
||||
len = 8;
|
||||
}
|
||||
cp += len;
|
||||
/* Block Length */
|
||||
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,
|
||||
page, subpage,
|
||||
data,
|
||||
alloc_len);
|
||||
} else {
|
||||
data_len = spdk_bdev_scsi_mode_sense10(bdev,
|
||||
cdb, dbd,
|
||||
llba, pc,
|
||||
page,
|
||||
subpage,
|
||||
data,
|
||||
alloc_len);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user