Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
[safe/jmp/linux-2.6] / drivers / scsi / ibmvscsi / ibmvscsi.c
index 78d46a9..74d07d1 100644 (file)
@@ -72,6 +72,7 @@
 #include <linux/delay.h>
 #include <asm/firmware.h>
 #include <asm/vio.h>
+#include <asm/firmware.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
@@ -88,6 +89,7 @@ static int max_id = 64;
 static int max_channel = 3;
 static int init_timeout = 5;
 static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
+static int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2;
 
 static struct scsi_transport_template *ibmvscsi_transport_template;
 
@@ -106,7 +108,7 @@ module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(max_channel, "Largest channel value");
 module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
-module_param_named(max_requests, max_requests, int, S_IRUGO | S_IWUSR);
+module_param_named(max_requests, max_requests, int, S_IRUGO);
 MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter");
 
 /* ------------------------------------------------------------
@@ -426,8 +428,10 @@ static int map_sg_data(struct scsi_cmnd *cmd,
                                           SG_ALL * sizeof(struct srp_direct_buf),
                                           &evt_struct->ext_list_token, 0);
                if (!evt_struct->ext_list) {
-                       sdev_printk(KERN_ERR, cmd->device,
-                                   "Can't allocate memory for indirect table\n");
+                       if (!firmware_has_feature(FW_FEATURE_CMO))
+                               sdev_printk(KERN_ERR, cmd->device,
+                                           "Can't allocate memory "
+                                           "for indirect table\n");
                        return 0;
                }
        }
@@ -686,7 +690,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,
@@ -730,6 +734,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;
@@ -738,11 +743,13 @@ 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)) {
-               sdev_printk(KERN_ERR, cmnd->device, "couldn't convert cmd to srp_cmd\n");
+               if (!firmware_has_feature(FW_FEATURE_CMO))
+                       sdev_printk(KERN_ERR, cmnd->device,
+                                   "couldn't convert cmd to srp_cmd\n");
                free_event_struct(&hostdata->pool, evt_struct);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
@@ -750,7 +757,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
        init_event_struct(evt_struct,
                          handle_cmd_rsp,
                          VIOSRP_SRP_FORMAT,
-                         cmnd->timeout_per_command/HZ);
+                         cmnd->request->timeout/HZ);
 
        evt_struct->cmnd = cmnd;
        evt_struct->cmnd_done = done;
@@ -853,8 +860,11 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
                                            sizeof(hostdata->madapter_info),
                                            DMA_BIDIRECTIONAL);
 
-       if (dma_mapping_error(req->buffer)) {
-               dev_err(hostdata->dev, "Unable to map request_buffer for adapter_info!\n");
+       if (dma_mapping_error(hostdata->dev, req->buffer)) {
+               if (!firmware_has_feature(FW_FEATURE_CMO))
+                       dev_err(hostdata->dev,
+                               "Unable to map request_buffer for "
+                               "adapter_info!\n");
                free_event_struct(&hostdata->pool, evt_struct);
                return;
        }
@@ -1051,7 +1061,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
        }
 
        sdev_printk(KERN_INFO, cmd->device,
-                    "aborting command. lun 0x%lx, tag 0x%lx\n",
+                    "aborting command. lun 0x%llx, tag 0x%llx\n",
                    (((u64) lun) << 48), (u64) found_evt);
 
        wait_for_completion(&evt->comp);
@@ -1072,7 +1082,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
        if (rsp_rc) {
                if (printk_ratelimit())
                        sdev_printk(KERN_WARNING, cmd->device,
-                                   "abort code %d for task tag 0x%lx\n",
+                                   "abort code %d for task tag 0x%llx\n",
                                    rsp_rc, tsk_mgmt->task_tag);
                return FAILED;
        }
@@ -1092,12 +1102,12 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
 
        if (found_evt == NULL) {
                spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-               sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%lx completed\n",
+               sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%llx completed\n",
                            tsk_mgmt->task_tag);
                return SUCCESS;
        }
 
-       sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%lx\n",
+       sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%llx\n",
                    tsk_mgmt->task_tag);
 
        cmd->result = (DID_ABORT << 16);
@@ -1172,7 +1182,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
                return FAILED;
        }
 
-       sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
+       sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%llx\n",
                    (((u64) lun) << 48));
 
        wait_for_completion(&evt->comp);
@@ -1193,7 +1203,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
        if (rsp_rc) {
                if (printk_ratelimit())
                        sdev_printk(KERN_WARNING, cmd->device,
-                                   "reset code %d for task tag 0x%lx\n",
+                                   "reset code %d for task tag 0x%llx\n",
                                    rsp_rc, tsk_mgmt->task_tag);
                return FAILED;
        }
@@ -1347,6 +1357,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
 
        del_timer(&evt_struct->timer);
 
+       if ((crq->status != VIOSRP_OK && crq->status != VIOSRP_OK2) && evt_struct->cmnd)
+               evt_struct->cmnd->result = DID_ERROR << 16;
        if (evt_struct->done)
                evt_struct->done(evt_struct);
        else
@@ -1396,8 +1408,10 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
                                                    length,
                                                    DMA_BIDIRECTIONAL);
 
-       if (dma_mapping_error(host_config->buffer)) {
-               dev_err(hostdata->dev, "dma_mapping error getting host config\n");
+       if (dma_mapping_error(hostdata->dev, host_config->buffer)) {
+               if (!firmware_has_feature(FW_FEATURE_CMO))
+                       dev_err(hostdata->dev,
+                               "dma_mapping error getting host config\n");
                free_event_struct(&hostdata->pool, evt_struct);
                return -1;
        }
@@ -1429,7 +1443,7 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
        spin_lock_irqsave(shost->host_lock, lock_flags);
        if (sdev->type == TYPE_DISK) {
                sdev->allow_restart = 1;
-               sdev->timeout = 60 * HZ;
+               blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
        }
        scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
        spin_unlock_irqrestore(shost->host_lock, lock_flags);
@@ -1456,9 +1470,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;
 
@@ -1467,7 +1482,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,
@@ -1475,10 +1490,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;
 
@@ -1487,7 +1503,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,
@@ -1495,10 +1511,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;
 
@@ -1507,7 +1524,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,
@@ -1515,9 +1532,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;
 
@@ -1526,7 +1544,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,
@@ -1534,9 +1552,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;
 
@@ -1544,7 +1563,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,
@@ -1552,9 +1571,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 */
@@ -1564,7 +1584,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,
@@ -1572,7 +1592,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,
@@ -1595,7 +1615,7 @@ static struct scsi_host_template driver_template = {
        .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,
+       .cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT,
        .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
        .this_id = -1,
        .sg_tablesize = SG_ALL,
@@ -1604,6 +1624,26 @@ static struct scsi_host_template driver_template = {
 };
 
 /**
+ * ibmvscsi_get_desired_dma - Calculate IO memory desired by the driver
+ *
+ * @vdev: struct vio_dev for the device whose desired IO mem is to be returned
+ *
+ * Return value:
+ *     Number of bytes of IO data the driver will need to perform well.
+ */
+static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
+{
+       /* iu_storage data allocated in initialize_event_pool */
+       unsigned long desired_io = max_events * sizeof(union viosrp_iu);
+
+       /* add io space for sg data */
+       desired_io += (IBMVSCSI_MAX_SECTORS_DEFAULT * 512 *
+                            IBMVSCSI_CMDS_PER_LUN_DEFAULT);
+
+       return desired_io;
+}
+
+/**
  * Called by bus code for each adapter
  */
 static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
@@ -1618,7 +1658,6 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 
        vdev->dev.driver_data = NULL;
 
-       driver_template.can_queue = max_requests;
        host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
        if (!host) {
                dev_err(&vdev->dev, "couldn't allocate host data\n");
@@ -1632,14 +1671,14 @@ 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 */
+       hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
 
-       rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests);
+       rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events);
        if (rc != 0 && rc != H_RESOURCE) {
                dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
                goto init_crq_failed;
        }
-       if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) {
+       if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) {
                dev_err(&vdev->dev, "couldn't initialize event pool\n");
                goto init_pool_failed;
        }
@@ -1691,7 +1730,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
       add_host_failed:
        release_event_pool(&hostdata->pool, hostdata);
       init_pool_failed:
-       ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_requests);
+       ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events);
       init_crq_failed:
        scsi_host_put(host);
       scsi_host_alloc_failed:
@@ -1703,7 +1742,7 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
        struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
        release_event_pool(&hostdata->pool, hostdata);
        ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
-                                       max_requests);
+                                       max_events);
 
        srp_remove_host(hostdata->host);
        scsi_remove_host(hostdata->host);
@@ -1726,6 +1765,7 @@ static struct vio_driver ibmvscsi_driver = {
        .id_table = ibmvscsi_device_table,
        .probe = ibmvscsi_probe,
        .remove = ibmvscsi_remove,
+       .get_desired_dma = ibmvscsi_get_desired_dma,
        .driver = {
                .name = "ibmvscsi",
                .owner = THIS_MODULE,
@@ -1739,6 +1779,10 @@ int __init ibmvscsi_module_init(void)
 {
        int ret;
 
+       /* Ensure we have two requests to do error recovery */
+       driver_template.can_queue = max_requests;
+       max_events = max_requests + 2;
+
        if (firmware_has_feature(FW_FEATURE_ISERIES))
                ibmvscsi_ops = &iseriesvscsi_ops;
        else if (firmware_has_feature(FW_FEATURE_VIO))