[SCSI] Let scsi_cmnd->cmnd use request->cmd buffer
[linux-block.git] / drivers / scsi / ibmvscsi / ibmvscsi.c
index 5f2396c03958924393864718485d1de683bda6b1..ccfd8aca3765875cf7cf4711aba0aa8bfbb6fb09 100644 (file)
@@ -629,6 +629,16 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
                list_del(&evt_struct->list);
                del_timer(&evt_struct->timer);
 
+               /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
+                * Firmware will send a CRQ with a transport event (0xFF) to
+                * tell this client what has happened to the transport.  This
+                * will be handled in ibmvscsi_handle_crq()
+                */
+               if (rc == H_CLOSED) {
+                       dev_warn(hostdata->dev, "send warning. "
+                                "Receive queue closed, will retry.\n");
+                       goto send_busy;
+               }
                dev_err(hostdata->dev, "send error %d\n", rc);
                atomic_inc(&hostdata->request_limit);
                goto send_error;
@@ -676,7 +686,7 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
        }
        
        if (cmnd) {
-               cmnd->result = rsp->status;
+               cmnd->result |= rsp->status;
                if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
                        memcpy(cmnd->sense_buffer,
                               rsp->data,
@@ -720,6 +730,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
        u16 lun = lun_from_dev(cmnd->device);
        u8 out_fmt, in_fmt;
 
+       cmnd->result = (DID_OK << 16);
        evt_struct = get_event_struct(&hostdata->pool);
        if (!evt_struct)
                return SCSI_MLQUEUE_HOST_BUSY;
@@ -728,7 +739,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
        srp_cmd = &evt_struct->iu.srp.cmd;
        memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
        srp_cmd->opcode = SRP_CMD;
-       memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
+       memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
        srp_cmd->lun = ((u64) lun) << 48;
 
        if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
@@ -976,58 +987,74 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
        int rsp_rc;
        unsigned long flags;
        u16 lun = lun_from_dev(cmd->device);
+       unsigned long wait_switch = 0;
 
        /* First, find this command in our sent list so we can figure
         * out the correct tag
         */
        spin_lock_irqsave(hostdata->host->host_lock, flags);
-       found_evt = NULL;
-       list_for_each_entry(tmp_evt, &hostdata->sent, list) {
-               if (tmp_evt->cmnd == cmd) {
-                       found_evt = tmp_evt;
-                       break;
+       wait_switch = jiffies + (init_timeout * HZ);
+       do {
+               found_evt = NULL;
+               list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+                       if (tmp_evt->cmnd == cmd) {
+                               found_evt = tmp_evt;
+                               break;
+                       }
                }
-       }
 
-       if (!found_evt) {
-               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-               return SUCCESS;
-       }
+               if (!found_evt) {
+                       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+                       return SUCCESS;
+               }
 
-       evt = get_event_struct(&hostdata->pool);
-       if (evt == NULL) {
-               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-               sdev_printk(KERN_ERR, cmd->device, "failed to allocate abort event\n");
-               return FAILED;
-       }
+               evt = get_event_struct(&hostdata->pool);
+               if (evt == NULL) {
+                       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+                       sdev_printk(KERN_ERR, cmd->device,
+                               "failed to allocate abort event\n");
+                       return FAILED;
+               }
        
-       init_event_struct(evt,
-                         sync_completion,
-                         VIOSRP_SRP_FORMAT,
-                         init_timeout);
+               init_event_struct(evt,
+                                 sync_completion,
+                                 VIOSRP_SRP_FORMAT,
+                                 init_timeout);
 
-       tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+               tsk_mgmt = &evt->iu.srp.tsk_mgmt;
        
-       /* Set up an abort SRP command */
-       memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
-       tsk_mgmt->opcode = SRP_TSK_MGMT;
-       tsk_mgmt->lun = ((u64) lun) << 48;
-       tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
-       tsk_mgmt->task_tag = (u64) found_evt;
-
-       sdev_printk(KERN_INFO, cmd->device, "aborting command. lun 0x%lx, tag 0x%lx\n",
-                   tsk_mgmt->lun, tsk_mgmt->task_tag);
-
-       evt->sync_srp = &srp_rsp;
-       init_completion(&evt->comp);
-       rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+               /* Set up an abort SRP command */
+               memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+               tsk_mgmt->opcode = SRP_TSK_MGMT;
+               tsk_mgmt->lun = ((u64) lun) << 48;
+               tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
+               tsk_mgmt->task_tag = (u64) found_evt;
+
+               evt->sync_srp = &srp_rsp;
+
+               init_completion(&evt->comp);
+               rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+
+               if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
+                       break;
+
+               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+               msleep(10);
+               spin_lock_irqsave(hostdata->host->host_lock, flags);
+       } while (time_before(jiffies, wait_switch));
+
        spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
        if (rsp_rc != 0) {
                sdev_printk(KERN_ERR, cmd->device,
                            "failed to send abort() event. rc=%d\n", rsp_rc);
                return FAILED;
        }
 
+       sdev_printk(KERN_INFO, cmd->device,
+                    "aborting command. lun 0x%lx, tag 0x%lx\n",
+                   (((u64) lun) << 48), (u64) found_evt);
+
        wait_for_completion(&evt->comp);
 
        /* make sure we got a good response */
@@ -1099,41 +1126,56 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
        int rsp_rc;
        unsigned long flags;
        u16 lun = lun_from_dev(cmd->device);
+       unsigned long wait_switch = 0;
 
        spin_lock_irqsave(hostdata->host->host_lock, flags);
-       evt = get_event_struct(&hostdata->pool);
-       if (evt == NULL) {
-               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-               sdev_printk(KERN_ERR, cmd->device, "failed to allocate reset event\n");
-               return FAILED;
-       }
+       wait_switch = jiffies + (init_timeout * HZ);
+       do {
+               evt = get_event_struct(&hostdata->pool);
+               if (evt == NULL) {
+                       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+                       sdev_printk(KERN_ERR, cmd->device,
+                               "failed to allocate reset event\n");
+                       return FAILED;
+               }
        
-       init_event_struct(evt,
-                         sync_completion,
-                         VIOSRP_SRP_FORMAT,
-                         init_timeout);
+               init_event_struct(evt,
+                                 sync_completion,
+                                 VIOSRP_SRP_FORMAT,
+                                 init_timeout);
 
-       tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+               tsk_mgmt = &evt->iu.srp.tsk_mgmt;
 
-       /* Set up a lun reset SRP command */
-       memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
-       tsk_mgmt->opcode = SRP_TSK_MGMT;
-       tsk_mgmt->lun = ((u64) lun) << 48;
-       tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
+               /* Set up a lun reset SRP command */
+               memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+               tsk_mgmt->opcode = SRP_TSK_MGMT;
+               tsk_mgmt->lun = ((u64) lun) << 48;
+               tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
 
-       sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
-                   tsk_mgmt->lun);
+               evt->sync_srp = &srp_rsp;
+
+               init_completion(&evt->comp);
+               rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+
+               if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
+                       break;
+
+               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+               msleep(10);
+               spin_lock_irqsave(hostdata->host->host_lock, flags);
+       } while (time_before(jiffies, wait_switch));
 
-       evt->sync_srp = &srp_rsp;
-       init_completion(&evt->comp);
-       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,
                            "failed to send reset event. rc=%d\n", rsp_rc);
                return FAILED;
        }
 
+       sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
+                   (((u64) lun) << 48));
+
        wait_for_completion(&evt->comp);
 
        /* make sure we got a good response */
@@ -1306,6 +1348,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
 
        del_timer(&evt_struct->timer);
 
+       if (crq->status != VIOSRP_OK && evt_struct->cmnd)
+               evt_struct->cmnd->result = DID_ERROR << 16;
        if (evt_struct->done)
                evt_struct->done(evt_struct);
        else
@@ -1386,8 +1430,10 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
        unsigned long lock_flags = 0;
 
        spin_lock_irqsave(shost->host_lock, lock_flags);
-       if (sdev->type == TYPE_DISK)
+       if (sdev->type == TYPE_DISK) {
                sdev->allow_restart = 1;
+               sdev->timeout = 60 * HZ;
+       }
        scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
        spin_unlock_irqrestore(shost->host_lock, lock_flags);
        return 0;
@@ -1413,9 +1459,10 @@ static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
 /* ------------------------------------------------------------
  * sysfs attributes
  */
-static ssize_t show_host_srp_version(struct class_device *class_dev, char *buf)
+static ssize_t show_host_srp_version(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct Scsi_Host *shost = class_to_shost(dev);
        struct ibmvscsi_host_data *hostdata = shost_priv(shost);
        int len;
 
@@ -1424,7 +1471,7 @@ static ssize_t show_host_srp_version(struct class_device *class_dev, char *buf)
        return len;
 }
 
-static struct class_device_attribute ibmvscsi_host_srp_version = {
+static struct device_attribute ibmvscsi_host_srp_version = {
        .attr = {
                 .name = "srp_version",
                 .mode = S_IRUGO,
@@ -1432,10 +1479,11 @@ static struct class_device_attribute ibmvscsi_host_srp_version = {
        .show = show_host_srp_version,
 };
 
-static ssize_t show_host_partition_name(struct class_device *class_dev,
+static ssize_t show_host_partition_name(struct device *dev,
+                                       struct device_attribute *attr,
                                        char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct Scsi_Host *shost = class_to_shost(dev);
        struct ibmvscsi_host_data *hostdata = shost_priv(shost);
        int len;
 
@@ -1444,7 +1492,7 @@ static ssize_t show_host_partition_name(struct class_device *class_dev,
        return len;
 }
 
-static struct class_device_attribute ibmvscsi_host_partition_name = {
+static struct device_attribute ibmvscsi_host_partition_name = {
        .attr = {
                 .name = "partition_name",
                 .mode = S_IRUGO,
@@ -1452,10 +1500,11 @@ static struct class_device_attribute ibmvscsi_host_partition_name = {
        .show = show_host_partition_name,
 };
 
-static ssize_t show_host_partition_number(struct class_device *class_dev,
+static ssize_t show_host_partition_number(struct device *dev,
+                                         struct device_attribute *attr,
                                          char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct Scsi_Host *shost = class_to_shost(dev);
        struct ibmvscsi_host_data *hostdata = shost_priv(shost);
        int len;
 
@@ -1464,7 +1513,7 @@ static ssize_t show_host_partition_number(struct class_device *class_dev,
        return len;
 }
 
-static struct class_device_attribute ibmvscsi_host_partition_number = {
+static struct device_attribute ibmvscsi_host_partition_number = {
        .attr = {
                 .name = "partition_number",
                 .mode = S_IRUGO,
@@ -1472,9 +1521,10 @@ static struct class_device_attribute ibmvscsi_host_partition_number = {
        .show = show_host_partition_number,
 };
 
-static ssize_t show_host_mad_version(struct class_device *class_dev, char *buf)
+static ssize_t show_host_mad_version(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct Scsi_Host *shost = class_to_shost(dev);
        struct ibmvscsi_host_data *hostdata = shost_priv(shost);
        int len;
 
@@ -1483,7 +1533,7 @@ static ssize_t show_host_mad_version(struct class_device *class_dev, char *buf)
        return len;
 }
 
-static struct class_device_attribute ibmvscsi_host_mad_version = {
+static struct device_attribute ibmvscsi_host_mad_version = {
        .attr = {
                 .name = "mad_version",
                 .mode = S_IRUGO,
@@ -1491,9 +1541,10 @@ static struct class_device_attribute ibmvscsi_host_mad_version = {
        .show = show_host_mad_version,
 };
 
-static ssize_t show_host_os_type(struct class_device *class_dev, char *buf)
+static ssize_t show_host_os_type(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct Scsi_Host *shost = class_to_shost(dev);
        struct ibmvscsi_host_data *hostdata = shost_priv(shost);
        int len;
 
@@ -1501,7 +1552,7 @@ static ssize_t show_host_os_type(struct class_device *class_dev, char *buf)
        return len;
 }
 
-static struct class_device_attribute ibmvscsi_host_os_type = {
+static struct device_attribute ibmvscsi_host_os_type = {
        .attr = {
                 .name = "os_type",
                 .mode = S_IRUGO,
@@ -1509,9 +1560,10 @@ static struct class_device_attribute ibmvscsi_host_os_type = {
        .show = show_host_os_type,
 };
 
-static ssize_t show_host_config(struct class_device *class_dev, char *buf)
+static ssize_t show_host_config(struct device *dev,
+                               struct device_attribute *attr, char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct Scsi_Host *shost = class_to_shost(dev);
        struct ibmvscsi_host_data *hostdata = shost_priv(shost);
 
        /* returns null-terminated host config data */
@@ -1521,7 +1573,7 @@ static ssize_t show_host_config(struct class_device *class_dev, char *buf)
                return 0;
 }
 
-static struct class_device_attribute ibmvscsi_host_config = {
+static struct device_attribute ibmvscsi_host_config = {
        .attr = {
                 .name = "config",
                 .mode = S_IRUGO,
@@ -1529,7 +1581,7 @@ static struct class_device_attribute ibmvscsi_host_config = {
        .show = show_host_config,
 };
 
-static struct class_device_attribute *ibmvscsi_attrs[] = {
+static struct device_attribute *ibmvscsi_attrs[] = {
        &ibmvscsi_host_srp_version,
        &ibmvscsi_host_partition_name,
        &ibmvscsi_host_partition_number,
@@ -1557,7 +1609,6 @@ static struct scsi_host_template driver_template = {
        .this_id = -1,
        .sg_tablesize = SG_ALL,
        .use_clustering = ENABLE_CLUSTERING,
-       .use_sg_chaining = ENABLE_SG_CHAINING,
        .shost_attrs = ibmvscsi_attrs,
 };