From e0e00e0e8e694c9775a0376f17e8d242203d5edc Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Thu, 30 Nov 2006 16:24:09 +0000 Subject: [PATCH] A bunch of small fixes and cleanups before 0.9.5 git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@36 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/ChangeLog | 2 + scst/README | 8 +- scst/src/dev_handlers/scst_fileio.c | 9 +- scst/src/scst_lib.c | 124 +++++++++++- scst/src/scst_priv.h | 6 + scst/src/scst_proc.c | 108 +++++------ scst/src/scst_targ.c | 291 ++++++++-------------------- 7 files changed, 275 insertions(+), 273 deletions(-) diff --git a/scst/ChangeLog b/scst/ChangeLog index f16bb389c..4b3d60a47 100644 --- a/scst/ChangeLog +++ b/scst/ChangeLog @@ -10,6 +10,8 @@ Summary of changes between versions 0.9.4 and 0.9.5 kernel, but pass-through modules (scst_disk, scst_tape, etc.) are not supported). + - Fixed problems with big amount of LUNs (500+). + - Timer-based retries for targets after SCST_TGT_RES_QUEUE_FULL status implemented. diff --git a/scst/README b/scst/README index 6d52b3ec6..002947384 100644 --- a/scst/README +++ b/scst/README @@ -255,16 +255,16 @@ following files and directories under /proc/scsi_tgt: - "del_group GROUP" to /proc/scsi_tgt/scsi_tgt deletes group "GROUP" - - "add H:C:I:L lun [RO]" to /proc/scsi_tgt/groups/GROUP/devices adds + - "add H:C:I:L lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds device with host:channel:id:lun as LUN "lun" in group "GROUP". Optionally, the device could be marked as read only. - "del H:C:I:L" to /proc/scsi_tgt/groups/GROUP/devices deletes device with host:channel:id:lun from group "GROUP" - - "add V_NAME lun [RO]" to /proc/scsi_tgt/groups/GROUP/devices adds device with - virtual name "V_NAME" as LUN "lun" in group "GROUP". Optionally, the device - could be marked as read only. + - "add V_NAME lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds + device with virtual name "V_NAME" as LUN "lun" in group "GROUP". + Optionally, the device could be marked as read only. - "del V_NAME" to /proc/scsi_tgt/groups/GROUP/devices deletes device with virtual name "V_NAME" from group "GROUP" diff --git a/scst/src/dev_handlers/scst_fileio.c b/scst/src/dev_handlers/scst_fileio.c index e954189e5..46fcb076a 100644 --- a/scst/src/dev_handlers/scst_fileio.c +++ b/scst/src/dev_handlers/scst_fileio.c @@ -2274,13 +2274,10 @@ static int fileio_proc_update_size(int size, off_t offset, int length, if (size > 0) { p->len += size; p->pos = p->begin + p->len; - if (p->pos < offset) { + if (p->pos <= offset) { p->len = 0; p->begin = p->pos; - } - if (p->pos > offset + length) { - p->begin = p->pbegin; - p->len = p->plen; + } else if (p->pos >= offset + length) { res = 1; goto out; } else @@ -2620,7 +2617,7 @@ stop_output: pu.len -= (offset - pu.begin); if (pu.len > length) pu.len = length; - res = pu.len; + res = max(0, pu.len); goto out_up; out_free_vpath: diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 54115518c..d4b2cf5d0 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -692,6 +692,128 @@ int scst_acg_remove_name(struct scst_acg *acg, const char *name) return res; } +struct scst_cmd *scst_create_prepare_internal_cmd( + struct scst_cmd *orig_cmd, int bufsize) +{ + struct scst_cmd *res; + int gfp_mask = scst_cmd_atomic(orig_cmd) ? GFP_ATOMIC : GFP_KERNEL; + + TRACE_ENTRY(); + + res = scst_alloc_cmd(gfp_mask); + if (unlikely(res == NULL)) { + goto out; + } + + res->sess = orig_cmd->sess; + res->state = SCST_CMD_STATE_SEND_TO_MIDLEV; + res->atomic = scst_cmd_atomic(orig_cmd); + res->internal = 1; + res->tgtt = orig_cmd->tgtt; + res->tgt = orig_cmd->tgt; + res->dev = orig_cmd->dev; + res->tgt_dev = orig_cmd->tgt_dev; + res->lun = orig_cmd->lun; + res->queue_type = SCST_CMD_QUEUE_HEAD_OF_QUEUE; + res->data_direction = SCST_DATA_UNKNOWN; + res->orig_cmd = orig_cmd; + + res->bufflen = bufsize; + if (bufsize > 0) { + if (scst_alloc_space(res) != 0) + PRINT_ERROR("Unable to create buffer (size %d) for " + "internal cmd", bufsize); + goto out_free_res; + } + +out: + TRACE_EXIT_HRES((unsigned long)res); + return res; + +out_free_res: + scst_destroy_cmd(res); + res = NULL; + goto out; +} + +void scst_free_internal_cmd(struct scst_cmd *cmd) +{ + TRACE_ENTRY(); + + if (cmd->bufflen > 0) + scst_release_space(cmd); + scst_destroy_cmd(cmd); + + TRACE_EXIT(); + return; +} + +int scst_prepare_request_sense(struct scst_cmd *orig_cmd) +{ + int res = SCST_CMD_STATE_RES_RESTART; +#define sbuf_size 252 + static const unsigned char request_sense[6] = + { REQUEST_SENSE, 0, 0, 0, sbuf_size, 0 }; + struct scst_cmd *rs_cmd; + + TRACE_ENTRY(); + + rs_cmd = scst_create_prepare_internal_cmd(orig_cmd, sbuf_size); + if (rs_cmd != 0) + goto out_error; + + memcpy(rs_cmd->cdb, request_sense, sizeof(request_sense)); + rs_cmd->cdb_len = sizeof(request_sense); + rs_cmd->data_direction = SCST_DATA_READ; + + spin_lock_irq(&scst_list_lock); + list_add(&rs_cmd->cmd_list_entry, &scst_active_cmd_list); + spin_unlock_irq(&scst_list_lock); + +out: + TRACE_EXIT_RES(res); + return res; + +out_error: + res = -1; + goto out; +#undef sbuf_size +} + +struct scst_cmd *scst_complete_request_sense(struct scst_cmd *cmd) +{ + struct scst_cmd *orig_cmd = cmd->orig_cmd; + uint8_t *buf; + int len; + + TRACE_ENTRY(); + + BUG_ON(orig_cmd); + + len = scst_get_buf_first(cmd, &buf); + + if ((cmd->status == 0) && SCST_SENSE_VALID(buf) && + (!SCST_NO_SENSE(buf))) + { + TRACE_BUFF_FLAG(TRACE_SCSI, "REQUEST SENSE returned", + buf, len); + memcpy(orig_cmd->sense_buffer, buf, + (sizeof(orig_cmd->sense_buffer) > len) ? + len : sizeof(orig_cmd->sense_buffer)); + } else { + PRINT_ERROR_PR("%s", "Unable to get the sense via " + "REQUEST SENSE, returning HARDWARE ERROR"); + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + } + + scst_put_buf(cmd, buf); + + scst_free_internal_cmd(cmd); + + TRACE_EXIT_HRES((unsigned long)orig_cmd); + return orig_cmd; +} + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) static void scst_req_done(struct scsi_cmnd *scsi_cmd) { @@ -1561,7 +1683,7 @@ lun_t scst_unpack_lun(const uint8_t *lun, int len) address_method = (*lun) >> 6; /* high 2 bits of byte 0 */ switch (address_method) { case 0: /* peripheral device addressing method */ -#if 0 /* At least QLA2300 Linux ini uses it as the flat space addressing method */ +#if 0 /* Looks like it's legal to use it as flat space addressing method as well */ if (*lun) { PRINT_ERROR_PR("Illegal BUS INDENTIFIER in LUN " "peripheral device addressing method 0x%02x, " diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 6f92e99b9..62b7272d8 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -237,6 +237,12 @@ int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev); int scst_acg_add_name(struct scst_acg *acg, const char *name); int scst_acg_remove_name(struct scst_acg *acg, const char *name); +struct scst_cmd *scst_create_prepare_internal_cmd( + struct scst_cmd *orig_cmd, int bufsize); +void scst_free_internal_cmd(struct scst_cmd *cmd); +int scst_prepare_request_sense(struct scst_cmd *orig_cmd); +struct scst_cmd *scst_complete_request_sense(struct scst_cmd *cmd); + int scst_assign_dev_handler(struct scst_device *dev, struct scst_dev_type *handler); diff --git a/scst/src/scst_proc.c b/scst/src/scst_proc.c index 47667e1de..ef59e32e9 100644 --- a/scst/src/scst_proc.c +++ b/scst/src/scst_proc.c @@ -228,11 +228,10 @@ int scst_proc_read_tlb(const struct scst_proc_log *tbl, char *buffer, if (*size > 0) { *len += *size; *pos = *begin + *len; - if (*pos < offset) { + if (*pos <= offset) { *len = 0; *begin = *pos; - } - if (*pos > offset + length) + } else if (*pos >= offset + length) goto out_end; } else goto out_end; @@ -278,11 +277,10 @@ int scst_proc_log_entry_read(char *buffer, char **start, if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) + } else if (pos >= offset + length) goto stop_output; } else goto stop_output; @@ -292,7 +290,7 @@ stop_output: len -= (offset - begin); if (len > length) len = length; - res = len; + res = max(0, len); TRACE_EXIT_RES(res); return res; } @@ -739,13 +737,10 @@ static int scst_proc_update_size(int size, off_t offset, int length, if (size > 0) { p->len += size; p->pos = p->begin + p->len; - if (p->pos < offset) { + if (p->pos <= offset) { p->len = 0; p->begin = p->pos; - } - if (p->pos > offset + length) { - p->begin = p->pbegin; - p->len = p->plen; + } else if (p->pos >= offset + length) { res = 1; goto out; } else @@ -836,7 +831,7 @@ stop_output: st.len -= (offset - st.begin); if (st.len > length) st.len = length; - res = st.len; + res = max(0, st.len); TRACE_EXIT_RES(res); return res; @@ -1006,6 +1001,8 @@ static int scst_scsi_tgt_proc_info(char *buffer, char **start, TRACE_ENTRY(); +//TRACE(TRACE_SPECIAL, "offset=%ld, length=%d", offset, length); + if (down_interruptible(&scst_mutex) != 0) { res = -EINTR; goto out; @@ -1014,14 +1011,17 @@ static int scst_scsi_tgt_proc_info(char *buffer, char **start, size = scnprintf(buffer + len, length - len, "%-60s%s\n", "Device (host:ch:id:lun or name)", "Device handler"); + +//TRACE(TRACE_SPECIAL, "size=%d, pos=%ld, begin=%ld, len=%d, buf %s", +// size, pos, begin, len, buffer+len); + if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) + } else if (pos >= offset + length) goto stop_output; } else goto stop_output; @@ -1030,31 +1030,35 @@ static int scst_scsi_tgt_proc_info(char *buffer, char **start, pplen = plen = len; list_for_each_entry(dev, &scst_dev_list, dev_list_entry) { if (dev->virt_id == 0) { + char conv[12]; size = scnprintf(buffer + len, length - len, - "%d:%d:%d:%-54d%s\n", + "%d:%d:%d:", dev->scsi_dev->host->host_no, dev->scsi_dev->channel, - dev->scsi_dev->id, - dev->scsi_dev->lun, - dev->handler ? dev->handler->name : - "-"); + dev->scsi_dev->id); + sprintf(conv, "%%-%dd%%s\n", 60-size); + size += scnprintf(buffer + len + size, length - len - size, + conv, dev->scsi_dev->lun, + dev->handler ? dev->handler->name : "-"); } else { size = scnprintf(buffer + len, length - len, "%-60s%s\n", dev->virt_name, dev->handler->name); } + +//printk("size=%d, pbegin=%ld, plen=%d, ppbegin=%ld, pplen=%d, buf %s", +// size, pbegin, plen, ppbegin, pplen, buffer+len); + if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; } - if (pos > offset + length) { - begin = pbegin; - len = plen; +//TRACE(TRACE_SPECIAL, "pos=%ld, begin=%ld, len=%d", pos, begin, len); + if (pos >= offset + length) goto stop_output; - } } else { begin = ppbegin; len = pplen; @@ -1073,7 +1077,9 @@ stop_output: len -= (offset - begin); if (len > length) len = length; - res = len; + res = max(0, len); + +//TRACE(TRACE_SPECIAL, "res=%d, start=%ld, len=%d, begin=%ld, eof=%d", res, offset-begin, len, begin, *eof); up(&scst_mutex); @@ -1822,11 +1828,10 @@ static int scst_proc_groups_devices_read(char *buffer, char **start, if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) + } else if (pos >= offset + length) goto stop_output; } else goto stop_output; @@ -1835,11 +1840,15 @@ static int scst_proc_groups_devices_read(char *buffer, char **start, pplen = plen = len; list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) { if (acg_dev->dev->virt_id == 0) { + char conv[20]; size = scnprintf(buffer + len, length - len, - "%d:%d:%d:%-54d%4d%12s\n", + "%d:%d:%d:", acg_dev->dev->scsi_dev->host->host_no, acg_dev->dev->scsi_dev->channel, - acg_dev->dev->scsi_dev->id, + acg_dev->dev->scsi_dev->id); + sprintf(conv, "%%-%dd%%4d%%12s\n", 60-size); + size += scnprintf(buffer + len + size, + length - len - size, conv, acg_dev->dev->scsi_dev->lun, acg_dev->lun, acg_dev->rd_only_flag ? "RO" : ""); @@ -1852,15 +1861,11 @@ static int scst_proc_groups_devices_read(char *buffer, char **start, if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) { - begin = pbegin; - len = plen; + } else if (pos >= offset + length) goto stop_output; - } } else { begin = ppbegin; len = pplen; @@ -1879,7 +1884,7 @@ stop_output: len -= (offset - begin); if (len > length) len = length; - res = len; + res = max(0, len); up(&scst_mutex); @@ -2099,11 +2104,10 @@ static int scst_proc_sessions_read(char *buffer, char **start, if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) + } else if (pos >= offset + length) goto stop_output; } else goto stop_output; @@ -2121,15 +2125,11 @@ static int scst_proc_sessions_read(char *buffer, char **start, if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) { - begin = pbegin; - len = plen; + } else if (pos >= offset + length) goto stop_output; - } } else { begin = ppbegin; len = pplen; @@ -2149,7 +2149,7 @@ stop_output: len -= (offset - begin); if (len > length) len = length; - res = len; + res = max(0, len); up(&scst_mutex); @@ -2183,15 +2183,11 @@ static int scst_proc_groups_names_read(char *buffer, char **start, if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) { - begin = pbegin; - len = plen; + } else if (pos >= offset + length) goto stop_output; - } } else { begin = ppbegin; len = pplen; @@ -2210,7 +2206,7 @@ stop_output: len -= (offset - begin); if (len > length) len = length; - res = len; + res = max(0, len); up(&scst_mutex); diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 5cff7f2a0..6cdbff8df 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -1141,15 +1141,6 @@ static void scst_cmd_done(void *data, char *sense, int result, int resid) WARN_ON(in_irq()); - /* - * We don't use resid, because: - * 1. Many low level initiator drivers don't use (set) this field - * 2. We determine the command's buffer size directly from CDB, - * so resid is not relevant for us, and target drivers - * should know the residual, if necessary, by comparing expected - * and actual transfer sizes. - */ - cmd = (struct scst_cmd *)data; if (cmd == NULL) goto out; @@ -1180,8 +1171,8 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state) if (next_state == SCST_CMD_STATE_DEFAULT) next_state = SCST_CMD_STATE_DEV_DONE; - if (next_state == SCST_CMD_STATE_DEV_DONE) { #if defined(DEBUG) || defined(TRACING) + if (next_state == SCST_CMD_STATE_DEV_DONE) { if (cmd->sg) { int i; struct scatterlist *sg = cmd->sg; @@ -1194,8 +1185,8 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state) sg[i].length); } } -#endif } +#endif #ifdef EXTRACHECKS @@ -1244,7 +1235,7 @@ static int scst_report_luns_local(struct scst_cmd *cmd) cmd->host_status = DID_OK; cmd->driver_status = 0; - if (cmd->cdb[2] != 0) { + if ((cmd->cdb[2] != 0) && (cmd->cdb[2] != 2)) { PRINT_ERROR_PR("Unsupported SELECT REPORT value %x in REPORT " "LUNS command", cmd->cdb[2]); goto out_err; @@ -1267,7 +1258,7 @@ static int scst_report_luns_local(struct scst_cmd *cmd) if (!overflow) { if (offs >= buffer_size) { scst_put_buf(cmd, buffer); - buffer_size = scst_get_buf_first(cmd, &buffer); + buffer_size = scst_get_buf_next(cmd, &buffer); if (buffer_size > 0) { memset(buffer, 0, buffer_size); offs = 0; @@ -1284,7 +1275,7 @@ static int scst_report_luns_local(struct scst_cmd *cmd) goto out_put_hw_err; } buffer[offs] = (tgt_dev->acg_dev->lun >> 8) & 0xff; - buffer[offs + 1] = tgt_dev->acg_dev->lun & 0xff; + buffer[offs+1] = tgt_dev->acg_dev->lun & 0xff; offs += 8; } inc_dev_cnt: @@ -1490,51 +1481,53 @@ static int scst_pre_exec(struct scst_cmd *cmd) TRACE_ENTRY(); /* Reserve check before Unit Attention */ - if (unlikely(test_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags)) && - (cmd->cdb[0] != INQUIRY) && - (cmd->cdb[0] != REPORT_LUNS) && - (cmd->cdb[0] != RELEASE) && - (cmd->cdb[0] != RELEASE_10) && - (cmd->cdb[0] != REPORT_DEVICE_IDENTIFIER) && - (cmd->cdb[0] != ALLOW_MEDIUM_REMOVAL || (cmd->cdb[4] & 3)) && - (cmd->cdb[0] != LOG_SENSE) && (cmd->cdb[0] != REQUEST_SENSE)) - { - scst_report_reserved(cmd); - res = SCST_EXEC_COMPLETED; - goto out; + if (unlikely(test_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags))) { + if ((cmd->cdb[0] != INQUIRY) && (cmd->cdb[0] != REPORT_LUNS) && + (cmd->cdb[0] != RELEASE) && (cmd->cdb[0] != RELEASE_10) && + (cmd->cdb[0] != REPORT_DEVICE_IDENTIFIER) && + (cmd->cdb[0] != ALLOW_MEDIUM_REMOVAL || (cmd->cdb[4] & 3)) && + (cmd->cdb[0] != LOG_SENSE) && (cmd->cdb[0] != REQUEST_SENSE)) + { + scst_report_reserved(cmd); + res = SCST_EXEC_COMPLETED; + goto out; + } } /* If we had a internal bus reset, set the command error unit attention */ if ((cmd->dev->scsi_dev != NULL) && - unlikely(cmd->dev->scsi_dev->was_reset) && - scst_is_ua_command(cmd)) - { - struct scst_device *dev = cmd->dev; - int done = 0; - /* Prevent more than 1 cmd to be triggered by was_reset */ - spin_lock_bh(&dev->dev_lock); - barrier(); /* to reread was_reset */ - if (dev->scsi_dev->was_reset) { - TRACE(TRACE_MGMT, "was_reset is %d", 1); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_reset_UA)); - /* It looks like it is safe to clear was_reset here */ - dev->scsi_dev->was_reset = 0; - smp_mb(); - done = 1; - } - spin_unlock_bh(&dev->dev_lock); + unlikely(cmd->dev->scsi_dev->was_reset)) { + if (scst_is_ua_command(cmd)) + { + struct scst_device *dev = cmd->dev; + int done = 0; + /* Prevent more than 1 cmd to be triggered by was_reset */ + spin_lock_bh(&dev->dev_lock); + barrier(); /* to reread was_reset */ + if (dev->scsi_dev->was_reset) { + TRACE(TRACE_MGMT, "was_reset is %d", 1); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_reset_UA)); + /* It looks like it is safe to clear was_reset here */ + dev->scsi_dev->was_reset = 0; + smp_mb(); + done = 1; + } + spin_unlock_bh(&dev->dev_lock); - if (done) - goto out_done; + if (done) + goto out_done; + } } - if (test_bit(SCST_TGT_DEV_UA_PENDING, &cmd->tgt_dev->tgt_dev_flags) && - scst_is_ua_command(cmd)) - { - rc = scst_set_pending_UA(cmd); - if (rc == 0) - goto out_done; + if (unlikely(test_bit(SCST_TGT_DEV_UA_PENDING, + &cmd->tgt_dev->tgt_dev_flags))) { + if (scst_is_ua_command(cmd)) + { + rc = scst_set_pending_UA(cmd); + if (rc == 0) + goto out_done; + } } /* Check READ_ONLY device status */ @@ -1653,14 +1646,12 @@ static int scst_do_send_to_midlev(struct scst_cmd *cmd) /* !! At this point cmd, sess & tgt_dev can be already freed !! */ TRACE_DBG("Dev handler %s exec() returned %d", dev->handler->name, rc); - if (rc != SCST_EXEC_NOT_COMPLETED) { - if (rc == SCST_EXEC_COMPLETED) - goto out; - else if (rc == SCST_EXEC_NEED_THREAD) - goto out_clear; - else - goto out_rc_error; - } + if (rc == SCST_EXEC_COMPLETED) + goto out; + else if (rc == SCST_EXEC_NEED_THREAD) + goto out_clear; + else if (rc != SCST_EXEC_NOT_COMPLETED) + goto out_rc_error; } TRACE_DBG("Sending cmd %p to SCSI mid-level", cmd); @@ -1673,10 +1664,15 @@ static int scst_do_send_to_midlev(struct scst_cmd *cmd) } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) - if (scst_alloc_request(cmd) != 0) { - PRINT_INFO_PR("%s", "Unable to allocate request, " - "sending BUSY status"); - goto out_busy; + if (unlikely(scst_alloc_request(cmd) != 0)) { + if (scst_cmd_atomic(cmd)) { + rc = SCST_EXEC_NEED_THREAD; + goto out_clear; + } else { + PRINT_INFO_PR("%s", "Unable to allocate request, " + "sending BUSY status"); + goto out_busy; + } } scst_do_req(cmd->scsi_req, (void *)cmd->cdb, @@ -1687,10 +1683,15 @@ static int scst_do_send_to_midlev(struct scst_cmd *cmd) rc = scst_exec_req(cmd->dev->scsi_dev, cmd->cdb, cmd->cdb_len, cmd->data_direction, cmd->sg, cmd->bufflen, cmd->sg_cnt, cmd->timeout, cmd->retries, cmd, scst_cmd_done, - GFP_KERNEL); - if (rc) { - PRINT_INFO_PR("scst_exec_req() failed: %d", rc); - goto out_error; + scst_cmd_atomic(cmd) ? GFP_ATOMIC : GFP_KERNEL); + if (unlikely(rc != 0)) { + if (scst_cmd_atomic(cmd)) { + rc = SCST_EXEC_NEED_THREAD; + goto out_clear; + } else { + PRINT_INFO_PR("scst_exec_req() failed: %d", rc); + goto out_error; + } } #endif @@ -1838,128 +1839,6 @@ out: return res; } -static struct scst_cmd *scst_create_prepare_internal_cmd( - struct scst_cmd *orig_cmd, int bufsize) -{ - struct scst_cmd *res; - int gfp_mask = scst_cmd_atomic(orig_cmd) ? GFP_ATOMIC : GFP_KERNEL; - - TRACE_ENTRY(); - - res = scst_alloc_cmd(gfp_mask); - if (unlikely(res == NULL)) { - goto out; - } - - res->sess = orig_cmd->sess; - res->state = SCST_CMD_STATE_SEND_TO_MIDLEV; - res->atomic = scst_cmd_atomic(orig_cmd); - res->internal = 1; - res->tgtt = orig_cmd->tgtt; - res->tgt = orig_cmd->tgt; - res->dev = orig_cmd->dev; - res->tgt_dev = orig_cmd->tgt_dev; - res->lun = orig_cmd->lun; - res->queue_type = SCST_CMD_QUEUE_HEAD_OF_QUEUE; - res->data_direction = SCST_DATA_UNKNOWN; - res->orig_cmd = orig_cmd; - - res->bufflen = bufsize; - if (bufsize > 0) { - if (scst_alloc_space(res) != 0) - PRINT_ERROR("Unable to create buffer (size %d) for " - "internal cmd", bufsize); - goto out_free_res; - } - -out: - TRACE_EXIT_HRES((unsigned long)res); - return res; - -out_free_res: - scst_destroy_cmd(res); - res = NULL; - goto out; -} - -static void scst_free_internal_cmd(struct scst_cmd *cmd) -{ - TRACE_ENTRY(); - - if (cmd->bufflen > 0) - scst_release_space(cmd); - scst_destroy_cmd(cmd); - - TRACE_EXIT(); - return; -} - -static int scst_prepare_request_sense(struct scst_cmd *orig_cmd) -{ - int res = SCST_CMD_STATE_RES_RESTART; -#define sbuf_size 252 - static const unsigned char request_sense[6] = - { REQUEST_SENSE, 0, 0, 0, sbuf_size, 0 }; - struct scst_cmd *rs_cmd; - - TRACE_ENTRY(); - - rs_cmd = scst_create_prepare_internal_cmd(orig_cmd, sbuf_size); - if (rs_cmd != 0) - goto out_error; - - memcpy(rs_cmd->cdb, request_sense, sizeof(request_sense)); - rs_cmd->cdb_len = sizeof(request_sense); - rs_cmd->data_direction = SCST_DATA_READ; - - spin_lock_irq(&scst_list_lock); - list_add(&rs_cmd->cmd_list_entry, &scst_active_cmd_list); - spin_unlock_irq(&scst_list_lock); - -out: - TRACE_EXIT_RES(res); - return res; - -out_error: - res = -1; - goto out; -#undef sbuf_size -} - -static struct scst_cmd *scst_complete_request_sense(struct scst_cmd *cmd) -{ - struct scst_cmd *orig_cmd = cmd->orig_cmd; - uint8_t *buf; - int len; - - TRACE_ENTRY(); - - BUG_ON(orig_cmd); - - len = scst_get_buf_first(cmd, &buf); - - if ((cmd->status == 0) && SCST_SENSE_VALID(buf) && - (!SCST_NO_SENSE(buf))) - { - TRACE_BUFF_FLAG(TRACE_SCSI, "REQUEST SENSE returned", - buf, len); - memcpy(orig_cmd->sense_buffer, buf, - (sizeof(orig_cmd->sense_buffer) > len) ? - len : sizeof(orig_cmd->sense_buffer)); - } else { - PRINT_ERROR_PR("%s", "Unable to get the sense via " - "REQUEST SENSE, returning HARDWARE ERROR"); - scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); - } - - scst_put_buf(cmd, buf); - - scst_free_internal_cmd(cmd); - - TRACE_EXIT_HRES((unsigned long)orig_cmd); - return orig_cmd; -} - static int scst_done_cmd_check(struct scst_cmd *cmd, int *pres) { int res = 0, rc; @@ -1967,10 +1846,10 @@ static int scst_done_cmd_check(struct scst_cmd *cmd, int *pres) TRACE_ENTRY(); - if (cmd->cdb[0] == REQUEST_SENSE) { + if (unlikely(cmd->cdb[0] == REQUEST_SENSE)) { if (cmd->internal) cmd = scst_complete_request_sense(cmd); - } else if (scst_check_auto_sense(cmd)) { + } else if (unlikely(scst_check_auto_sense(cmd))) { PRINT_INFO_PR("Command finished with CHECK CONDITION, but " "without sense data (opcode 0x%x), issuing " "REQUEST SENSE", cmd->cdb[0]); @@ -2238,7 +2117,7 @@ static int scst_xmit_response(struct scst_cmd *cmd) if (cmd->sg) { int i; struct scatterlist *sg = cmd->sg; - TRACE(TRACE_SEND_BOT, + TRACE(TRACE_SEND_BOT, "Xmitting %d S/G(s) at %p sg[0].page at %p", cmd->sg_cnt, sg, (void*)sg[0].page); for(i = 0; i < cmd->sg_cnt; ++i) { @@ -2306,6 +2185,19 @@ out_error: goto out; } +void scst_tgt_cmd_done(struct scst_cmd *cmd) +{ + TRACE_ENTRY(); + + BUG_ON(cmd->state != SCST_CMD_STATE_XMIT_WAIT); + + cmd->state = SCST_CMD_STATE_FINISHED; + scst_proccess_redirect_cmd(cmd, scst_get_context(), 1); + + TRACE_EXIT(); + return; +} + static int scst_finish_cmd(struct scst_cmd *cmd) { int res; @@ -2343,19 +2235,6 @@ static int scst_finish_cmd(struct scst_cmd *cmd) return res; } -void scst_tgt_cmd_done(struct scst_cmd *cmd) -{ - TRACE_ENTRY(); - - BUG_ON(cmd->state != SCST_CMD_STATE_XMIT_WAIT); - - cmd->state = SCST_CMD_STATE_FINISHED; - scst_proccess_redirect_cmd(cmd, scst_get_context(), 1); - - TRACE_EXIT(); - return; -} - /* * Returns 0 on success, > 0 when we need to wait for unblock, * < 0 if there is no device (lun) or device type handler.