From 0244b5d78d698a9e5737a629e51f79ec361d41a0 Mon Sep 17 00:00:00 2001 From: Pawel Wodkowski Date: Thu, 20 Oct 2016 18:20:22 +0200 Subject: [PATCH] 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 --- lib/scsi/scsi_bdev.c | 227 ++++++++++--------------- test/lib/scsi/scsi_bdev/scsi_bdev_ut.c | 14 ++ 2 files changed, 104 insertions(+), 137 deletions(-) diff --git a/lib/scsi/scsi_bdev.c b/lib/scsi/scsi_bdev.c index 4841c20c7..3e923b445 100644 --- a/lib/scsi/scsi_bdev.c +++ b/lib/scsi/scsi_bdev.c @@ -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; diff --git a/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c b/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c index 439a48bc1..218d305ff 100644 --- a/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c +++ b/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c @@ -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) {