diff --git a/iscsi-scst/README b/iscsi-scst/README index 0a5d968b8..36cc6d199 100644 --- a/iscsi-scst/README +++ b/iscsi-scst/README @@ -103,6 +103,14 @@ means name of the target, for example: "Default_iqn.2007-05.com.example:storage.disk1.sys1.xyz", and add there all necessary LUNs. Check SCST README file for details. +If under high load you experience I/O stalls or see in the kernel log +abort or reset messages then try to reduce QueuedCommands parameter in +iscsi-scstd.conf file for the corresponding target. Particularly, it is +known that the default value 32 sometimes too high if you do intensive +writes from VMware on a target disk, which use LVM in the snapshot mode. +In this case value like 16 or even 10 depending of your backstorage +speed could be more appropriate. + Compilation options ------------------- diff --git a/iscsi-scst/include/iscsi_u.h b/iscsi-scst/include/iscsi_u.h index 4d7c748c9..807f51894 100644 --- a/iscsi-scst/include/iscsi_u.h +++ b/iscsi-scst/include/iscsi_u.h @@ -45,7 +45,6 @@ struct session_info { char initiator_name[ISCSI_NAME_LEN]; char user_name[ISCSI_NAME_LEN]; u32 exp_cmd_sn; - u32 max_cmd_sn; }; #define DIGEST_ALL (DIGEST_NONE | DIGEST_CRC32C) diff --git a/iscsi-scst/kernel/config.c b/iscsi-scst/kernel/config.c index efda41c4f..3a0ec09bc 100644 --- a/iscsi-scst/kernel/config.c +++ b/iscsi-scst/kernel/config.c @@ -301,7 +301,6 @@ static int get_session_info(struct iscsi_target *target, unsigned long ptr) return -ENOENT; info.exp_cmd_sn = session->exp_cmd_sn; - info.max_cmd_sn = session->max_cmd_sn; if (copy_to_user((void *) ptr, &info, sizeof(info))) return -EFAULT; diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index b21994df8..4a3b10281 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -62,6 +62,7 @@ static LIST_HEAD(iscsi_threads_list); static void cmnd_remove_hash(struct iscsi_cmnd *cmnd); static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status); static void cmnd_prepare_skip_pdu(struct iscsi_cmnd *cmnd); +static void iscsi_cond_send_tm_resp(struct iscsi_cmnd *rsp, int force); static inline u32 cmnd_write_size(struct iscsi_cmnd *cmnd) { @@ -115,6 +116,7 @@ struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn, struct iscsi_cmnd *parent if (parent == NULL) { conn_get(conn); + #ifdef NET_PAGE_CALLBACKS_DEFINED atomic_set(&cmnd->net_ref_cnt, 0); #endif @@ -229,6 +231,14 @@ void cmnd_done(struct iscsi_cmnd *cmnd) #endif } + if (cmnd->dec_active_cmnds) { + struct iscsi_session *sess = cmnd->conn->session; + TRACE_DBG("Decrementing active_cmds (cmd %p, sess %p, " + "new value %d)", cmnd, sess, + atomic_read(&sess->active_cmds)-1); + atomic_dec(&sess->active_cmds); + } + cmnd_free(cmnd); return; } @@ -333,6 +343,15 @@ void req_cmnd_release(struct iscsi_cmnd *req) if (req->hashed) cmnd_remove_hash(req); + if (req->dec_active_cmnds) { + struct iscsi_session *sess = req->conn->session; + TRACE_DBG("Decrementing active_cmds (cmd %p, sess %p, " + "new value %d)", req, sess, + atomic_read(&sess->active_cmds)-1); + atomic_dec(&sess->active_cmds); + req->dec_active_cmnds = 0; + } + cmnd_put(req); TRACE_EXIT(); @@ -629,6 +648,15 @@ static void iscsi_cmnd_reject(struct iscsi_cmnd *req, int reason) req->pdu.bhs.opcode = ISCSI_OP_PDU_REJECT; } +static inline int iscsi_get_allowed_cmds(struct iscsi_session *sess) +{ + int res = max(-1, (int)sess->max_queued_cmnds - + atomic_read(&sess->active_cmds)-1); + TRACE_DBG("allowed cmds %d (sess %p, active_cmds %d)", res, + sess, atomic_read(&sess->active_cmds)); + return res; +} + static u32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn) { struct iscsi_conn *conn = cmnd->conn; @@ -640,7 +668,8 @@ static u32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn) if (set_stat_sn) cmnd->pdu.bhs.sn = cpu_to_be32(conn->stat_sn++); cmnd->pdu.bhs.exp_sn = cpu_to_be32(sess->exp_cmd_sn); - cmnd->pdu.bhs.max_sn = cpu_to_be32(sess->exp_cmd_sn + sess->max_queued_cmnds); + cmnd->pdu.bhs.max_sn = cpu_to_be32(sess->exp_cmd_sn + + iscsi_get_allowed_cmds(sess)); res = cpu_to_be32(conn->stat_sn); @@ -738,6 +767,7 @@ static int cmnd_insert_hash(struct iscsi_cmnd *cmnd) TRACE_DBG("%p:%x", cmnd, itt); if (itt == ISCSI_RESERVED_TAG) { + PRINT_ERROR("%s", "ITT is RESERVED_TAG"); err = -ISCSI_REASON_PROTOCOL_ERROR; goto out; } @@ -1143,6 +1173,12 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req) TRACE_DBG("scsi command: %02x", req_hdr->scb[0]); + TRACE_DBG("Incrementing active_cmds (cmd %p, sess %p, " + "new value %d)", req, session, + atomic_read(&session->active_cmds)+1); + atomic_inc(&session->active_cmds); + req->dec_active_cmnds = 1; + scst_cmd = scst_rx_cmd(session->scst_sess, (uint8_t*)&req_hdr->lun, sizeof(req_hdr->lun), req_hdr->scb, sizeof(req_hdr->scb), SCST_NON_ATOMIC); @@ -1591,7 +1627,14 @@ static void execute_task_management(struct iscsi_cmnd *req) memset(¶ms, 0, sizeof(params)); params.atomic = SCST_NON_ATOMIC; params.tgt_priv = req; - + + if (conn->session->tm_rsp != NULL) { + struct iscsi_task_rsp_hdr *rsp_hdr = + (struct iscsi_task_rsp_hdr *)&conn->session->tm_rsp->pdu.bhs; + rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_REJECTED; + iscsi_cond_send_tm_resp(conn->session->tm_rsp, 1); + } + if ((function != ISCSI_FUNCTION_ABORT_TASK) && (req_hdr->rtt != ISCSI_RESERVED_TAG)) { PRINT_ERROR("Invalid RTT %x (TM fn %x)", req_hdr->rtt, @@ -1944,6 +1987,9 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd) spin_unlock(&session->sn_lock); + if (unlikely(session->tm_rsp != NULL)) + iscsi_cond_send_tm_resp(session->tm_rsp, 0); + iscsi_cmnd_exec(cmnd); if (list_empty(&session->pending_list)) @@ -1964,9 +2010,10 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd) session->exp_cmd_sn); } - if (after(cmd_sn, session->exp_cmd_sn + session->max_queued_cmnds)) { - PRINT_ERROR("too large cmd_sn (%u,%u)", cmd_sn, - session->exp_cmd_sn); + if (after(cmd_sn, session->exp_cmd_sn + iscsi_get_allowed_cmds(session))) { + PRINT_ERROR("too large cmd_sn %u (exp_cmd_sn %u, " + "max_sn %u)", cmd_sn, session->exp_cmd_sn, + iscsi_get_allowed_cmds(session)); } spin_unlock(&session->sn_lock); @@ -2061,14 +2108,8 @@ out: void cmnd_rx_end(struct iscsi_cmnd *cmnd) { - if (unlikely(cmnd->tmfabort)) { - TRACE_MGMT_DBG("cmnd %p (scst_cmd %p) aborted", cmnd, - cmnd->scst_cmd); - req_cmnd_release_force(cmnd, ISCSI_FORCE_RELEASE_WRITE); - return; - } - TRACE_DBG("%p:%x", cmnd, cmnd_opcode(cmnd)); + switch (cmnd_opcode(cmnd)) { case ISCSI_OP_SCSI_REJECT: case ISCSI_OP_NOOP_OUT: @@ -2093,6 +2134,7 @@ void cmnd_rx_end(struct iscsi_cmnd *cmnd) req_cmnd_release(cmnd); break; } + return; } #ifndef NET_PAGE_CALLBACKS_DEFINED @@ -2313,6 +2355,50 @@ out: return SCST_TGT_RES_SUCCESS; } +static void iscsi_cond_send_tm_resp(struct iscsi_cmnd *rsp, int force) +{ + struct iscsi_task_mgt_hdr *req_hdr = + (struct iscsi_task_mgt_hdr *)&rsp->parent_req->pdu.bhs; + int function = req_hdr->function & ISCSI_FUNCTION_MASK; + struct iscsi_session *sess = rsp->conn->session; + + TRACE_ENTRY(); + + if (!force) { + spin_lock(&sess->sn_lock); + switch(function) { + case ISCSI_FUNCTION_ABORT_TASK_SET: + case ISCSI_FUNCTION_CLEAR_TASK_SET: + case ISCSI_FUNCTION_CLEAR_ACA: + if (after(req_hdr->cmd_sn, sess->exp_cmd_sn)) { + TRACE_MGMT_DBG("Delaying TM fn %x response, " + "because not all affected commands " + "received (rsp %p, cmd sn %x, exp sn " + "%x)", function, rsp, req_hdr->cmd_sn, + sess->exp_cmd_sn); + sess->tm_rsp = rsp; + spin_unlock(&sess->sn_lock); + goto out; + } + break; + default: + break; + } + spin_unlock(&sess->sn_lock); + } + + if (rsp == sess->tm_rsp) { + TRACE_MGMT_DBG("Sending delayed rsp %p (fn %x)", rsp, function); + sess->tm_rsp = NULL; + } + iscsi_cmnd_init_write(rsp, + ISCSI_INIT_WRITE_REMOVE_HASH | ISCSI_INIT_WRITE_WAKE); + +out: + TRACE_EXIT(); + return; +} + static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status) { struct iscsi_cmnd *rsp; @@ -2320,6 +2406,8 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status) (struct iscsi_task_mgt_hdr *)&req->pdu.bhs; struct iscsi_task_rsp_hdr *rsp_hdr; + TRACE_ENTRY(); + TRACE((req_hdr->function == ISCSI_FUNCTION_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT, "TM req %p finished, status %d", req, status); @@ -2336,9 +2424,12 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status) ISCSI_FUNCTION_TARGET_COLD_RESET) rsp->should_close_conn = 1; - iscsi_cmnd_init_write(rsp, - ISCSI_INIT_WRITE_REMOVE_HASH | ISCSI_INIT_WRITE_WAKE); + iscsi_cond_send_tm_resp(rsp, 0); + req_cmnd_release(req); + + TRACE_EXIT(); + return; } static inline int iscsi_get_mgmt_response(int status) diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index c328e9189..670f3a210 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -92,13 +92,14 @@ struct iscsi_session { struct list_head pending_list; u32 next_ttt; - /* Both unprotected, since read-only */ - u32 max_queued_cmnds; - u32 max_cmd_sn; /* Not used ??, ToDo */ + u32 max_queued_cmnds; /* unprotected, since read-only */ + atomic_t active_cmds; spinlock_t sn_lock; u32 exp_cmd_sn; /* protected by sn_lock */ + struct iscsi_cmnd *tm_rsp; + /* read only, if there are connection(s) */ struct iscsi_sess_param sess_param; @@ -238,6 +239,7 @@ struct iscsi_cmnd { unsigned int write_processing_started:1; unsigned int data_waiting:1; unsigned int force_cleanup_done:1; + unsigned int dec_active_cmnds:1; #ifdef EXTRACHECKS unsigned int release_called:1; #endif diff --git a/iscsi-scst/kernel/session.c b/iscsi-scst/kernel/session.c index 6a5b3a35f..881071125 100644 --- a/iscsi-scst/kernel/session.c +++ b/iscsi-scst/kernel/session.c @@ -48,9 +48,9 @@ static int iscsi_session_alloc(struct iscsi_target *target, struct session_info memcpy(&session->sess_param, &target->trgt_sess_param, sizeof(session->sess_param)); session->max_queued_cmnds = target->trgt_param.queued_cmnds; + atomic_set(&session->active_cmds, 0); session->exp_cmd_sn = info->exp_cmd_sn; - session->max_cmd_sn = info->max_cmd_sn; session->initiator_name = kstrdup(info->initiator_name, GFP_KERNEL); if (!session->initiator_name) { @@ -127,6 +127,11 @@ int session_free(struct iscsi_session *session) (unsigned long long)session->sid); sBUG_ON(!list_empty(&session->conn_list)); + if (unlikely(atomic_read(&session->active_cmds) != 0)) { + PRINT_ERROR("active_cmds not 0 (%d)!!", + atomic_read(&session->active_cmds)); + sBUG(); + } for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++) sBUG_ON(!list_empty(&session->cmnd_hash[i])); diff --git a/iscsi-scst/usr/ctldev.c b/iscsi-scst/usr/ctldev.c index 8826a0cef..41929d644 100644 --- a/iscsi-scst/usr/ctldev.c +++ b/iscsi-scst/usr/ctldev.c @@ -377,7 +377,7 @@ static int iscsi_param_set(u32 tid, u64 sid, int type, u32 partial, } static int iscsi_session_create(u32 tid, u64 sid, u32 exp_cmd_sn, - u32 max_cmd_sn, char *name, char *user) + char *name, char *user) { struct session_info info; @@ -386,7 +386,6 @@ static int iscsi_session_create(u32 tid, u64 sid, u32 exp_cmd_sn, info.tid = tid; info.sid = sid; info.exp_cmd_sn = exp_cmd_sn; - info.max_cmd_sn = max_cmd_sn; strncpy(info.initiator_name, name, sizeof(info.initiator_name) - 1); strncpy(info.user_name, user, sizeof(info.user_name) - 1); diff --git a/iscsi-scst/usr/iscsi_scstd.c b/iscsi-scst/usr/iscsi_scstd.c index 80caefef7..d9bacdbcc 100644 --- a/iscsi-scst/usr/iscsi_scstd.c +++ b/iscsi-scst/usr/iscsi_scstd.c @@ -224,11 +224,11 @@ static void accept_connection(int listen) if (from.ss_family == AF_INET) { struct sockaddr_in *in = (struct sockaddr_in *)&from; - log_info("Connect from %s:%hd", inet_ntoa(in->sin_addr), + log_info("Connect from %s:%hu", inet_ntoa(in->sin_addr), ntohs(in->sin_port)); } else if (from.ss_family == AF_INET6) { struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&from; - log_info("Connect from %x:%x:%x:%x:%x:%x:%x:%x.%hd", + log_info("Connect from %x:%x:%x:%x:%x:%x:%x:%x.%hu", in6->sin6_addr.s6_addr16[7], in6->sin6_addr.s6_addr16[6], in6->sin6_addr.s6_addr16[5], in6->sin6_addr.s6_addr16[4], in6->sin6_addr.s6_addr16[3], in6->sin6_addr.s6_addr16[2], diff --git a/iscsi-scst/usr/iscsid.c b/iscsi-scst/usr/iscsid.c index 7112215aa..76d70575e 100644 --- a/iscsi-scst/usr/iscsid.c +++ b/iscsi-scst/usr/iscsid.c @@ -582,8 +582,7 @@ static void cmnd_exec_login(struct connection *conn) rsp->sid = conn->sid; rsp->stat_sn = cpu_to_be32(conn->stat_sn++); rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn); - conn->max_cmd_sn = conn->exp_cmd_sn + 1; - rsp->max_cmd_sn = cpu_to_be32(conn->max_cmd_sn); + rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1); return; init_err: rsp->flags = 0; @@ -690,8 +689,7 @@ static void cmnd_exec_text(struct connection *conn) rsp->stat_sn = cpu_to_be32(conn->stat_sn++); rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn); - conn->max_cmd_sn = conn->exp_cmd_sn + 1; - rsp->max_cmd_sn = cpu_to_be32(conn->max_cmd_sn); + rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1); } static void cmnd_exec_logout(struct connection *conn) @@ -709,8 +707,7 @@ static void cmnd_exec_logout(struct connection *conn) rsp->stat_sn = cpu_to_be32(conn->stat_sn++); rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn); - conn->max_cmd_sn = conn->exp_cmd_sn + 1; - rsp->max_cmd_sn = cpu_to_be32(conn->max_cmd_sn); + rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1); } int cmnd_execute(struct connection *conn) diff --git a/iscsi-scst/usr/iscsid.h b/iscsi-scst/usr/iscsid.h index 13bcb7467..9ecaa2bcc 100644 --- a/iscsi-scst/usr/iscsid.h +++ b/iscsi-scst/usr/iscsid.h @@ -74,7 +74,6 @@ struct connection { u32 cmd_sn; u32 exp_cmd_sn; - u32 max_cmd_sn; struct PDU req; void *req_buffer; @@ -216,7 +215,7 @@ struct iscsi_kernel_interface { int (*param_set) (u32, u64, int, u32, struct iscsi_param *, int); int (*target_create) (u32 *, char *); int (*target_destroy) (u32); - int (*session_create) (u32, u64, u32, u32, char *, char *); + int (*session_create) (u32, u64, u32, char *, char *); int (*session_destroy) (u32, u64); int (*conn_create) (u32, u64, u32, u32, u32, int, u32, u32); int (*conn_destroy) (u32 tid, u64 sid, u32 cid); diff --git a/iscsi-scst/usr/session.c b/iscsi-scst/usr/session.c index f487d859e..bafc80292 100644 --- a/iscsi-scst/usr/session.c +++ b/iscsi-scst/usr/session.c @@ -161,7 +161,7 @@ void session_create(struct connection *conn) user = ""; ki->session_create(conn->tid, session->sid.id64, conn->exp_cmd_sn, - conn->max_cmd_sn, session->initiator, user); + session->initiator, user); ki->param_set(conn->tid, session->sid.id64, key_session, 0, conn->session_param, 0); } diff --git a/qla2x00t/qla2x00-target/ChangeLog b/qla2x00t/qla2x00-target/ChangeLog index f961ae170..e5d497694 100644 --- a/qla2x00t/qla2x00-target/ChangeLog +++ b/qla2x00t/qla2x00-target/ChangeLog @@ -3,7 +3,7 @@ Summary of changes between versions 0.9.5 and 0.9.6 - Support for per-target default security groups added. - - Updateed to work on 2.6.22.x kernels. + - Updated to work on 2.6.22.x kernels. - Updated to work with SCST 0.9.6. diff --git a/scst/README b/scst/README index 07e4db3af..59094498c 100644 --- a/scst/README +++ b/scst/README @@ -245,6 +245,17 @@ in/out in Makefile: and eases CPU load, but could create a security hole (information leakage), so enable it, if you have strict security requirements. + - ABORT_CONSIDER_FINISHED_TASKS_AS_NOT_EXISTING - if defined, in case + when TASK MANAGEMENT function ABORT TASK is trying to abort a + command, which has already finished, remote initiator, which sent the + ABORT TASK request, will receive TASK NOT EXIST (or ABORT FAILED) + response for the ABORT TASK request. This is more logical response, + since, because the command finished, attempt to abort it failed, but + some initiators, particularly VMware iSCSI initiator, consider TASK + NOT EXIST response as if the target got crazy and try to RESET it. + Then sometimes get crazy itself. So, this option is disabled by + default. + HIGHMEM kernel configurations are fully supported, but not recommended for performance reasons, except for scst_user, where they are not supported, because this module deals with user supplied memory on a diff --git a/scst/include/scsi_tgt.h b/scst/include/scsi_tgt.h index f3a4417b6..cd32e7443 100644 --- a/scst/include/scsi_tgt.h +++ b/scst/include/scsi_tgt.h @@ -2504,4 +2504,10 @@ int scst_block_generic_dev_done(struct scst_cmd *cmd, int scst_tape_generic_dev_done(struct scst_cmd *cmd, void (*set_block_size)(struct scst_cmd *cmd, int block_size)); +/* + * Issues a MODE SENSE for control mode page data and sets the corresponding + * dev's parameter from it. Returns 0 on success and not 0 otherwise. + */ +int scst_obtain_device_parameters(struct scst_device *dev); + #endif /* __SCST_H */ diff --git a/scst/src/Makefile b/scst/src/Makefile index 9987b8f5d..9ecb2f719 100644 --- a/scst/src/Makefile +++ b/scst/src/Makefile @@ -118,6 +118,7 @@ EXTRA_CFLAGS += -DEXTRACHECKS #EXTRA_CFLAGS += -DUSE_EXPECTED_VALUES #EXTRA_CFLAGS += -DALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ +#EXTRA_CFLAGS += -DABORT_CONSIDER_FINISHED_TASKS_AS_NOT_EXISTING #EXTRA_CFLAGS += -fno-inline diff --git a/scst/src/dev_handlers/scst_cdrom.c b/scst/src/dev_handlers/scst_cdrom.c index 67201ffa3..538969d43 100644 --- a/scst/src/dev_handlers/scst_cdrom.c +++ b/scst/src/dev_handlers/scst_cdrom.c @@ -147,6 +147,10 @@ int cdrom_attach(struct scst_device *dev) goto out_free_buf; } + res = scst_obtain_device_parameters(dev); + if (res != 0) + goto out_free_buf; + out_free_buf: kfree(buffer); diff --git a/scst/src/dev_handlers/scst_changer.c b/scst/src/dev_handlers/scst_changer.c index 97b9e59e2..fe9af9df1 100644 --- a/scst/src/dev_handlers/scst_changer.c +++ b/scst/src/dev_handlers/scst_changer.c @@ -90,8 +90,14 @@ int changer_attach(struct scst_device *dev) CHANGER_RETRIES); TRACE_DBG("TEST_UNIT_READY done: %x", res); } while ((--retries > 0) && res); - if (res) + if (res) { res = -ENODEV; + goto out; + } + + res = scst_obtain_device_parameters(dev); + if (res != 0) + goto out; out: TRACE_EXIT_HRES(res); diff --git a/scst/src/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c index f7668821b..5062da360 100644 --- a/scst/src/dev_handlers/scst_disk.c +++ b/scst/src/dev_handlers/scst_disk.c @@ -219,6 +219,10 @@ int disk_attach(struct scst_device *dev) goto out_free_buf; } + res = scst_obtain_device_parameters(dev); + if (res != 0) + goto out_free_buf; + out_free_buf: kfree(buffer); diff --git a/scst/src/dev_handlers/scst_modisk.c b/scst/src/dev_handlers/scst_modisk.c index a82993942..a6d574d5e 100644 --- a/scst/src/dev_handlers/scst_modisk.c +++ b/scst/src/dev_handlers/scst_modisk.c @@ -234,6 +234,10 @@ int modisk_attach(struct scst_device *dev) goto out_free_buf; } + res = scst_obtain_device_parameters(dev); + if (res != 0) + goto out_free_buf; + out_free_buf: kfree(buffer); diff --git a/scst/src/dev_handlers/scst_processor.c b/scst/src/dev_handlers/scst_processor.c index a23704302..a5d662311 100644 --- a/scst/src/dev_handlers/scst_processor.c +++ b/scst/src/dev_handlers/scst_processor.c @@ -90,8 +90,14 @@ int processor_attach(struct scst_device *dev) PROCESSOR_RETRIES); TRACE_DBG("TEST_UNIT_READY done: %x", res); } while ((--retries > 0) && res); - if (res) + if (res) { res = -ENODEV; + goto out; + } + + res = scst_obtain_device_parameters(dev); + if (res != 0) + goto out; out: TRACE_EXIT(); diff --git a/scst/src/dev_handlers/scst_raid.c b/scst/src/dev_handlers/scst_raid.c index 2ae93d8a2..99c79bf26 100644 --- a/scst/src/dev_handlers/scst_raid.c +++ b/scst/src/dev_handlers/scst_raid.c @@ -90,8 +90,14 @@ int raid_attach(struct scst_device *dev) RAID_RETRIES); TRACE_DBG("TEST_UNIT_READY done: %x", res); } while ((--retries > 0) && res); - if (res) + if (res) { res = -ENODEV; + goto out; + } + + res = scst_obtain_device_parameters(dev); + if (res != 0) + goto out; out: TRACE_EXIT(); diff --git a/scst/src/dev_handlers/scst_tape.c b/scst/src/dev_handlers/scst_tape.c index 0e14841cf..d1ae0af23 100644 --- a/scst/src/dev_handlers/scst_tape.c +++ b/scst/src/dev_handlers/scst_tape.c @@ -222,6 +222,10 @@ int tape_attach(struct scst_device *dev) goto out_free_buf; } + res = scst_obtain_device_parameters(dev); + if (res != 0) + goto out_free_buf; + out_free_buf: kfree(buffer); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index ca2875542..7bc260422 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -38,7 +38,7 @@ #include "scst_cdbprobe.h" static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev); -int scst_check_internal_sense(struct scst_device *dev, int result, +static void scst_check_internal_sense(struct scst_device *dev, int result, uint8_t *sense, int sense_len); void scst_set_cmd_error_status(struct scst_cmd *cmd, int status) @@ -189,6 +189,7 @@ int scst_alloc_device(int gfp_mask, struct scst_device **out_dev) init_waitqueue_head(&dev->on_dev_waitQ); dev->dev_double_ua_possible = 1; dev->dev_serialized = 1; + dev->queue_alg = SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER; dev->dev_num = dev_num++; *out_dev = dev; @@ -1048,9 +1049,8 @@ static void scst_send_release(struct scst_tgt_dev *tgt_dev) PRINT_ERROR("RELEASE failed: %d", rc); TRACE_BUFFER("RELEASE sense", sense, SCST_SENSE_BUFFERSIZE); - if (scst_check_internal_sense(tgt_dev->dev, rc, - sense, SCST_SENSE_BUFFERSIZE) != 0) - break; + scst_check_internal_sense(tgt_dev->dev, rc, + sense, SCST_SENSE_BUFFERSIZE); } } @@ -2214,20 +2214,23 @@ out: return res; } -int scst_check_internal_sense(struct scst_device *dev, int result, +static void scst_check_internal_sense(struct scst_device *dev, int result, uint8_t *sense, int sense_len) { TRACE_ENTRY(); if (host_byte(result) == DID_RESET) { + TRACE(TRACE_MGMT_MINOR, "%s", "DID_RESET received, triggering " + "reset UA"); scst_set_sense(sense, sense_len, SCST_LOAD_SENSE(scst_sense_reset_UA)); scst_dev_check_set_UA(dev, NULL, sense, sense_len); - } else if (SCST_SENSE_VALID(sense) && scst_is_ua_sense(sense)) + } else if ((status_byte(result) == CHECK_CONDITION) && + SCST_SENSE_VALID(sense) && scst_is_ua_sense(sense)) scst_dev_check_set_UA(dev, NULL, sense, sense_len); TRACE_EXIT(); - return 0; + return; } int scst_obtain_device_parameters(struct scst_device *dev) @@ -2294,12 +2297,20 @@ int scst_obtain_device_parameters(struct scst_device *dev) goto out; } else { - PRINT_ERROR("Internal MODE_SENSE failed: %d", res); - TRACE_BUFFER("MODE_SENSE sense", sense_buffer, - sizeof(sense_buffer)); - if (scst_check_internal_sense(dev, res, sense_buffer, - sizeof(sense_buffer)) != 0) - break; + TRACE(TRACE_MGMT_MINOR, "Internal MODE SENSE to device " + "%d:%d:%d:%d failed: %x", dev->scsi_dev->host->host_no, + dev->scsi_dev->channel, dev->scsi_dev->id, + dev->scsi_dev->lun, res); + TRACE_BUFF_FLAG(TRACE_MGMT_MINOR, "MODE SENSE sense", + sense_buffer, sizeof(sense_buffer)); + if ((status_byte(res) == CHECK_CONDITION) && + SCST_SENSE_VALID(sense_buffer) && + (sense_buffer[2] == ILLEGAL_REQUEST)) { + res = 0; + goto out; + } + scst_check_internal_sense(dev, res, sense_buffer, + sizeof(sense_buffer)); } } res = -ENODEV; diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index bf72489aa..0008272d7 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -510,10 +510,6 @@ static int scst_register_device(struct scsi_device *scsidp) list_add_tail(&dev->dev_list_entry, &scst_dev_list); - res = scst_obtain_device_parameters(dev); - if (res != 0) - goto out_free; - list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) { if (dt->type == scsidp->type) { res = scst_assign_dev_handler(dev, dt); @@ -1760,6 +1756,7 @@ EXPORT_SYMBOL(scst_tape_generic_dev_done); EXPORT_SYMBOL(scst_get_cdb_info); EXPORT_SYMBOL(scst_cmd_get_tgt_priv_lock); EXPORT_SYMBOL(scst_cmd_set_tgt_priv_lock); +EXPORT_SYMBOL(scst_obtain_device_parameters); #ifdef DEBUG EXPORT_SYMBOL(scst_random); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 7c0f5d199..061a4f107 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -354,8 +354,6 @@ void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type); int scst_get_cdb_len(const uint8_t *cdb); -int scst_obtain_device_parameters(struct scst_device *dev); - void __scst_dev_check_set_UA(struct scst_device *dev, struct scst_cmd *exclude, const uint8_t *sense, int sense_len); static inline void scst_dev_check_set_UA(struct scst_device *dev, diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index d4108a173..bbdcb3820 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -3225,7 +3225,9 @@ static int scst_call_dev_task_mgmt_fn(struct scst_mgmt_cmd *mcmd, static inline int scst_is_strict_mgmt_fn(int mgmt_fn) { switch(mgmt_fn) { +#ifdef ABORT_CONSIDER_FINISHED_TASKS_AS_NOT_EXISTING case SCST_ABORT_TASK: +#endif #if 0 case SCST_ABORT_TASK_SET: case SCST_CLEAR_TASK_SET: