Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3d0e91f7ace12499c4b00088e9a6b1361e1bb0ca
Commit:     3d0e91f7ace12499c4b00088e9a6b1361e1bb0ca
Parent:     6c0a60ec52042ece8bf4904c91ac497188e8d70b
Author:     Brian King <[EMAIL PROTECTED]>
AuthorDate: Wed Jun 13 17:12:26 2007 -0500
Committer:  James Bottomley <[EMAIL PROTECTED]>
CommitDate: Sun Jun 17 15:52:53 2007 -0500

    [SCSI] ibmvscsi: Add eh_host_reset_handler
    
    Adds an eh_host_reset_handler to ibmvscsi which resets the connection
    to the vscsi server. This patch also adds a timer to internally
    issues commands to prevent client hangs in the case of a misbehaving
    server. Tested by modifying the VIOS such that it would occasionally
    drop one or more request in sequence.
    
    Signed-off-by: Brian King <[EMAIL PROTECTED]>
    Signed-off-by: James Bottomley <[EMAIL PROTECTED]>
---
 drivers/scsi/ibmvscsi/ibmvscsi.c |  136 +++++++++++++++++++++++++++++--------
 drivers/scsi/ibmvscsi/ibmvscsi.h |    1 +
 2 files changed, 107 insertions(+), 30 deletions(-)

diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index c63a26e..0a16972 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -509,6 +509,70 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
        return map_single_data(cmd, srp_cmd, dev);
 }
 
+/**
+ * purge_requests: Our virtual adapter just shut down.  purge any sent requests
+ * @hostdata:    the adapter
+ */
+static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
+{
+       struct srp_event_struct *tmp_evt, *pos;
+       unsigned long flags;
+
+       spin_lock_irqsave(hostdata->host->host_lock, flags);
+       list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
+               list_del(&tmp_evt->list);
+               del_timer(&tmp_evt->timer);
+               if (tmp_evt->cmnd) {
+                       tmp_evt->cmnd->result = (error_code << 16);
+                       unmap_cmd_data(&tmp_evt->iu.srp.cmd,
+                                      tmp_evt,
+                                      tmp_evt->hostdata->dev);
+                       if (tmp_evt->cmnd_done)
+                               tmp_evt->cmnd_done(tmp_evt->cmnd);
+               } else if (tmp_evt->done)
+                       tmp_evt->done(tmp_evt);
+               free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+       }
+       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+}
+
+/**
+ * ibmvscsi_reset_host - Reset the connection to the server
+ * @hostdata:  struct ibmvscsi_host_data to reset
+*/
+static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
+{
+       scsi_block_requests(hostdata->host);
+       atomic_set(&hostdata->request_limit, 0);
+
+       purge_requests(hostdata, DID_ERROR);
+       if ((ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata)) ||
+           (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0)) ||
+           (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
+               atomic_set(&hostdata->request_limit, -1);
+               dev_err(hostdata->dev, "error after reset\n");
+       }
+
+       scsi_unblock_requests(hostdata->host);
+}
+
+/**
+ * ibmvscsi_timeout - Internal command timeout handler
+ * @evt_struct:        struct srp_event_struct that timed out
+ *
+ * Called when an internally generated command times out
+*/
+static void ibmvscsi_timeout(struct srp_event_struct *evt_struct)
+{
+       struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+
+       dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n",
+               evt_struct->iu.srp.cmd.opcode);
+
+       ibmvscsi_reset_host(hostdata);
+}
+
+
 /* ------------------------------------------------------------
  * Routines for sending and receiving SRPs
  */
@@ -516,12 +580,14 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
  * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls 
send_crq()
  * @evt_struct:        evt_struct to be sent
  * @hostdata:  ibmvscsi_host_data of host
+ * @timeout:   timeout in seconds - 0 means do not time command
  *
  * Returns the value returned from ibmvscsi_send_crq(). (Zero for success)
  * Note that this routine assumes that host_lock is held for synchronization
 */
 static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
-                                  struct ibmvscsi_host_data *hostdata)
+                                  struct ibmvscsi_host_data *hostdata,
+                                  unsigned long timeout)
 {
        u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
        int request_status;
@@ -577,9 +643,18 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct 
*evt_struct,
         */
        list_add_tail(&evt_struct->list, &hostdata->sent);
 
+       init_timer(&evt_struct->timer);
+       if (timeout) {
+               evt_struct->timer.data = (unsigned long) evt_struct;
+               evt_struct->timer.expires = jiffies + (timeout * HZ);
+               evt_struct->timer.function = (void (*)(unsigned 
long))ibmvscsi_timeout;
+               add_timer(&evt_struct->timer);
+       }
+
        if ((rc =
             ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
                list_del(&evt_struct->list);
+               del_timer(&evt_struct->timer);
 
                dev_err(hostdata->dev, "send error %d\n", rc);
                atomic_inc(&hostdata->request_limit);
@@ -709,7 +784,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
                        offsetof(struct srp_indirect_buf, desc_list);
        }
 
-       return ibmvscsi_send_srp_event(evt_struct, hostdata);
+       return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
 }
 
 /* ------------------------------------------------------------
@@ -800,7 +875,7 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data 
*hostdata)
                return;
        }
        
-       if (ibmvscsi_send_srp_event(evt_struct, hostdata)) {
+       if (ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2)) {
                dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
                dma_unmap_single(hostdata->dev,
                                 addr,
@@ -889,7 +964,7 @@ static int send_srp_login(struct ibmvscsi_host_data 
*hostdata)
         */
        atomic_set(&hostdata->request_limit, 1);
 
-       rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+       rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
        spin_unlock_irqrestore(hostdata->host->host_lock, flags);
        dev_info(hostdata->dev, "sent SRP login\n");
        return rc;
@@ -969,7 +1044,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
 
        evt->sync_srp = &srp_rsp;
        init_completion(&evt->comp);
-       rsp_rc = ibmvscsi_send_srp_event(evt, hostdata);
+       rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
        spin_unlock_irqrestore(hostdata->host->host_lock, flags);
        if (rsp_rc != 0) {
                sdev_printk(KERN_ERR, cmd->device,
@@ -1077,7 +1152,7 @@ static int ibmvscsi_eh_device_reset_handler(struct 
scsi_cmnd *cmd)
 
        evt->sync_srp = &srp_rsp;
        init_completion(&evt->comp);
-       rsp_rc = ibmvscsi_send_srp_event(evt, hostdata);
+       rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
        spin_unlock_irqrestore(hostdata->host->host_lock, flags);
        if (rsp_rc != 0) {
                sdev_printk(KERN_ERR, cmd->device,
@@ -1133,32 +1208,30 @@ static int ibmvscsi_eh_device_reset_handler(struct 
scsi_cmnd *cmd)
 }
 
 /**
- * purge_requests: Our virtual adapter just shut down.  purge any sent requests
- * @hostdata:    the adapter
- */
-static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
+ * ibmvscsi_eh_host_reset_handler - Reset the connection to the server
+ * @cmd:       struct scsi_cmnd having problems
+*/
+static int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd)
 {
-       struct srp_event_struct *tmp_evt, *pos;
-       unsigned long flags;
+       unsigned long wait_switch = 0;
+       struct ibmvscsi_host_data *hostdata =
+               (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
 
-       spin_lock_irqsave(hostdata->host->host_lock, flags);
-       list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
-               list_del(&tmp_evt->list);
-               if (tmp_evt->cmnd) {
-                       tmp_evt->cmnd->result = (error_code << 16);
-                       unmap_cmd_data(&tmp_evt->iu.srp.cmd, 
-                                      tmp_evt, 
-                                      tmp_evt->hostdata->dev);
-                       if (tmp_evt->cmnd_done)
-                               tmp_evt->cmnd_done(tmp_evt->cmnd);
-               } else {
-                       if (tmp_evt->done) {
-                               tmp_evt->done(tmp_evt);
-                       }
-               }
-               free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+       dev_err(hostdata->dev, "Resetting connection due to error recovery\n");
+
+       ibmvscsi_reset_host(hostdata);
+
+       for (wait_switch = jiffies + (init_timeout * HZ);
+            time_before(jiffies, wait_switch) &&
+                    atomic_read(&hostdata->request_limit) < 2;) {
+
+               msleep(10);
        }
-       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
+       if (atomic_read(&hostdata->request_limit) <= 0)
+               return FAILED;
+
+       return SUCCESS;
 }
 
 /**
@@ -1258,6 +1331,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta,
                           &hostdata->request_limit);
 
+       del_timer(&evt_struct->timer);
+
        if (evt_struct->done)
                evt_struct->done(evt_struct);
        else
@@ -1313,7 +1388,7 @@ static int ibmvscsi_do_host_config(struct 
ibmvscsi_host_data *hostdata,
        }
 
        init_completion(&evt_struct->comp);
-       rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+       rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
        if (rc == 0)
                wait_for_completion(&evt_struct->comp);
        dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL);
@@ -1504,6 +1579,7 @@ static struct scsi_host_template driver_template = {
        .queuecommand = ibmvscsi_queuecommand,
        .eh_abort_handler = ibmvscsi_eh_abort_handler,
        .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
+       .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
        .slave_configure = ibmvscsi_slave_configure,
        .change_queue_depth = ibmvscsi_change_queue_depth,
        .cmd_per_lun = 16,
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 727ca7c..b19c2e2 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -70,6 +70,7 @@ struct srp_event_struct {
        union viosrp_iu iu;
        void (*cmnd_done) (struct scsi_cmnd *);
        struct completion comp;
+       struct timer_list timer;
        union viosrp_iu *sync_srp;
        struct srp_direct_buf *ext_list;
        dma_addr_t ext_list_token;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to