scsi-lowlevel: remove scsi_inquiry_params and refactor INQUIRY data-in unmarshalling

Split the INQUIRY data-in unmarshalling into smaller chunks, fixing some
potential memory leaks along the way.

Signed-off-by: Arne Redlich <arne.redlich@googlemail.com>
This commit is contained in:
Arne Redlich
2012-11-18 22:46:04 +01:00
parent b5a9ba6159
commit 5f414317dc
2 changed files with 250 additions and 212 deletions

View File

@@ -176,10 +176,6 @@ struct scsi_readtoc_list {
struct scsi_readtoc_desc desc[0]; struct scsi_readtoc_desc desc[0];
}; };
struct scsi_inquiry_params {
int evpd;
int page_code;
};
struct scsi_modesense6_params { struct scsi_modesense6_params {
int dbd; int dbd;
int pc; int pc;
@@ -232,7 +228,6 @@ struct scsi_task {
int expxferlen; int expxferlen;
unsigned char cdb[SCSI_CDB_MAX_SIZE]; unsigned char cdb[SCSI_CDB_MAX_SIZE];
union { union {
struct scsi_inquiry_params inquiry;
struct scsi_modesense6_params modesense6; struct scsi_modesense6_params modesense6;
struct scsi_serviceactionin_params serviceactionin; struct scsi_serviceactionin_params serviceactionin;
struct scsi_readtoc_params readtoc; struct scsi_readtoc_params readtoc;

View File

@@ -728,12 +728,21 @@ scsi_cdb_inquiry(int evpd, int page_code, int alloc_len)
} }
task->expxferlen = alloc_len; task->expxferlen = alloc_len;
task->params.inquiry.evpd = evpd;
task->params.inquiry.page_code = page_code;
return task; return task;
} }
static inline int
scsi_inquiry_evpd_set(const struct scsi_task *task)
{
return task->cdb[1] & 0x1;
}
static inline uint8_t
scsi_inquiry_page_code(const struct scsi_task *task)
{
return task->cdb[2];
}
/* /*
* parse the data in blob and calculate the size of a full * parse the data in blob and calculate the size of a full
* inquiry datain structure * inquiry datain structure
@@ -741,11 +750,11 @@ scsi_cdb_inquiry(int evpd, int page_code, int alloc_len)
static int static int
scsi_inquiry_datain_getfullsize(struct scsi_task *task) scsi_inquiry_datain_getfullsize(struct scsi_task *task)
{ {
if (task->params.inquiry.evpd == 0) { if (scsi_inquiry_evpd_set(task) == 0) {
return task->datain.data[4] + 5; return task->datain.data[4] + 5;
} }
switch (task->params.inquiry.page_code) { switch (scsi_inquiry_page_code(task)) {
case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES: case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES:
case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS: case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS:
case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER: case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER:
@@ -759,17 +768,10 @@ scsi_inquiry_datain_getfullsize(struct scsi_task *task)
} }
} }
/* static struct scsi_inquiry_standard *
* unmarshall the data in blob for inquiry into a structure scsi_inquiry_unmarshall_standard(struct scsi_task *task)
*/
static void *
scsi_inquiry_datain_unmarshall(struct scsi_task *task)
{ {
if (task->params.inquiry.evpd == 0) { struct scsi_inquiry_standard *inq = scsi_malloc(task, sizeof(*inq));
struct scsi_inquiry_standard *inq;
/* standard inquiry */
inq = scsi_malloc(task, sizeof(struct scsi_inquiry_standard));
if (inq == NULL) { if (inq == NULL) {
return NULL; return NULL;
} }
@@ -809,14 +811,13 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task)
inq->ius = !!(task->datain.data[56]&0x01); inq->ius = !!(task->datain.data[56]&0x01);
return inq; return inq;
} }
if (task->params.inquiry.page_code static struct scsi_inquiry_supported_pages *
== SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES) { scsi_inquiry_unmarshall_supported_pages(struct scsi_task *task)
struct scsi_inquiry_supported_pages *inq; {
struct scsi_inquiry_supported_pages *inq = scsi_malloc(task,
inq = scsi_malloc(task, sizeof(*inq));
sizeof(struct scsi_inquiry_supported_pages));
if (inq == NULL) { if (inq == NULL) {
return NULL; return NULL;
} }
@@ -827,16 +828,18 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task)
inq->num_pages = task->datain.data[3]; inq->num_pages = task->datain.data[3];
inq->pages = scsi_malloc(task, inq->num_pages); inq->pages = scsi_malloc(task, inq->num_pages);
if (inq->pages == NULL) { if (inq->pages == NULL) {
free (inq);
return NULL; return NULL;
} }
memcpy(inq->pages, &task->datain.data[4], inq->num_pages); memcpy(inq->pages, &task->datain.data[4], inq->num_pages);
return inq; return inq;
} else if (task->params.inquiry.page_code }
== SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER) {
struct scsi_inquiry_unit_serial_number *inq;
inq = scsi_malloc(task, static struct scsi_inquiry_unit_serial_number *
sizeof(struct scsi_inquiry_unit_serial_number)); scsi_inquiry_unmarshall_unit_serial_number(struct scsi_task* task)
{
struct scsi_inquiry_unit_serial_number *inq = scsi_malloc(task,
sizeof(*inq));
if (inq == NULL) { if (inq == NULL) {
return NULL; return NULL;
} }
@@ -846,19 +849,22 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task)
inq->usn = scsi_malloc(task, task->datain.data[3]+1); inq->usn = scsi_malloc(task, task->datain.data[3]+1);
if (inq->usn == NULL) { if (inq->usn == NULL) {
free(inq);
return NULL; return NULL;
} }
memcpy(inq->usn, &task->datain.data[4], task->datain.data[3]); memcpy(inq->usn, &task->datain.data[4], task->datain.data[3]);
inq->usn[task->datain.data[3]] = 0; inq->usn[task->datain.data[3]] = 0;
return inq; return inq;
} else if (task->params.inquiry.page_code }
== SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION) {
struct scsi_inquiry_device_identification *inq; static struct scsi_inquiry_device_identification *
scsi_inquiry_unmarshall_device_identification(struct scsi_task *task)
{
struct scsi_inquiry_device_identification *inq = scsi_malloc(task,
sizeof(*inq));
int remaining = ntohs(*(uint16_t *)&task->datain.data[2]); int remaining = ntohs(*(uint16_t *)&task->datain.data[2]);
unsigned char *dptr; unsigned char *dptr;
inq = scsi_malloc(task,
sizeof(struct scsi_inquiry_device_identification));
if (inq == NULL) { if (inq == NULL) {
return NULL; return NULL;
} }
@@ -868,12 +874,10 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task)
dptr = &task->datain.data[4]; dptr = &task->datain.data[4];
while (remaining > 0) { while (remaining > 0) {
struct scsi_inquiry_device_designator *dev; struct scsi_inquiry_device_designator *dev =
scsi_malloc(task, sizeof(*dev));
dev = scsi_malloc(task,
sizeof(struct scsi_inquiry_device_designator));
if (dev == NULL) { if (dev == NULL) {
return NULL; goto err;
} }
dev->next = inq->designators; dev->next = inq->designators;
@@ -886,10 +890,9 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task)
dev->designator_type = dptr[1]&0x0f; dev->designator_type = dptr[1]&0x0f;
dev->designator_length = dptr[3]; dev->designator_length = dptr[3];
dev->designator = scsi_malloc(task, dev->designator = scsi_malloc(task, dev->designator_length + 1);
dev->designator_length+1);
if (dev->designator == NULL) { if (dev->designator == NULL) {
return NULL; goto err;
} }
dev->designator[dev->designator_length] = 0; dev->designator[dev->designator_length] = 0;
memcpy(dev->designator, &dptr[4], memcpy(dev->designator, &dptr[4],
@@ -901,12 +904,24 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task)
dptr += dev->designator_length + 4; dptr += dev->designator_length + 4;
} }
return inq; return inq;
} else if (task->params.inquiry.page_code
== SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS) {
struct scsi_inquiry_block_limits *inq;
inq = scsi_malloc(task, err:
sizeof(struct scsi_inquiry_block_limits)); while (inq->designators) {
struct scsi_inquiry_device_designator *dev = inq->designators;
inq->designators = dev->next;
free(dev->designator);
free(dev);
}
free(inq);
return NULL;
}
static struct scsi_inquiry_block_limits *
scsi_inquiry_unmarshall_block_limits(struct scsi_task *task)
{
struct scsi_inquiry_block_limits *inq = scsi_malloc(task,
sizeof(*inq));
if (inq == NULL) { if (inq == NULL) {
return NULL; return NULL;
} }
@@ -929,12 +944,13 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task)
inq->max_ws_len = (inq->max_ws_len << 32) | ntohl(*(uint32_t *)&task->datain.data[40]); inq->max_ws_len = (inq->max_ws_len << 32) | ntohl(*(uint32_t *)&task->datain.data[40]);
return inq; return inq;
} else if (task->params.inquiry.page_code }
== SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS) {
struct scsi_inquiry_block_device_characteristics *inq;
inq = scsi_malloc(task, static struct scsi_inquiry_block_device_characteristics *
sizeof(struct scsi_inquiry_block_device_characteristics)); scsi_inquiry_unmarshall_block_device_characteristics(struct scsi_task *task)
{
struct scsi_inquiry_block_device_characteristics *inq =
scsi_malloc(task, sizeof(*inq));
if (inq == NULL) { if (inq == NULL) {
return NULL; return NULL;
} }
@@ -944,12 +960,13 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task)
inq->medium_rotation_rate = ntohs(*(uint16_t *)&task->datain.data[4]); inq->medium_rotation_rate = ntohs(*(uint16_t *)&task->datain.data[4]);
return inq; return inq;
} else if (task->params.inquiry.page_code }
== SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING) {
struct scsi_inquiry_logical_block_provisioning *inq;
inq = scsi_malloc(task, struct scsi_inquiry_logical_block_provisioning *
sizeof(struct scsi_inquiry_logical_block_provisioning)); scsi_inquiry_unmarshall_logical_block_provisioning(struct scsi_task *task)
{
struct scsi_inquiry_logical_block_provisioning *inq =
scsi_malloc(task, sizeof(*inq));
if (inq == NULL) { if (inq == NULL) {
return NULL; return NULL;
} }
@@ -967,9 +984,35 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task)
inq->provisioning_type = task->datain.data[6] & 0x07; inq->provisioning_type = task->datain.data[6] & 0x07;
return inq; return inq;
}
/*
* unmarshall the data in blob for inquiry into a structure
*/
static void *
scsi_inquiry_datain_unmarshall(struct scsi_task *task)
{
if (scsi_inquiry_evpd_set(task) == 0) {
return scsi_inquiry_unmarshall_standard(task);
} }
switch (scsi_inquiry_page_code(task))
{
case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES:
return scsi_inquiry_unmarshall_supported_pages(task);
case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER:
return scsi_inquiry_unmarshall_unit_serial_number(task);
case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION:
return scsi_inquiry_unmarshall_device_identification(task);
case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS:
return scsi_inquiry_unmarshall_block_limits(task);
case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS:
return scsi_inquiry_unmarshall_block_device_characteristics(task);
case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING:
return scsi_inquiry_unmarshall_logical_block_provisioning(task);
default:
return NULL; return NULL;
}
} }
/* /*