iscsi update
Subsystems (3)
The following patches were made over scsi-misc.
The bugs fixed are:
- Have qla4xxx hook into block/unblock code, and use new session state to fail/requeue IO during transport problems.
- Hook qla4xxx into async scanning code. Qla4xxx looks more like a normal old scsi card than a iscsi card. There is very little iscsi stuff going on in the driver, so it is much easier to just have this type of iscsi card work like other FC and SPI cards. Currently distros are doing crazy things to special case qla4xxx, so you can boot from it.
- Fix libiscsi nop timer setting, bad printks and session age testing.
PATCH 1/12 iscsi class, libiscsi: add iscsi sysfs session state file
From: Mike Christie <[email protected]>
This adds a iscsi session state file which exports the session state for both software and hardware iscsi. It also hooks libiscsi in.
--- drivers/scsi/libiscsi.c | 41 +++++++++----- drivers/scsi/scsi_transport_iscsi.c | 107 ++++++++++++++++++++++++++++++++++- include/scsi/libiscsi.h | 19 ++++++ include/scsi/scsi_transport_iscsi.h | 27 ++++----- 4 files changed, 161 insertions(+), 33 deletions(-)
drivers/scsi/libiscsi.c +26 -15
@@ -997,6 +997,7 @@ enum {FAILURE_SESSION_IN_RECOVERY ,FAILURE_SESSION_RECOVERY_TIMEOUT ,FAILURE_SESSION_LOGGING_OUT , + FAILURE_SESSION_NOT_READY, };int iscsi_queuecommand (struct scsi_cmnd *sc,void (*done)(struct scsi_cmnd *))
@@ -1017,6 +1018,12 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) session =iscsi_hostdata (host->hostdata);spin_lock (&session->lock); + reason =iscsi_session_chkready (session_to_cls (session)); +if (reason) { + sc->result = reason; + goto fault; + } +/* * ISCSI_STATE_FAILED is a temp. state. The recovery * code will decide what is best to do with command queued
@@ -1033,18 +1040,23 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))switch (session->state) {case ISCSI_STATE_IN_RECOVERY : reason =FAILURE_SESSION_IN_RECOVERY ; - goto reject; + sc->result =DID_IMM_RETRY <<16 ; +break ;case ISCSI_STATE_LOGGING_OUT : reason =FAILURE_SESSION_LOGGING_OUT ; - goto reject; + sc->result =DID_IMM_RETRY <<16 ; +break ;case ISCSI_STATE_RECOVERY_FAILED : reason =FAILURE_SESSION_RECOVERY_TIMEOUT ; + sc->result =DID_NO_CONNECT <<16 ;break ;case ISCSI_STATE_TERMINATE : reason =FAILURE_SESSION_TERMINATE ; + sc->result =DID_NO_CONNECT <<16 ;break ;default : reason =FAILURE_SESSION_FREED ; + sc->result =DID_NO_CONNECT <<16 ; } goto fault; }
@@ -1052,6 +1064,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) conn = session->leadconn;if (!conn) { reason =FAILURE_SESSION_FREED ; + sc->result =DID_NO_CONNECT <<16 ; goto fault; }
@@ -1091,9 +1104,7 @@ reject: fault:spin_unlock (&session->lock); -printk (KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n" , - sc->cmnd[0 ], reason); - sc->result = (DID_NO_CONNECT <<16 ); +debug_scsi ("iscsi: cmd 0x%x is not queued (%d)\n" , sc->cmnd[0 ], reason);scsi_set_resid (sc,scsi_bufflen (sc)); sc->scsi_done (sc);spin_lock (host->host_lock);
@@ -1239,7 +1250,8 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,* Fail commands. session lock held and recv side suspended and xmit * thread flushed */ -static void fail_all_commands (struct iscsi_conn *conn,unsigned lun) +static void fail_all_commands (struct iscsi_conn *conn,unsigned lun, +int error) {struct iscsi_cmd_task *ctask, *tmp;
@@ -1251,7 +1263,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)if (lun == ctask->sc->device->lun || lun ==-1 ) {debug_scsi ("failing pending sc %p itt 0x%x\n" , ctask->sc, ctask->itt); -fail_command (conn, ctask,DID_BUS_BUSY <<16 ); +fail_command (conn, ctask, error <<16 ); } }
@@ -1259,7 +1271,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)if (lun == ctask->sc->device->lun || lun ==-1 ) {debug_scsi ("failing requeued sc %p itt 0x%x\n" , ctask->sc, ctask->itt); -fail_command (conn, ctask,DID_BUS_BUSY <<16 ); +fail_command (conn, ctask, error <<16 ); } }
@@ -1573,7 +1585,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)/* need to grab the recv lock then session lock */ write_lock_bh (conn->recv_lock);spin_lock (&session->lock); -fail_all_commands (conn, sc->device->lun); +fail_all_commands (conn, sc->device->lun,DID_ERROR ); conn->tmf_state =TMF_INITIAL ;spin_unlock (&session->lock);write_unlock_bh (conn->recv_lock);
@@ -2019,11 +2031,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) conn->stop_stage =0 ; conn->tmf_state =TMF_INITIAL ; session->age++; -spin_unlock_bh (&session->lock); - -iscsi_unblock_session (session_to_cls (session)); -wake_up (&conn->ehwait); -return 0 ; +break ;case STOP_CONN_TERM : conn->stop_stage =0 ;break ;
@@ -2032,6 +2040,8 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) }spin_unlock_bh (&session->lock); +iscsi_unblock_session (session_to_cls (session)); +wake_up (&conn->ehwait);return 0 ; }EXPORT_SYMBOL_GPL (iscsi_conn_start);
@@ -2123,7 +2133,8 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,* flush queues. */ spin_lock_bh (&session->lock); -fail_all_commands (conn,-1 ); +fail_all_commands (conn,-1 , +STOP_CONN_RECOVER ?DID_BUS_BUSY :DID_ERROR );flush_control_queues (session, conn);spin_unlock_bh (&session->lock);mutex_unlock (&session->eh_mutex);
drivers/scsi/scsi_transport_iscsi.c +104 -3
188 lines not on this page · raw message
include/scsi/libiscsi.h +19 -0
@@ -135,6 +135,14 @@ static inline void* iscsi_next_hdr(struct iscsi_cmd_task *ctask)return (void *)ctask->hdr + ctask->hdr_len; } +/* Connection's states */ +enum { +ISCSI_CONN_INITIAL_STAGE , +ISCSI_CONN_STARTED , +ISCSI_CONN_STOPPED , +ISCSI_CONN_CLEANUP_WAIT , +}; +struct iscsi_conn {struct iscsi_cls_conn *cls_conn;/* ptr to class connection */ void *dd_data;/* iscsi_transport data */
@@ -227,6 +235,17 @@ struct iscsi_pool {int max;/* Max number of elements */ }; +/* Session's states */ +enum { +ISCSI_STATE_FREE =1 , +ISCSI_STATE_LOGGED_IN , +ISCSI_STATE_FAILED , +ISCSI_STATE_TERMINATE , +ISCSI_STATE_IN_RECOVERY , +ISCSI_STATE_RECOVERY_FAILED , +ISCSI_STATE_LOGGING_OUT , +}; +struct iscsi_session {/* * Syncs up the scsi eh thread with the iscsi eh thread when sending
include/scsi/scsi_transport_iscsi.h +12 -15
@@ -149,13 +149,6 @@ extern void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error);extern int iscsi_recv_pdu (struct iscsi_cls_conn *conn,struct iscsi_hdr *hdr,char *data,uint32_t data_size); - -/* Connection's states */ -#define ISCSI_CONN_INITIAL_STAGE 0 -#define ISCSI_CONN_STARTED 1 -#define ISCSI_CONN_STOPPED 2 -#define ISCSI_CONN_CLEANUP_WAIT 3 -struct iscsi_cls_conn {struct list_head conn_list;/* item in connlist */ void *dd_data;/* LLD private data */
@@ -169,19 +162,21 @@ struct iscsi_cls_conn {#define iscsi_dev_to_conn (_dev) \ container_of(_dev, struct iscsi_cls_conn, dev) -/* Session's states */ -#define ISCSI_STATE_FREE 1 -#define ISCSI_STATE_LOGGED_IN 2 -#define ISCSI_STATE_FAILED 3 -#define ISCSI_STATE_TERMINATE 4 -#define ISCSI_STATE_IN_RECOVERY 5 -#define ISCSI_STATE_RECOVERY_FAILED 6 -#define ISCSI_STATE_LOGGING_OUT 7 +#define iscsi_conn_to_session (_conn) \ + iscsi_dev_to_session(_conn->dev.parent) + +/* iscsi class session state */ +enum { +ISCSI_SESSION_LOGGED_IN , +ISCSI_SESSION_FAILED , +ISCSI_SESSION_FREE , +};struct iscsi_cls_session {struct list_head sess_list;/* item in session_list */ struct list_head host_list;struct iscsi_transport *transport; +spinlock_t lock;/* recovery fields */ int recovery_tmo;
@@ -190,6 +185,7 @@ struct iscsi_cls_session {int target_id; +int state;int sid;/* session id */ void *dd_data;/* LLD private data */ struct device dev;/* sysfs transport/container device */
@@ -214,6 +210,7 @@ struct iscsi_host {/* * session and connection functions that can be used by HW iSCSI LLDs */ +extern int iscsi_session_chkready (struct iscsi_cls_session *session);extern struct iscsi_cls_session *iscsi_alloc_session (struct Scsi_Host *shost,struct iscsi_transport *transport); extern int iscsi_add_session(struct iscsi_cls_session *session,
Signature · 1 line
1.5.2.1
PATCH 2/12 qla4xxx: have qla4xxx directly call iscsi recovery functions
From: Mike Christie <[email protected]>
Qla4xxx can just call the iscsi recovery functions directly. There is no need for userspace to do this for qla4xxx, because we do not use the mutex to iterate over devices anymore and iscsi_block /unblock_session can be called from interrupt context or the dpc thread. And having userspace do this just creates uneeded headaches for qla4xxx root situations where the session may experience problems. For example during the kernel shutdown the scsi layer wants to send sync caches, but at this time userspace is not up (iscsid is not running), so we cannot recover from the problem.
--- drivers/scsi/qla4xxx/ql4_init.c | 1 + drivers/scsi/qla4xxx/ql4_os.c | 40 +++----------------------------------- 2 files changed, 5 insertions(+), 36 deletions(-)
drivers/scsi/qla4xxx/ql4_init.c +1 -0
@@ -1306,6 +1306,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,atomic_set (&ddb_entry->relogin_timer,0 );clear_bit (DF_RELOGIN , &ddb_entry->flags);clear_bit (DF_NO_RELOGIN , &ddb_entry->flags); +iscsi_unblock_session (ddb_entry->sess);iscsi_session_event (ddb_entry->sess,ISCSI_KEVENT_CREATE_SESSION );/*
drivers/scsi/qla4xxx/ql4_os.c +4 -36
@@ -63,8 +63,6 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, enum iscsi_param param, char *buf);static int qla4xxx_host_get_param (struct Scsi_Host *shost,enum iscsi_host_param param,char *buf); -static void qla4xxx_conn_stop (struct iscsi_cls_conn *conn,int flag); -static int qla4xxx_conn_start (struct iscsi_cls_conn *conn);static void qla4xxx_recovery_timedout (struct iscsi_cls_session *session);/*
@@ -116,8 +114,6 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { .get_conn_param = qla4xxx_conn_get_param, .get_session_param = qla4xxx_sess_get_param, .get_host_param = qla4xxx_host_get_param, - .start_conn = qla4xxx_conn_start, - .stop_conn = qla4xxx_conn_stop, .session_recovery_timedout = qla4xxx_recovery_timedout, };
@@ -140,38 +136,6 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)queue_work (ha->dpc_thread, &ha->dpc_work); } -static int qla4xxx_conn_start (struct iscsi_cls_conn *conn) -{ -struct iscsi_cls_session *session; -struct ddb_entry *ddb_entry; - - session =iscsi_dev_to_session (conn->dev.parent); - ddb_entry = session->dd_data; - -DEBUG2 (printk ("scsi%ld: %s: index [%d] starting conn\n" , - ddb_entry->ha->host_no, __func__, - ddb_entry->fw_ddb_index)); -iscsi_unblock_session (session); -return 0 ; -} - -static void qla4xxx_conn_stop (struct iscsi_cls_conn *conn,int flag) -{ -struct iscsi_cls_session *session; -struct ddb_entry *ddb_entry; - - session =iscsi_dev_to_session (conn->dev.parent); - ddb_entry = session->dd_data; - -DEBUG2 (printk ("scsi%ld: %s: index [%d] stopping conn\n" , - ddb_entry->ha->host_no, __func__, - ddb_entry->fw_ddb_index)); -if (flag ==STOP_CONN_RECOVER ) -iscsi_block_session (session); -else -printk (KERN_ERR "iscsi: invalid stop flag %d\n" , flag); -} -static int qla4xxx_host_get_param (struct Scsi_Host *shost,enum iscsi_host_param param,char *buf) {
@@ -308,6 +272,9 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)DEBUG2 (printk (KERN_ERR "Could not add connection.\n" ));return -ENOMEM ; } + +/* finally ready to go */ +iscsi_unblock_session (ddb_entry->sess);return 0 ; }
@@ -364,6 +331,7 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,DEBUG3 (printk ("scsi%d:%d:%d: index [%d] marked MISSING\n" , ha->host_no, ddb_entry->bus, ddb_entry->target, ddb_entry->fw_ddb_index)); +iscsi_block_session (ddb_entry->sess);iscsi_conn_error (ddb_entry->conn,ISCSI_ERR_CONN_FAILED ); }
Signature · 1 line
1.5.2.1
PATCH 3/12 qla4xxx: have qla4xxx use iscsi class session state check ready
From: Mike Christie <[email protected]>
This has qla4xxx use the iscsi class's check ready function in the queue command function, so all iscsi drivers return the same error value for common problems.
--- drivers/scsi/qla4xxx/ql4_os.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-)
drivers/scsi/qla4xxx/ql4_os.c +12 -0
@@ -398,9 +398,21 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, {struct scsi_qla_host *ha =to_qla_host (cmd->device->host);struct ddb_entry *ddb_entry = cmd->device->hostdata; +struct iscsi_cls_session *sess = ddb_entry->sess;struct srb *srb;int rval; +if (!sess) { + cmd->result =DID_IMM_RETRY <<16 ; + goto qc_fail_command; + } + + rval =iscsi_session_chkready (sess); +if (rval) { + cmd->result = rval; + goto qc_fail_command; + } +if (atomic_read (&ddb_entry->state) !=DDB_STATE_ONLINE ) {if (atomic_read (&ddb_entry->state) ==DDB_STATE_DEAD ) { cmd->result =DID_NO_CONNECT <<16 ;
Signature · 1 line
1.5.2.1
PATCH 4/12 iscsi class: add session scanning
From: Mike Christie <[email protected]>
This just adds iscsi session scanning which works like fc rport scanning. The future patches will hook the drivers into Mathew Wilcox's async scanning infrastructure, so userspace does not have to special case iscsi and so userspace does not have to make a extra special case for hardware iscsi root scanning.
--- drivers/scsi/scsi_transport_iscsi.c | 37 ++++++++++++++++++++++++++++------ include/scsi/scsi_transport_iscsi.h | 7 +++-- 2 files changed, 34 insertions(+), 10 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +30 -7
@@ -128,11 +128,11 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,INIT_LIST_HEAD (&ihost->sessions);mutex_init (&ihost->mutex); -snprintf (ihost->unbind_workq_name,KOBJ_NAME_LEN ,"iscsi_unbind_%d" , +snprintf (ihost->scan_workq_name,KOBJ_NAME_LEN ,"iscsi_scan_%d" , shost->host_no); - ihost->unbind_workq =create_singlethread_workqueue ( - ihost->unbind_workq_name); -if (!ihost->unbind_workq) + ihost->scan_workq =create_singlethread_workqueue ( + ihost->scan_workq_name); +if (!ihost->scan_workq)return -ENOMEM ;return 0 ; }
@@ -143,7 +143,7 @@ static int iscsi_remove_host(struct transport_container *tc, struct device *dev,struct Scsi_Host *shost =dev_to_shost (dev);struct iscsi_host *ihost = shost->shost_data; -destroy_workqueue (ihost->unbind_workq); +destroy_workqueue (ihost->scan_workq);return 0 ; }
@@ -302,6 +302,23 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,return 0 ; } +static void iscsi_scan_session (struct work_struct *work) +{ +struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, scan_work); +unsigned long flags; + +spin_lock_irqsave (&session->lock, flags); +if (session->state !=ISCSI_SESSION_LOGGED_IN ) { +spin_unlock_irqrestore (&session->lock, flags); +return ; + } +spin_unlock_irqrestore (&session->lock, flags); + +scsi_scan_target (&session->dev,0 , session->target_id, +SCAN_WILD_CARD ,1 ); +} +static void session_recovery_timedout (struct work_struct *work) { struct iscsi_cls_session *session =
@@ -340,6 +357,8 @@ void __iscsi_unblock_session(struct iscsi_cls_session *session)void iscsi_unblock_session (struct iscsi_cls_session *session) { +struct Scsi_Host *shost =iscsi_session_to_shost (session); +struct iscsi_host *ihost = shost->shost_data;unsigned long flags;spin_lock_irqsave (&session->lock, flags);
@@ -347,6 +366,7 @@ void iscsi_unblock_session(struct iscsi_cls_session *session)spin_unlock_irqrestore (&session->lock, flags);__iscsi_unblock_session (session); +queue_work (ihost->scan_workq, &session->scan_work); }EXPORT_SYMBOL_GPL (iscsi_unblock_session);
@@ -390,7 +410,7 @@ static int iscsi_unbind_session(struct iscsi_cls_session *session)struct Scsi_Host *shost =iscsi_session_to_shost (session);struct iscsi_host *ihost = shost->shost_data; -return queue_work (ihost->unbind_workq, &session->unbind_work); +return queue_work (ihost->scan_workq, &session->unbind_work); } struct iscsi_cls_session *
@@ -411,6 +431,7 @@ iscsi_alloc_session(struct Scsi_Host *shost,INIT_LIST_HEAD (&session->host_list);INIT_LIST_HEAD (&session->sess_list);INIT_WORK (&session->unbind_work, __iscsi_unbind_session); +INIT_WORK (&session->scan_work, iscsi_scan_session);spin_lock_init (&session->lock);/* this is released in the dev's release function */
@@ -530,13 +551,15 @@ void iscsi_remove_session(struct iscsi_cls_session *session)spin_unlock_irqrestore (&session->lock, flags);__iscsi_unblock_session (session);iscsi_unbind_session (session); + +/* flush running scans */ +flush_workqueue (ihost->scan_workq);/* * If the session dropped while removing devices then we need to make * sure it is not blocked */ if (!cancel_delayed_work (&session->recovery_work))flush_workqueue (iscsi_eh_timer_workq); -flush_workqueue (ihost->unbind_workq);/* hw iscsi may not have removed all connections from session */ err = device_for_each_child(&session->dev, NULL,
include/scsi/scsi_transport_iscsi.h +4 -3
@@ -177,11 +177,12 @@ struct iscsi_cls_session {struct list_head host_list;struct iscsi_transport *transport;spinlock_t lock; +struct work_struct scan_work; +struct work_struct unbind_work;/* recovery fields */ int recovery_tmo;struct delayed_work recovery_work; -struct work_struct unbind_work;int target_id;
@@ -203,8 +204,8 @@ struct iscsi_cls_session {struct iscsi_host {struct list_head sessions;struct mutex mutex; -struct workqueue_struct *unbind_workq; -char unbind_workq_name[KOBJ_NAME_LEN ]; +struct workqueue_struct *scan_workq; +char scan_workq_name[KOBJ_NAME_LEN ]; };/*
Signature · 1 line
1.5.2.1
PATCH 5/12 qla4xxx: fix recovery timer and session unblock race
From: Mike Christie <[email protected]>
If qla4xxx is resetting up a session and the recovery timer fires we do not want to just set it to dead, because the dpc thread could have just set it to online and is in the middle of resetting it up.
--- drivers/scsi/qla4xxx/ql4_os.c | 19 +++++++++++-------- 1 files changed, 11 insertions(+), 8 deletions(-)
drivers/scsi/qla4xxx/ql4_os.c +11 -8
@@ -124,16 +124,19 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)struct ddb_entry *ddb_entry = session->dd_data;struct scsi_qla_host *ha = ddb_entry->ha; -DEBUG2 (printk ("scsi%ld: %s: index [%d] port down retry count of (%d) " -"secs exhausted, marking device DEAD.\n" , ha->host_no, - __func__, ddb_entry->fw_ddb_index, - ha->port_down_retry_count)); +if (atomic_read (&ddb_entry->state) !=DDB_STATE_ONLINE ) { +atomic_set (&ddb_entry->state,DDB_STATE_DEAD ); -atomic_set (&ddb_entry->state,DDB_STATE_DEAD ); +DEBUG2 (printk ("scsi%ld: %s: index [%d] port down retry count " +"of (%d) secs exhausted, marking device DEAD.\n" , + ha->host_no, __func__, ddb_entry->fw_ddb_index, + ha->port_down_retry_count)); -DEBUG2 (printk ("scsi%ld: %s: scheduling dpc routine - dpc flags = " -"0x%lx\n" , ha->host_no, __func__, ha->dpc_flags)); -queue_work (ha->dpc_thread, &ha->dpc_work); +DEBUG2 (printk ("scsi%ld: %s: scheduling dpc routine - dpc " +"flags = 0x%lx\n" , + ha->host_no, __func__, ha->dpc_flags)); +queue_work (ha->dpc_thread, &ha->dpc_work); + } } static int qla4xxx_host_get_param(struct Scsi_Host *shost,
Signature · 1 line
1.5.2.1
PATCH 6/12 iscsi class: add async scan helper
From: Mike Christie <[email protected]>
In qla4xxx's probe it will call the iscsi session setup functions for session that got setup on the initial start. This then makes it easy for the iscsi class to export a helper which indicates when those scans are done.
--- drivers/scsi/scsi_transport_iscsi.c | 38 ++++++++++++++++++++++++++++++++-- include/scsi/scsi_transport_iscsi.h | 3 +- 2 files changed, 37 insertions(+), 4 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +35 -3
@@ -127,6 +127,7 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,memset (ihost,0 ,sizeof (*ihost));INIT_LIST_HEAD (&ihost->sessions);mutex_init (&ihost->mutex); +atomic_set (&ihost->nr_scans,0 );snprintf (ihost->scan_workq_name,KOBJ_NAME_LEN ,"iscsi_scan_%d" , shost->host_no);
@@ -284,6 +285,25 @@ static int iscsi_is_session_dev(const struct device *dev)return dev->release == iscsi_session_release; } +/** +* iscsi_scan_finished - helper to report when running scans are done +* @shost: scsi host +* @time: scan run time +* +* This function can be used by drives like qla4xxx to report to the scsi +* layer when the scans it kicked off at module load time are done. +*/ +int iscsi_scan_finished (struct Scsi_Host *shost,unsigned long time) +{ +struct iscsi_host *ihost = shost->shost_data; +/* +* qla4xxx will have kicked off some session unblocks before calling +* scsi_scan_host, so just wait for them to complete. +*/ +return !atomic_read (&ihost->nr_scans); +} +EXPORT_SYMBOL_GPL (iscsi_scan_finished); +static int iscsi_user_scan (struct Scsi_Host *shost,uint channel,uint id,uint lun) {
@@ -306,17 +326,21 @@ static void iscsi_scan_session(struct work_struct *work) {struct iscsi_cls_session *session = container_of(work, struct iscsi_cls_session, scan_work); +struct Scsi_Host *shost =iscsi_session_to_shost (session); +struct iscsi_host *ihost = shost->shost_data;unsigned long flags;spin_lock_irqsave (&session->lock, flags);if (session->state !=ISCSI_SESSION_LOGGED_IN ) {spin_unlock_irqrestore (&session->lock, flags); -return ; + goto done; }spin_unlock_irqrestore (&session->lock, flags);scsi_scan_target (&session->dev,0 , session->target_id,SCAN_WILD_CARD ,1 ); +done: +atomic_dec (&ihost->nr_scans); }static void session_recovery_timedout (struct work_struct *work)
@@ -366,7 +390,15 @@ void iscsi_unblock_session(struct iscsi_cls_session *session)spin_unlock_irqrestore (&session->lock, flags);__iscsi_unblock_session (session); -queue_work (ihost->scan_workq, &session->scan_work); +/* +* Only do kernel scanning if the driver is properly hooked into +* the async scanning code (drivers like iscsi_tcp do login and +* scanning from userspace). +*/ +if (shost->hostt->scan_finished) { +if (queue_work (ihost->scan_workq, &session->scan_work)) +atomic_inc (&ihost->nr_scans); + } }EXPORT_SYMBOL_GPL (iscsi_unblock_session);
@@ -550,7 +582,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session) session->state =ISCSI_SESSION_FREE ;spin_unlock_irqrestore (&session->lock, flags);__iscsi_unblock_session (session); -iscsi_unbind_session (session); +__iscsi_unbind_session (&session->unbind_work);/* flush running scans */ flush_workqueue (ihost->scan_workq);
include/scsi/scsi_transport_iscsi.h +2 -1
@@ -203,6 +203,7 @@ struct iscsi_cls_session {struct iscsi_host {struct list_head sessions; +atomic_t nr_scans;struct mutex mutex;struct workqueue_struct *scan_workq;char scan_workq_name[KOBJ_NAME_LEN ];
@@ -229,6 +230,6 @@ extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess,extern int iscsi_destroy_conn (struct iscsi_cls_conn *conn);extern void iscsi_unblock_session (struct iscsi_cls_session *session);extern void iscsi_block_session (struct iscsi_cls_session *session); - +extern int iscsi_scan_finished (struct Scsi_Host *shost,unsigned long time);#endif
Signature · 1 line
1.5.2.1
PATCH 7/12 qla4xxx: add qla4xxx async scan support
From: Mike Christie <[email protected]>
qla4xxx has the old school startup/probe where it finds presetup sessions in its flash and then attempts to log into them before returning from the probe. This however, makes it very simple to add a iscsi class scan finished helper which the driver can use.
In future patches Dave or I will rip apart the driver to make it more like qla2xxx, but for now this is a very simple two line patch which fixes the problem of trying to figure out when the initial sessions are done being scanned.
--- drivers/scsi/qla4xxx/ql4_os.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
drivers/scsi/qla4xxx/ql4_os.c +3 -1
@@ -89,6 +89,8 @@ static struct scsi_host_template qla4xxx_driver_template = { .slave_alloc = qla4xxx_slave_alloc, .slave_destroy = qla4xxx_slave_destroy, + .scan_finished = iscsi_scan_finished, + .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING,
@@ -1306,7 +1308,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, qla4xxx_version_str, ha->pdev->device,pci_name (ha->pdev), ha->host_no, ha->firmware_version[0 ], ha->firmware_version[1 ], ha->patch_number, ha->build_number); - +scsi_scan_host (host);return 0 ; remove_host:
Signature · 1 line
1.5.2.1
PATCH 8/12 libiscsi: fix setting of nop timer
From: Mike Christie <[email protected]>
If we rollover then we could get a next_timeout of zero, so we need to set the new timer to that value.
--- drivers/scsi/libiscsi.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-)
drivers/scsi/libiscsi.c +3 -6
@@ -1385,14 +1385,11 @@ static void iscsi_check_transport_timeouts(unsigned long data)iscsi_send_nopout (conn,NULL ); } next_timeout = last_recv + timeout + (conn->ping_timeout *HZ ); - }else { + }else next_timeout = last_recv + timeout; - } -if (next_timeout) { -debug_scsi ("Setting next tmo %lu\n" , next_timeout); -mod_timer (&conn->transport_timer, next_timeout); - } +debug_scsi ("Setting next tmo %lu\n" , next_timeout); +mod_timer (&conn->transport_timer, next_timeout); done:spin_unlock (&session->lock); }
Signature · 1 line
1.5.2.1
PATCH 9/12 iscsi class: fix iscsi conn attr counter
From: Mike Christie <[email protected]>
There are 13 iscsi conn attrs, but since the IF/OF markers were not being used we did not notice that we forgot to increment the ISCSI_CONN_ATTRS counter.
--- drivers/scsi/scsi_transport_iscsi.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +1 -1
@@ -31,7 +31,7 @@#include <scsi/iscsi_if.h> #define ISCSI_SESSION_ATTRS 19 -#define ISCSI_CONN_ATTRS 11 +#define ISCSI_CONN_ATTRS 13#define ISCSI_HOST_ATTRS 4#define ISCSI_TRANSPORT_VERSION "2.0-867"
Signature · 1 line
1.5.2.1
PATCH 10/12 iscsi: fix up iscsi printk prefix
From: Mike Christie <[email protected]>
Some iscsi class messages have the dev_printk prefix and some libiscsi and iscsi_tcp messages have "iscsi" or the module name as a prefix which is normally pretty useless when trying to figure out which session or connection the message is attached to. This patch adds iscsi lib and class dev_printks so all messages have a common prefix that can be used to figure out which object printed it.
--- drivers/scsi/iscsi_tcp.c | 57 ++++++++++++++------------ drivers/scsi/libiscsi.c | 76 ++++++++++++++++++++--------------- drivers/scsi/scsi_transport_iscsi.c | 56 ++++++++++++++------------ include/scsi/libiscsi.h | 7 +++ include/scsi/scsi_transport_iscsi.h | 6 +++ 5 files changed, 116 insertions(+), 86 deletions(-)
drivers/scsi/iscsi_tcp.c +30 -27
@@ -629,8 +629,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)int rc;if (tcp_conn->in.datalen) { -printk (KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n" , - tcp_conn->in.datalen); +iscsi_conn_printk (KERN_ERR , conn, +"invalid R2t with datalen %d\n" , + tcp_conn->in.datalen);return ISCSI_ERR_DATALEN ; }
@@ -644,8 +645,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)iscsi_update_cmdsn (session, (struct iscsi_nopin *)rhdr);if (!ctask->sc || session->state !=ISCSI_STATE_LOGGED_IN ) { -printk (KERN_INFO "iscsi_tcp: dropping R2T itt %d in " -"recovery...\n" , ctask->itt); +iscsi_conn_printk (KERN_INFO , conn, +"dropping R2T itt %d in recovery.\n" , + ctask->itt);return 0 ; }
@@ -655,7 +657,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->exp_statsn = rhdr->statsn; r2t->data_length =be32_to_cpu (rhdr->data_length);if (r2t->data_length ==0 ) { -printk (KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n" ); +iscsi_conn_printk (KERN_ERR , conn, +"invalid R2T with zero data len\n" );__kfifo_put (tcp_ctask->r2tpool.queue, (void *)&r2t,sizeof (void *));return ISCSI_ERR_DATALEN ;
@@ -668,9 +671,10 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_offset =be32_to_cpu (rhdr->data_offset);if (r2t->data_offset + r2t->data_length >scsi_bufflen (ctask->sc)) { -printk (KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " -"offset %u and total length %d\n" , r2t->data_length, - r2t->data_offset,scsi_bufflen (ctask->sc)); +iscsi_conn_printk (KERN_ERR , conn, +"invalid R2T with data len %u at offset %u " +"and total length %d\n" , r2t->data_length, + r2t->data_offset,scsi_bufflen (ctask->sc));__kfifo_put (tcp_ctask->r2tpool.queue, (void *)&r2t,sizeof (void *));return ISCSI_ERR_DATALEN ;
@@ -736,8 +740,9 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)/* verify PDU length */ tcp_conn->in.datalen =ntoh24 (hdr->dlength);if (tcp_conn->in.datalen > conn->max_recv_dlength) { -printk (KERN_ERR "iscsi_tcp: datalen %d > %d\n" , - tcp_conn->in.datalen, conn->max_recv_dlength); +iscsi_conn_printk (KERN_ERR , conn, +"iscsi_tcp: datalen %d > %d\n" , + tcp_conn->in.datalen, conn->max_recv_dlength);return ISCSI_ERR_DATALEN ; }
@@ -819,10 +824,12 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)* For now we fail until we find a vendor that needs it */ if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) { -printk (KERN_ERR "iscsi_tcp: received buffer of len %u " -"but conn buffer is only %u (opcode %0x)\n" , - tcp_conn->in.datalen, -ISCSI_DEF_MAX_RECV_SEG_LEN , opcode); +iscsi_conn_printk (KERN_ERR , conn, +"iscsi_tcp: received buffer of " +"len %u but conn buffer is only %u " +"(opcode %0x)\n" , + tcp_conn->in.datalen, +ISCSI_DEF_MAX_RECV_SEG_LEN , opcode); rc =ISCSI_ERR_PROTO ;break ; }
@@ -1496,30 +1503,25 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) tcp_conn->tx_hash.tfm =crypto_alloc_hash ("crc32c" ,0 ,CRYPTO_ALG_ASYNC ); tcp_conn->tx_hash.flags =0 ; -if (IS_ERR (tcp_conn->tx_hash.tfm)) { -printk (KERN_ERR "Could not create connection due to crc32c " -"loading error %ld. Make sure the crc32c module is " -"built as a module or into the kernel\n" , -PTR_ERR (tcp_conn->tx_hash.tfm)); +if (IS_ERR (tcp_conn->tx_hash.tfm)) goto free_tcp_conn; - } tcp_conn->rx_hash.tfm =crypto_alloc_hash ("crc32c" ,0 ,CRYPTO_ALG_ASYNC ); tcp_conn->rx_hash.flags =0 ; -if (IS_ERR (tcp_conn->rx_hash.tfm)) { -printk (KERN_ERR "Could not create connection due to crc32c " -"loading error %ld. Make sure the crc32c module is " -"built as a module or into the kernel\n" , -PTR_ERR (tcp_conn->rx_hash.tfm)); +if (IS_ERR (tcp_conn->rx_hash.tfm)) goto free_tx_tfm; - }return cls_conn; free_tx_tfm:crypto_free_hash (tcp_conn->tx_hash.tfm); free_tcp_conn: +iscsi_conn_printk (KERN_ERR , conn, +"Could not create connection due to crc32c " +"loading error. Make sure the crc32c " +"module is built as a module or into the " +"kernel\n" );kfree (tcp_conn); tcp_conn_alloc_fail:iscsi_conn_teardown (cls_conn);
@@ -1627,7 +1629,8 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,/* lookup for existing socket */ sock =sockfd_lookup ((int )transport_eph, &err);if (!sock) { -printk (KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n" , err); +iscsi_conn_printk (KERN_ERR , conn, +"sockfd_lookup failed %d\n" , err);return -EEXIST ; }/*
drivers/scsi/libiscsi.c +43 -33
159 lines not on this page · raw message
drivers/scsi/scsi_transport_iscsi.c +30 -26
134 lines not on this page · raw message
include/scsi/libiscsi.h +7 -0
@@ -344,6 +344,10 @@ extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session,#define session_to_cls (_sess) \ hostdata_session(_sess->host->hostdata) +#define iscsi_session_printk(prefix, _sess, fmt, a...) \ + iscsi_cls_session_printk(prefix, \ + (struct iscsi_cls_session *)session_to_cls(_sess), fmt, ##a) +/* * connection management */
@@ -358,6 +362,9 @@ extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err);extern int iscsi_conn_get_param (struct iscsi_cls_conn *cls_conn,enum iscsi_param param,char *buf); +#define iscsi_conn_printk(prefix, _c, fmt, a...) \ + iscsi_cls_conn_printk(prefix, _c->cls_conn, fmt, ##a) +/* * pdu and task processing */
include/scsi/scsi_transport_iscsi.h +6 -0
@@ -212,6 +212,12 @@ struct iscsi_host {/* * session and connection functions that can be used by HW iSCSI LLDs */ +#define iscsi_cls_session_printk(prefix, _cls_session, fmt, a...) \ + dev_printk(prefix, &(_cls_session)->dev, fmt, ##a) + +#define iscsi_cls_conn_printk(prefix, _cls_conn, fmt, a...) \ + dev_printk(prefix, &(_cls_conn)->dev, fmt, ##a) +extern int iscsi_session_chkready (struct iscsi_cls_session *session);extern struct iscsi_cls_session *iscsi_alloc_session (struct Scsi_Host *shost,struct iscsi_transport *transport);
Signature · 1 line
1.5.2.1
PATCH 11/12 libiscsi: fix session age rollover and remove cid encoding
From: Mike Christie <[email protected]>
The session age mask is only 4 bits, but session->age is 32. When it gets larger then 15 and we try to or the bits some bits get dropped and the check for session age in iscsi_verify_itt is useless.
The ISCSI_CID_MASK related bits are also useless since cid is always one.
--- drivers/scsi/libiscsi.c | 14 ++++---------- include/scsi/iscsi_proto.h | 4 ++-- include/scsi/libiscsi.h | 2 -- 3 files changed, 6 insertions(+), 14 deletions(-)
drivers/scsi/libiscsi.c +4 -10
@@ -160,7 +160,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) hdr->opcode =ISCSI_OP_SCSI_CMD ; hdr->flags =ISCSI_ATTR_SIMPLE ;int_to_scsilun (sc->device->lun, (struct scsi_lun *)hdr->lun); - hdr->itt =build_itt (ctask->itt, conn->id, session->age); + hdr->itt =build_itt (ctask->itt, session->age); hdr->data_length =cpu_to_be32 (scsi_bufflen (sc)); hdr->cmdsn =cpu_to_be32 (session->cmdsn); session->cmdsn++;
@@ -706,14 +706,6 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,return ISCSI_ERR_BAD_ITT ; } -if (((__force u32 )hdr->itt &ISCSI_CID_MASK ) != - (conn->id <<ISCSI_CID_SHIFT )) { -iscsi_conn_printk (KERN_ERR , conn, -"iscsi: received itt %x, expected " -"CID (%x)\n" , - (__force u32 )hdr->itt, conn->id); -return ISCSI_ERR_BAD_ITT ; - } itt =get_itt (hdr->itt); }else itt = ~0U ;
@@ -777,7 +769,7 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn,*/ nop->cmdsn =cpu_to_be32 (session->cmdsn);if (hdr->itt !=RESERVED_ITT ) { - hdr->itt =build_itt (mtask->itt, conn->id, session->age); + hdr->itt =build_itt (mtask->itt, session->age);/* * TODO: We always use immediate, so we never hit this. * If we start to send tmfs or nops as non-immediate then
@@ -2037,6 +2029,8 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) conn->stop_stage =0 ; conn->tmf_state =TMF_INITIAL ; session->age++; +if (session->age ==16 ) + session->age =0 ;break ;case STOP_CONN_TERM : conn->stop_stage =0 ;
include/scsi/iscsi_proto.h +2 -2
@@ -45,8 +45,8 @@/* initiator tags; opaque for target */ typedef uint32_t __bitwise__ itt_t;/* below makes sense only for initiator that created this tag */ -#define build_itt (itt, id, age) ((__force itt_t)\ - ((itt) | ((id) << ISCSI_CID_SHIFT) | ((age) << ISCSI_AGE_SHIFT))) +#define build_itt (itt, age) ((__force itt_t)\ + ((itt) | ((age) << ISCSI_AGE_SHIFT)))#define get_itt (itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK)#define RESERVED_ITT ((__force itt_t)0xffffffff)
include/scsi/libiscsi.h +0 -2
@@ -70,8 +70,6 @@ enum {#define ISCSI_SUSPEND_BIT 1#define ISCSI_ITT_MASK (0xfff) -#define ISCSI_CID_SHIFT 12 -#define ISCSI_CID_MASK (0xffff << ISCSI_CID_SHIFT)#define ISCSI_AGE_SHIFT 28#define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT)
Signature · 1 line
1.5.2.1
PATCH 12/12 bump iscsi version
From: Mike Christie <[email protected]>
Set iscsi version to 2.0-868
--- drivers/scsi/scsi_transport_iscsi.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +1 -1
@@ -33,7 +33,7 @@#define ISCSI_SESSION_ATTRS 19#define ISCSI_CONN_ATTRS 13#define ISCSI_HOST_ATTRS 4 -#define ISCSI_TRANSPORT_VERSION "2.0-867" +#define ISCSI_TRANSPORT_VERSION "2.0-868"struct iscsi_internal {int daemon_pid;
Signature · 1 line
1.5.2.1
RE: [PATCH 07/12] qla4xxx: add qla4xxx async scan support
In reply to [email protected]Quoted 44 lines · Mike Christie
qla4xxx has the old school startup/probe where it finds presetup sessions
in its flash and then attempts to log into them before returning from the
probe. This however, makes it very simple to add a iscsi class scan finished
helper which the driver can use.In future patches Dave or I will rip apart the driver to make it more like qla2xxx, but for now this is a very simple two line patch which fixes the problem of trying to figure out when the initial sessions are done being scanned.
Signed-off-by Mike Christie <[email protected]>--- drivers/scsi/qla4xxx/ql4_os.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)drivers/scsi/qla4xxx/ql4_os.c +2
-0@@ -89,6 +89,8 @@ static struct scsi_host_template qla4xxx_driver_template = { .slave_alloc = qla4xxx_slave_alloc, .slave_destroy = qla4xxx_slave_destroy, + .scan_finished = iscsi_scan_finished, + .this_id = -1, .cmd_per_lun = 3,drivers/scsi/qla4xxx/ql4_os.c +1
-1.use_clustering = ENABLE_CLUSTERING,@@ -1306,7 +1308,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->patch_number, ha->build_number); - +scsi_scan_host (host);return 0;
Quoted 3 lines
remove_host:Signature · 1 line
1.5.2.1
Acked by David Somayajulu <[email protected]>
RE: [PATCH 05/12] qla4xxx: fix recovery timer and session unblock race
In reply to [email protected]Quoted 53 lines · Mike Christie
If qla4xxx is resetting up a session and the recovery timer fires we do not want to just set it to dead, because the dpc thread could have just set it to online and is in the middle of resetting it up.
Signed-off-by Mike Christie <[email protected]>--- drivers/scsi/qla4xxx/ql4_os.c | 19 +++++++++++-------- 1 files changed, 11 insertions(+), 8 deletions(-)drivers/scsi/qla4xxx/ql4_os.c +0
-1@@ -124,16 +124,19 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) struct ddb_entry *ddb_entry = session->dd_data;struct scsi_qla_host *ha = ddb_entry->ha; - DEBUG2(printk("scsi%ld: %s: index [%d] port down retrycount of (%d) "
drivers/scsi/qla4xxx/ql4_os.c +0
-1- "secs exhausted, marking device DEAD.\n",
ha->host_no,drivers/scsi/qla4xxx/ql4_os.c +3
-3- __func__, ddb_entry->fw_ddb_index, - ha->port_down_retry_count)); +if (atomic_read (&ddb_entry->state) !=DDB_STATE_ONLINE ) { +atomic_set (&ddb_entry->state,DDB_STATE_DEAD ); -atomic_set (&ddb_entry->state,DDB_STATE_DEAD ); + DEBUG2(printk("scsi%ld: %s: index [%d] portdown retry count "
drivers/scsi/qla4xxx/ql4_os.c +1
-0+ "of (%d) secs exhausted, markingdevice DEAD.\n",
drivers/scsi/qla4xxx/ql4_os.c +1
-0+ ha->host_no, __func__,
ddb_entry->fw_ddb_index,drivers/scsi/qla4xxx/ql4_os.c +1
-1+ ha->port_down_retry_count)); - DEBUG2(printk("scsi%ld: %s: scheduling dpc routine -dpc flags = "
drivers/scsi/qla4xxx/ql4_os.c +1
-2- "0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); -queue_work (ha->dpc_thread, &ha->dpc_work); + DEBUG2(printk("scsi%ld: %s: scheduling dpcroutine - dpc "
drivers/scsi/qla4xxx/ql4_os.c +4
-0+"flags = 0x%lx\n" , + ha->host_no, __func__, ha->dpc_flags)); +queue_work (ha->dpc_thread, &ha->dpc_work); + } } static int qla4xxx_host_get_param(struct Scsi_Host *shost,Signature · 1 line
1.5.2.1
Acked by David Somayajulu <[email protected]>
RE: [PATCH 03/12] qla4xxx: have qla4xxx use iscsi class session state check ready
In reply to [email protected]Quoted 36 lines · Mike Christie
This has qla4xxx use the iscsi class's check ready function in the queue command function, so all iscsi drivers return the same error value for common problems.
Signed-off-by Mike Christie <[email protected]>--- drivers/scsi/qla4xxx/ql4_os.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-)drivers/scsi/qla4xxx/ql4_os.c +12
-0@@ -398,9 +398,21 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, {struct scsi_qla_host *ha =to_qla_host (cmd->device->host);struct ddb_entry *ddb_entry = cmd->device->hostdata; +struct iscsi_cls_session *sess = ddb_entry->sess;struct srb *srb;int rval; +if (!sess) { + cmd->result =DID_IMM_RETRY <<16 ; + goto qc_fail_command; + } + + rval =iscsi_session_chkready (sess); +if (rval) { + cmd->result = rval; + goto qc_fail_command; + } +if (atomic_read (&ddb_entry->state) !=DDB_STATE_ONLINE ) {if (atomic_read (&ddb_entry->state) ==DDB_STATE_DEAD ) {
Quoted 3 lines
cmd->result=DID_NO_CONNECT<< 16;Signature · 1 line
1.5.2.1
Acked by David Somayajulu <[email protected]>
RE: [PATCH 02/12] qla4xxx: have qla4xxx directly call iscsi recovery functions
In reply to [email protected]Quoted 115 lines · Mike Christie
Qla4xxx can just call the iscsi recovery functions directly. There is no need for userspace to do this for qla4xxx, because we do not use the mutex to iterate over devices anymore and
iscsi_block
/unblock_session can be called from interrupt context or the dpc thread.
And having userspace do this just creates uneeded headaches for qla4xxx root
situations where the session may experience problems. For example during the kernel shutdown the scsi layer wants to send sync caches, but at
this time userspace is not up (iscsid is not running), so we cannot recover from the problem.Signed-off-by Mike Christie <[email protected]>--- drivers/scsi/qla4xxx/ql4_init.c | 1 + drivers/scsi/qla4xxx/ql4_os.c | 40 +++----------------------------------- 2 files changed, 5 insertions(+), 36 deletions(-)drivers/scsi/qla4xxx/ql4_init.c +1
-0@@ -1306,6 +1306,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,atomic_set (&ddb_entry->relogin_timer,0 );clear_bit (DF_RELOGIN , &ddb_entry->flags);clear_bit (DF_NO_RELOGIN , &ddb_entry->flags); +iscsi_unblock_session (ddb_entry->sess);iscsi_session_event (ddb_entry->sess,ISCSI_KEVENT_CREATE_SESSION );drivers/scsi/qla4xxx/ql4_init.c +0
-0/* drivers/scsi/qla4xxx/ql4_os.c +0
-2@@ -63,8 +63,6 @@ static int qla4xxx_sess_get_param(structiscsi_cls_session *sess, enum iscsi_param param, char *buf);static int qla4xxx_host_get_param (struct Scsi_Host *shost,enum iscsi_host_param param,char *buf); -static void qla4xxx_conn_stop (struct iscsi_cls_conn *conn,int flag); -static int qla4xxx_conn_start (struct iscsi_cls_conn *conn); static void qla4xxx_recovery_timedout(struct
iscsi_cls_session*session);/*
drivers/scsi/qla4xxx/ql4_os.c +0
-34@@ -116,8 +114,6 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { .get_conn_param = qla4xxx_conn_get_param, .get_session_param = qla4xxx_sess_get_param, .get_host_param = qla4xxx_host_get_param, - .start_conn = qla4xxx_conn_start, - .stop_conn = qla4xxx_conn_stop, .session_recovery_timedout = qla4xxx_recovery_timedout, };@@ -140,38 +136,6 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) queue_work(ha->dpc_thread, &ha->dpc_work); } -static int qla4xxx_conn_start (struct iscsi_cls_conn *conn) -{ -struct iscsi_cls_session *session; -struct ddb_entry *ddb_entry; - - session =iscsi_dev_to_session (conn->dev.parent); - ddb_entry = session->dd_data; - -DEBUG2 (printk ("scsi%ld: %s: index [%d] starting conn\n" , - ddb_entry->ha->host_no, __func__, - ddb_entry->fw_ddb_index)); -iscsi_unblock_session (session); -return 0 ; -} - -static void qla4xxx_conn_stop (struct iscsi_cls_conn *conn,int flag) -{ -struct iscsi_cls_session *session; -struct ddb_entry *ddb_entry; - - session =iscsi_dev_to_session (conn->dev.parent); - ddb_entry = session->dd_data; - -DEBUG2 (printk ("scsi%ld: %s: index [%d] stopping conn\n" , - ddb_entry->ha->host_no, __func__, - ddb_entry->fw_ddb_index)); -if (flag ==STOP_CONN_RECOVER ) -iscsi_block_session (session); -else -printk (KERN_ERR "iscsi: invalid stop flag %d\n" , flag); -} - static int qla4xxx_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,char *buf)
{drivers/scsi/qla4xxx/ql4_os.c +3
-0@@ -308,6 +272,9 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)DEBUG2 (printk (KERN_ERR "Could not add connection.\n" ));return -ENOMEM ; } + +/* finally ready to go */ +iscsi_unblock_session (ddb_entry->sess);return 0 ; }
drivers/scsi/qla4xxx/ql4_os.c void qla4xxx_mark_device_missing(struct · line 337
Quoted 7 lines
drivers/scsi/qla4xxx/ql4_os.c +1
-0@@ -364,6 +331,7 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,DEBUG3 (printk ("scsi%d:%d:%d: index [%d] marked MISSING\n" , ha->host_no, ddb_entry->bus, ddb_entry->target, ddb_entry->fw_ddb_index)); +iscsi_block_session (ddb_entry->sess);iscsi_conn_error (ddb_entry->conn,ISCSI_ERR_CONN_FAILED ); }
Acked by David Somayajulu <[email protected]>