Fixed processing of REQUEST SENSE and INQUIRY commands for not existing LUNs
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Wed, 13 Jan 2010 18:10:10 +0000 (18:10 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Wed, 13 Jan 2010 18:10:10 +0000 (18:10 +0000)
git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@1462 d57e44dd-8a1f-0410-8b47-8ef2f437770f

iscsi-scst/kernel/iscsi.c
scst/src/scst_lib.c

index 3a265cc..33d8a0f 100644 (file)
@@ -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
index 3fdcb9c..c3abaed 100644 (file)
@@ -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;