From eada62f32904ccc92e4a131abcbd7618c655b9d0 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Wed, 13 Jan 2010 18:10:10 +0000 Subject: [PATCH] Fixed processing of REQUEST SENSE and INQUIRY commands for not existing LUNs git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1462 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/iscsi.c | 4 -- scst/src/scst_lib.c | 146 +++++++++++++++++++++++++++++++++++--- 2 files changed, 137 insertions(+), 13 deletions(-) diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index 3a265cc26..33d8a0f70 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -207,7 +207,6 @@ unlock_cont: req_cmnd_release(cmnd); goto out; } - EXTRACHECKS_BUG_ON(scst_cmd_get_status(cmnd->scst_cmd) == 0); status = SCST_PREPROCESS_STATUS_ERROR_SENSE_SET; } else @@ -3080,9 +3079,6 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd) TRACE_DBG("Prelim completed req %p", req); - /* To make sure we didn't miss anything above */ - sBUG_ON(status == 0); - /* * We could preliminary have finished req before we * knew its device, so check if we return correct sense diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 3fdcb9c83..c3abaedd8 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -665,12 +665,130 @@ out: } EXPORT_SYMBOL(scst_set_cmd_error_status); +static int scst_set_lun_not_supported_request_sense(struct scst_cmd *cmd, + int key, int asc, int ascq) +{ + int res; + int sense_len; + + TRACE_ENTRY(); + + if (cmd->status != 0) { + TRACE_MGMT_DBG("cmd %p already has status %x set", cmd, + cmd->status); + res = -EEXIST; + goto out; + } + + if ((cmd->sg != NULL) && SCST_SENSE_VALID(sg_virt(cmd->sg))) { + TRACE_MGMT_DBG("cmd %p already has sense set", cmd); + res = -EEXIST; + goto out; + } + + if (cmd->sg == NULL) { + if (cmd->bufflen == 0) + cmd->bufflen = cmd->cdb[4]; + + cmd->sg = scst_alloc(cmd->bufflen, GFP_ATOMIC, &cmd->sg_cnt); + if (cmd->sg == NULL) { + PRINT_CRIT_ERROR("Unable to alloc sg" + "(sense %x/%x/%x)", key, asc, ascq); + res = 1; + goto out; + } + } + + TRACE_MEM("sg %p alloced for sense for cmd %p (cnt %d, " + "len %d)", cmd->sg, cmd, cmd->sg_cnt, cmd->bufflen); + + sense_len = scst_set_sense(sg_virt(cmd->sg), + cmd->bufflen, cmd->cdb[1] & 1, key, asc, ascq); + scst_set_resp_data_len(cmd, sense_len); + + TRACE_BUFFER("Sense set", sg_virt(cmd->sg), sense_len); + + res = 0; + cmd->completed = 1; + +out: + TRACE_EXIT_RES(res); + return res; +} + +static int scst_set_lun_not_supported_inquiry(struct scst_cmd *cmd) +{ + int res; + uint8_t *buf; + int len; + + TRACE_ENTRY(); + + if (cmd->status != 0) { + TRACE_MGMT_DBG("cmd %p already has status %x set", cmd, + cmd->status); + res = -EEXIST; + goto out; + } + + if (cmd->sg == NULL) { + if (cmd->bufflen == 0) + cmd->bufflen = min_t(int, 36, (cmd->cdb[3] << 8) | cmd->cdb[4]); + + cmd->sg = scst_alloc(cmd->bufflen, GFP_ATOMIC, &cmd->sg_cnt); + if (cmd->sg == NULL) { + PRINT_CRIT_ERROR("%s", "Unable to alloc sg for INQUIRY " + "for not supported LUN"); + res = 1; + goto out; + } + } + + TRACE_MEM("sg %p alloced INQUIRY for cmd %p (cnt %d, len %d)", + cmd->sg, cmd, cmd->sg_cnt, cmd->bufflen); + + buf = sg_virt(cmd->sg); + len = min_t(int, 36, cmd->bufflen); + + memset(buf, 0, len); + buf[0] = 0x7F; /* Peripheral qualifier 011b, Peripheral device type 1Fh */ + + TRACE_BUFFER("INQUIRY for not supported LUN set", buf, len); + + res = 0; + cmd->completed = 1; + +out: + TRACE_EXIT_RES(res); + return res; +} + int scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq) { int res; TRACE_ENTRY(); + /* + * We need for LOGICAL UNIT NOT SUPPORTED special handling for + * REQUEST SENSE and INQUIRY. + */ + if ((key == ILLEGAL_REQUEST) && (asc == 0x25) && (ascq == 0)) { + if (cmd->cdb[0] == REQUEST_SENSE) + res = scst_set_lun_not_supported_request_sense(cmd, + key, asc, ascq); + else if (cmd->cdb[0] == INQUIRY) + res = scst_set_lun_not_supported_inquiry(cmd); + else + goto do_sense; + + if (res > 0) + goto do_sense; + else + goto out; + } + +do_sense: res = scst_set_cmd_error_status(cmd, SAM_STAT_CHECK_CONDITION); if (res != 0) goto out; @@ -3465,21 +3583,22 @@ static void scst_release_space(struct scst_cmd *cmd) { TRACE_ENTRY(); - if (cmd->sgv == NULL) - goto out; + if (cmd->sgv == NULL) { + if ((cmd->sg != NULL) && + !(cmd->tgt_data_buf_alloced || cmd->dh_data_buf_alloced)) { + TRACE_MEM("Freeing sg %p for cmd %p (cnt %d)", cmd->sg, + cmd, cmd->sg_cnt); + scst_free(cmd->sg, cmd->sg_cnt); + goto out_zero; + } else + goto out; + } if (cmd->tgt_data_buf_alloced || cmd->dh_data_buf_alloced) { TRACE_MEM("%s", "*data_buf_alloced set, returning"); goto out; } - sgv_pool_free(cmd->sgv, &cmd->dev->dev_mem_lim); - cmd->sgv = NULL; - cmd->sg_cnt = 0; - cmd->sg = NULL; - cmd->bufflen = 0; - cmd->data_len = 0; - if (cmd->in_sgv != NULL) { sgv_pool_free(cmd->in_sgv, &cmd->dev->dev_mem_lim); cmd->in_sgv = NULL; @@ -3488,6 +3607,15 @@ static void scst_release_space(struct scst_cmd *cmd) cmd->in_bufflen = 0; } + sgv_pool_free(cmd->sgv, &cmd->dev->dev_mem_lim); + +out_zero: + cmd->sgv = NULL; + cmd->sg_cnt = 0; + cmd->sg = NULL; + cmd->bufflen = 0; + cmd->data_len = 0; + out: TRACE_EXIT(); return;