From d71a9d4f952b0f59088c296c53652ea6ac7f69fc Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 20 Apr 2012 17:57:40 +1000 Subject: [PATCH] Add support for BLOCK LIMITS VPD page Signed-off-by: Ronnie Sahlberg --- include/scsi-lowlevel.h | 20 ++++++++++++++++++++ lib/scsi-lowlevel.c | 39 +++++++++++++++++++++++++++++++++------ src/iscsi-inq.c | 19 +++++++++++++++++++ 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index 31970be..d1bfb62 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -293,6 +293,7 @@ enum scsi_inquiry_pagecode { SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES = 0x00, SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER = 0x80, SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION = 0x83, + SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS = 0xB0, SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS = 0xB1, SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING = 0xB2 }; @@ -308,6 +309,25 @@ struct scsi_inquiry_supported_pages { unsigned char *pages; }; +struct scsi_inquiry_block_limits { + enum scsi_inquiry_peripheral_qualifier periperal_qualifier; + enum scsi_inquiry_peripheral_device_type periperal_device_type; + enum scsi_inquiry_pagecode pagecode; + + int wsnz; /* write same no zero */ + uint8_t max_cmp; /* maximum_compare_and_write_length */ + uint16_t opt_gran; /* optimal_transfer_length_granularity */ + uint32_t max_xfer_len; /* maximum_transfer_length */ + uint32_t opt_xfer_len; /* optimal_transfer_length */ + uint32_t max_prefetch; /* maximum_prefetched_xdread_xdwrite_transfer_length */ + uint32_t max_unmap; /* maximum_unmap_lba_count */ + uint32_t max_unmap_bdc; /* maximum_unmap_block_descriptor_count */ + uint32_t opt_unmap_gran; /* optimal_unmap_granularity */ + int ugavalid; + uint32_t unmap_gran_align; /* unmap_granularity_alignment */ + uint64_t max_ws_len; /* maximum_write_same_length */ +}; + struct scsi_inquiry_block_device_characteristics { enum scsi_inquiry_peripheral_qualifier periperal_qualifier; enum scsi_inquiry_peripheral_device_type periperal_device_type; diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index 7d46a98..b2eb435 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -371,13 +371,13 @@ scsi_inquiry_datain_getfullsize(struct scsi_task *task) switch (task->params.inquiry.page_code) { case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES: - return task->datain.data[3] + 4; + case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS: case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER: return task->datain.data[3] + 4; case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION: - return ntohs(*(uint16_t *)&task->datain.data[2]) + 4; - case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS: - return task->datain.data[3] + 4; + case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS: + case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING: + return ntohs(*(uint16_t *)&task->datain.data[2]) + 4; default: return -1; } @@ -522,6 +522,34 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task) dptr += dev->designator_length + 4; } + return inq; + } else if (task->params.inquiry.page_code + == SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS) { + struct scsi_inquiry_block_limits *inq; + + inq = scsi_malloc(task, + sizeof(struct scsi_inquiry_block_limits)); + if (inq == NULL) { + return NULL; + } + inq->periperal_qualifier = (task->datain.data[0]>>5)&0x07; + inq->periperal_device_type = task->datain.data[0]&0x1f; + inq->pagecode = task->datain.data[1]; + + inq->wsnz = task->datain.data[4] & 0x01; + inq->max_cmp = task->datain.data[5]; + inq->opt_gran = ntohs(*(uint16_t *)&task->datain.data[6]); + inq->max_xfer_len = ntohl(*(uint32_t *)&task->datain.data[8]); + inq->opt_xfer_len = ntohl(*(uint32_t *)&task->datain.data[12]); + inq->max_prefetch = ntohl(*(uint32_t *)&task->datain.data[16]); + inq->max_unmap = ntohl(*(uint32_t *)&task->datain.data[20]); + inq->max_unmap_bdc = ntohl(*(uint32_t *)&task->datain.data[24]); + inq->opt_unmap_gran = ntohl(*(uint32_t *)&task->datain.data[28]); + inq->ugavalid = !!(task->datain.data[32]&0x80); + inq->unmap_gran_align = ntohl(*(uint32_t *)&task->datain.data[32]) & 0x7fffffff; + inq->max_ws_len = ntohl(*(uint32_t *)&task->datain.data[36]); + inq->max_ws_len = (inq->max_ws_len << 32) | ntohl(*(uint32_t *)&task->datain.data[40]); + return inq; } else if (task->params.inquiry.page_code == SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS) { @@ -536,8 +564,7 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task) inq->periperal_device_type = task->datain.data[0]&0x1f; inq->pagecode = task->datain.data[1]; - inq->medium_rotation_rate = ntohs(*(uint16_t *) - &task->datain.data[4]); + inq->medium_rotation_rate = ntohs(*(uint16_t *)&task->datain.data[4]); return inq; } else if (task->params.inquiry.page_code == SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING) { diff --git a/src/iscsi-inq.c b/src/iscsi-inq.c index 9b123f9..5daba98 100644 --- a/src/iscsi-inq.c +++ b/src/iscsi-inq.c @@ -27,6 +27,22 @@ const char *initiator = "iqn.2010-11.ronnie:iscsi-inq"; +void inquiry_block_limits(struct scsi_inquiry_block_limits *inq) +{ + printf("wsnz:%d\n", inq->wsnz); + printf("maximum compare and write length:%d\n", inq->max_cmp); + printf("optimal transfer length granularity:%d\n", inq->opt_gran); + printf("maximum transfer length:%d\n", inq->max_xfer_len); + printf("optimal transfer length:%d\n",inq->opt_xfer_len); + printf("maximum prefetch xdread xdwrite transfer length:%d\n", inq->max_prefetch); + printf("maximum unmap lba count:%d\n", inq->max_unmap); + printf("maximum unmap block descriptor count:%d\n", inq->max_unmap_bdc); + printf("optimal unmap granularity:%d\n", inq->opt_unmap_gran); + printf("ugavalid:%d\n", inq->ugavalid); + printf("unmap granularity alignment:%d\n", inq->unmap_gran_align); + printf("maximum write same length:%d\n", (int)inq->max_ws_len); +} + void inquiry_logical_block_provisioning(struct scsi_inquiry_logical_block_provisioning *inq) { printf("Threshold Exponent:%d\n", inq->threshold_exponent); @@ -151,6 +167,9 @@ void do_inquiry(struct iscsi_context *iscsi, int lun, int evpd, int pc) case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION: inquiry_device_identification(inq); break; + case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS: + inquiry_block_limits(inq); + break; case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS: inquiry_block_device_characteristics(inq); break;