vserver 1.9.5.x5
[linux-2.6.git] / drivers / scsi / ibmvscsi / ibmvscsi.c
index 210ee7d..e89f76e 100644 (file)
@@ -69,6 +69,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
+#include <linux/delay.h>
 #include <asm/vio.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -86,7 +87,7 @@ static int max_channel = 3;
 static int init_timeout = 5;
 static int max_requests = 50;
 
-#define IBMVSCSI_VERSION "1.5.1"
+#define IBMVSCSI_VERSION "1.5.5"
 
 MODULE_DESCRIPTION("IBM Virtual SCSI");
 MODULE_AUTHOR("Dave Boutcher");
@@ -255,6 +256,7 @@ static void init_event_struct(struct srp_event_struct *evt_struct,
 {
        evt_struct->cmnd = NULL;
        evt_struct->cmnd_done = NULL;
+       evt_struct->sync_srp = NULL;
        evt_struct->crq.format = format;
        evt_struct->crq.timeout = timeout;
        evt_struct->done = done;
@@ -466,7 +468,7 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
 static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
                                   struct ibmvscsi_host_data *hostdata)
 {
-       struct scsi_cmnd *cmnd = evt_struct->cmnd;
+       struct scsi_cmnd *cmnd;
        u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
        int rc;
 
@@ -478,22 +480,15 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
        if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) &&
            (atomic_dec_if_positive(&hostdata->request_limit) < 0)) {
                /* See if the adapter is disabled */
-               if (atomic_read(&hostdata->request_limit) < 0) {
-                       if (cmnd)
-                               cmnd->result = DID_ERROR << 16;
-                       if (evt_struct->cmnd_done)
-                               evt_struct->cmnd_done(cmnd);
-                       unmap_cmd_data(&evt_struct->iu.srp.cmd,
-                                      hostdata->dev);
-                       free_event_struct(&hostdata->pool, evt_struct);
-                       return 0;
-               } else {
-                       printk("ibmvscsi: Warning, request_limit exceeded\n");
-                       unmap_cmd_data(&evt_struct->iu.srp.cmd,
-                                      hostdata->dev);
-                       free_event_struct(&hostdata->pool, evt_struct);
-                       return SCSI_MLQUEUE_HOST_BUSY;
-               }
+               if (atomic_read(&hostdata->request_limit) < 0)
+                       goto send_error;
+       
+               printk(KERN_WARNING 
+                      "ibmvscsi: Warning, request_limit exceeded\n");
+               unmap_cmd_data(&evt_struct->iu.srp.cmd,
+                              hostdata->dev);
+               free_event_struct(&hostdata->pool, evt_struct);
+               return SCSI_MLQUEUE_HOST_BUSY;
        }
 
        /* Copy the IU into the transfer area */
@@ -510,18 +505,24 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
             ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
                list_del(&evt_struct->list);
 
-               cmnd = evt_struct->cmnd;
                printk(KERN_ERR "ibmvscsi: failed to send event struct rc %d\n",
                       rc);
-               unmap_cmd_data(&evt_struct->iu.srp.cmd, hostdata->dev);
-               free_event_struct(&hostdata->pool, evt_struct);
-               if (cmnd)
-                       cmnd->result = DID_ERROR << 16;
-               if (evt_struct->cmnd_done)
-                       evt_struct->cmnd_done(cmnd);
+               goto send_error;
        }
 
        return 0;
+
+ send_error:
+       unmap_cmd_data(&evt_struct->iu.srp.cmd, hostdata->dev);
+
+       if ((cmnd = evt_struct->cmnd) != NULL) {
+               cmnd->result = DID_ERROR << 16;
+               evt_struct->cmnd_done(cmnd);
+       } else if (evt_struct->done)
+               evt_struct->done(evt_struct);
+       
+       free_event_struct(&hostdata->pool, evt_struct);
+       return 0;
 }
 
 /**
@@ -536,6 +537,13 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
        struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp;
        struct scsi_cmnd *cmnd = evt_struct->cmnd;
 
+       if (unlikely(rsp->type != SRP_RSP_TYPE)) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING 
+                              "ibmvscsi: bad SRP RSP type %d\n",
+                              rsp->type);
+       }
+       
        if (cmnd) {
                cmnd->result = rsp->status;
                if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
@@ -640,11 +648,16 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
                       evt_struct->xfer_iu->mad.adapter_info.common.status);
        } else {
                printk("ibmvscsi: host srp version: %s, "
-                      "host partition %s (%d), OS %d\n",
+                      "host partition %s (%d), OS %d, max io %u\n",
                       hostdata->madapter_info.srp_version,
                       hostdata->madapter_info.partition_name,
                       hostdata->madapter_info.partition_number,
-                      hostdata->madapter_info.os_type);
+                      hostdata->madapter_info.os_type,
+                      hostdata->madapter_info.port_max_txu[0]);
+               
+               if (hostdata->madapter_info.port_max_txu[0]) 
+                       hostdata->host->max_sectors = 
+                               hostdata->madapter_info.port_max_txu[0] >> 9;
        }
 }
 
@@ -795,6 +808,10 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
  */
 static void sync_completion(struct srp_event_struct *evt_struct)
 {
+       /* copy the response back */
+       if (evt_struct->sync_srp)
+               *evt_struct->sync_srp = *evt_struct->xfer_iu;
+       
        complete(&evt_struct->comp);
 }
 
@@ -809,6 +826,8 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
        struct srp_tsk_mgmt *tsk_mgmt;
        struct srp_event_struct *evt;
        struct srp_event_struct *tmp_evt, *found_evt;
+       union viosrp_iu srp_rsp;
+       int rsp_rc;
        u16 lun = lun_from_dev(cmd->device);
 
        /* First, find this command in our sent list so we can figure
@@ -848,6 +867,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
        printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n",
               tsk_mgmt->lun, tsk_mgmt->managed_task_tag);
 
+       evt->sync_srp = &srp_rsp;
        init_completion(&evt->comp);
        if (ibmvscsi_send_srp_event(evt, hostdata) != 0) {
                printk(KERN_ERR "ibmvscsi: failed to send abort() event\n");
@@ -858,6 +878,29 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
        wait_for_completion(&evt->comp);
        spin_lock_irq(hostdata->host->host_lock);
 
+       /* make sure we got a good response */
+       if (unlikely(srp_rsp.srp.generic.type != SRP_RSP_TYPE)) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING 
+                              "ibmvscsi: abort bad SRP RSP type %d\n",
+                              srp_rsp.srp.generic.type);
+               return FAILED;
+       }
+
+       if (srp_rsp.srp.rsp.rspvalid)
+               rsp_rc = *((int *)srp_rsp.srp.rsp.sense_and_response_data);
+       else
+               rsp_rc = srp_rsp.srp.rsp.status;
+
+       if (rsp_rc) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING 
+                      "ibmvscsi: abort code %d for task tag 0x%lx\n",
+                              rsp_rc,
+                              tsk_mgmt->managed_task_tag);
+               return FAILED;
+       }
+
        /* Because we dropped the spinlock above, it's possible
         * The event is no longer in our list.  Make sure it didn't
         * complete while we were aborting
@@ -870,13 +913,17 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
                }
        }
 
+       if (found_evt == NULL) {
+               printk(KERN_INFO
+                      "ibmvscsi: aborted task tag 0x%lx completed\n",
+                      tsk_mgmt->managed_task_tag);
+               return SUCCESS;
+       }
+
        printk(KERN_INFO
               "ibmvscsi: successfully aborted task tag 0x%lx\n",
               tsk_mgmt->managed_task_tag);
 
-       if (found_evt == NULL)
-               return SUCCESS;
-
        cmd->result = (DID_ABORT << 16);
        list_del(&found_evt->list);
        unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev);
@@ -898,6 +945,8 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
        struct srp_tsk_mgmt *tsk_mgmt;
        struct srp_event_struct *evt;
        struct srp_event_struct *tmp_evt, *pos;
+       union viosrp_iu srp_rsp;
+       int rsp_rc;
        u16 lun = lun_from_dev(cmd->device);
 
        evt = get_event_struct(&hostdata->pool);
@@ -922,6 +971,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
        printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n",
               tsk_mgmt->lun);
 
+       evt->sync_srp = &srp_rsp;
        init_completion(&evt->comp);
        if (ibmvscsi_send_srp_event(evt, hostdata) != 0) {
                printk(KERN_ERR "ibmvscsi: failed to send reset event\n");
@@ -932,6 +982,29 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
        wait_for_completion(&evt->comp);
        spin_lock_irq(hostdata->host->host_lock);
 
+       /* make sure we got a good response */
+       if (unlikely(srp_rsp.srp.generic.type != SRP_RSP_TYPE)) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING 
+                              "ibmvscsi: reset bad SRP RSP type %d\n",
+                              srp_rsp.srp.generic.type);
+               return FAILED;
+       }
+
+       if (srp_rsp.srp.rsp.rspvalid)
+               rsp_rc = *((int *)srp_rsp.srp.rsp.sense_and_response_data);
+       else
+               rsp_rc = srp_rsp.srp.rsp.status;
+
+       if (rsp_rc) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING 
+                              "ibmvscsi: reset code %d for task tag 0x%lx\n",
+                      rsp_rc,
+                              tsk_mgmt->managed_task_tag);
+               return FAILED;
+       }
+
        /* We need to find all commands for this LUN that have not yet been
         * responded to, and fail them with DID_RESET
         */
@@ -1047,6 +1120,13 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                return;
        }
 
+       if (atomic_read(&evt_struct->free)) {
+               printk(KERN_ERR
+                      "ibmvscsi: received duplicate  correlation_token 0x%p!\n",
+                      (void *)crq->IU_data_ptr);
+               return;
+       }
+
        if (crq->format == VIOSRP_SRP_FORMAT)
                atomic_add(evt_struct->xfer_iu->srp.rsp.request_limit_delta,
                           &hostdata->request_limit);
@@ -1294,6 +1374,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        hostdata->host = host;
        hostdata->dev = dev;
        atomic_set(&hostdata->request_limit, -1);
+       hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */
 
        if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata,
                                    max_requests) != 0) {
@@ -1325,10 +1406,9 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
                 */
                for (wait_switch = jiffies + (init_timeout * HZ);
                     time_before(jiffies, wait_switch) &&
-                    atomic_read(&hostdata->request_limit) < 0;) {
+                    atomic_read(&hostdata->request_limit) < 2;) {
 
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(HZ / 100);
+                       msleep(10);
                }
 
                /* if we now have a valid request_limit, initiate a scan */