[SCSI] Fix ibmvscsi client for multiplatform iSeries+pSeries kernel
authorDavid Woodhouse <dwmw2@infradead.org>
Fri, 21 Sep 2007 22:29:36 +0000 (08:29 +1000)
committerJames Bottomley <jejb@mulgrave.localdomain>
Fri, 12 Oct 2007 18:49:26 +0000 (14:49 -0400)
If you build a multiplatform kernel for iSeries and pSeries, with
ibmvscsic support, the resulting client doesn't work on iSeries.

This fixes that, using the appropriate low-level operations
for the machine detected at runtime.

[jejb: fixed up rejections around the srp transport patch]

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Acked by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
drivers/scsi/ibmvscsi/Makefile
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvscsi.h
drivers/scsi/ibmvscsi/iseries_vscsi.c
drivers/scsi/ibmvscsi/rpa_vscsi.c

index f67d9efc7a99abe8c4c5e8a16ab09e0acf866610..6ac0633d5452af8c36a0683653485980335950e3 100644 (file)
@@ -1,9 +1,7 @@
 obj-$(CONFIG_SCSI_IBMVSCSI)    += ibmvscsic.o
 
 ibmvscsic-y                    += ibmvscsi.o
-ifndef CONFIG_PPC_PSERIES
 ibmvscsic-$(CONFIG_PPC_ISERIES)        += iseries_vscsi.o 
-endif
 ibmvscsic-$(CONFIG_PPC_PSERIES)        += rpa_vscsi.o 
 
 obj-$(CONFIG_SCSI_IBMVSCSIS)   += ibmvstgt.o
index 93bd01b1e4b50a0f6238e161f14f200073ff01e2..cda0cc3d182fde457f4b15259d8a10eb476489af 100644 (file)
@@ -70,6 +70,7 @@
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <asm/firmware.h>
 #include <asm/vio.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -92,6 +93,8 @@ static struct scsi_transport_template *ibmvscsi_transport_template;
 
 #define IBMVSCSI_VERSION "1.5.8"
 
+static struct ibmvscsi_ops *ibmvscsi_ops;
+
 MODULE_DESCRIPTION("IBM Virtual SCSI");
 MODULE_AUTHOR("Dave Boutcher");
 MODULE_LICENSE("GPL");
@@ -509,8 +512,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
        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)) ||
+       if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) ||
+           (ibmvscsi_ops->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");
@@ -615,7 +618,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
        }
 
        if ((rc =
-            ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
+            ibmvscsi_ops->send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
                list_del(&evt_struct->list);
                del_timer(&evt_struct->timer);
 
@@ -1214,8 +1217,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                case 0x01:      /* Initialization message */
                        dev_info(hostdata->dev, "partner initialized\n");
                        /* Send back a response */
-                       if ((rc = ibmvscsi_send_crq(hostdata,
-                                                   0xC002000000000000LL, 0)) == 0) {
+                       if ((rc = ibmvscsi_ops->send_crq(hostdata,
+                                                        0xC002000000000000LL, 0)) == 0) {
                                /* Now login */
                                send_srp_login(hostdata);
                        } else {
@@ -1240,10 +1243,10 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                        /* We need to re-setup the interpartition connection */
                        dev_info(hostdata->dev, "Re-enabling adapter!\n");
                        purge_requests(hostdata, DID_REQUEUE);
-                       if ((ibmvscsi_reenable_crq_queue(&hostdata->queue,
-                                                       hostdata)) ||
-                           (ibmvscsi_send_crq(hostdata,
-                                              0xC001000000000000LL, 0))) {
+                       if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue,
+                                                             hostdata)) ||
+                           (ibmvscsi_ops->send_crq(hostdata,
+                                                   0xC001000000000000LL, 0))) {
                                        atomic_set(&hostdata->request_limit,
                                                   -1);
                                        dev_err(hostdata->dev, "error after enable\n");
@@ -1253,10 +1256,10 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                                crq->format);
 
                        purge_requests(hostdata, DID_ERROR);
-                       if ((ibmvscsi_reset_crq_queue(&hostdata->queue,
-                                                       hostdata)) ||
-                           (ibmvscsi_send_crq(hostdata,
-                                              0xC001000000000000LL, 0))) {
+                       if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue,
+                                                          hostdata)) ||
+                           (ibmvscsi_ops->send_crq(hostdata,
+                                                   0xC001000000000000LL, 0))) {
                                        atomic_set(&hostdata->request_limit,
                                                   -1);
                                        dev_err(hostdata->dev, "error after reset\n");
@@ -1579,7 +1582,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        atomic_set(&hostdata->request_limit, -1);
        hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */
 
-       rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests);
+       rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests);
        if (rc != 0 && rc != H_RESOURCE) {
                dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
                goto init_crq_failed;
@@ -1608,7 +1611,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
         * to fail if the other end is not acive.  In that case we don't
         * want to scan
         */
-       if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0
+       if (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0) == 0
            || rc == H_RESOURCE) {
                /*
                 * Wait around max init_timeout secs for the adapter to finish
@@ -1636,7 +1639,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_release_crq_queue(&hostdata->queue, hostdata, max_requests);
+       ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_requests);
       init_crq_failed:
        scsi_host_put(host);
       scsi_host_alloc_failed:
@@ -1647,8 +1650,8 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
 {
        struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
        release_event_pool(&hostdata->pool, hostdata);
-       ibmvscsi_release_crq_queue(&hostdata->queue, hostdata,
-                                  max_requests);
+       ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
+                                       max_requests);
 
        srp_remove_host(hostdata->host);
        scsi_remove_host(hostdata->host);
@@ -1684,6 +1687,13 @@ int __init ibmvscsi_module_init(void)
 {
        int ret;
 
+       if (firmware_has_feature(FW_FEATURE_ISERIES))
+               ibmvscsi_ops = &iseriesvscsi_ops;
+       else if (firmware_has_feature(FW_FEATURE_VIO))
+               ibmvscsi_ops = &rpavscsi_ops;
+       else
+               return -ENODEV;
+
        ibmvscsi_transport_template =
                srp_attach_transport(&ibmvscsi_transport_functions);
        if (!ibmvscsi_transport_template)
index b19c2e26c2a541853ab01bccb803146fb78d3db5..46e850e302c7918306d96218ff606229ae230183 100644 (file)
@@ -98,21 +98,25 @@ struct ibmvscsi_host_data {
 };
 
 /* routines for managing a command/response queue */
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
-                           struct ibmvscsi_host_data *hostdata,
-                           int max_requests);
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
-                               struct ibmvscsi_host_data *hostdata,
-                               int max_requests);
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
-                             struct ibmvscsi_host_data *hostdata);
-
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
-                               struct ibmvscsi_host_data *hostdata);
-
 void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                         struct ibmvscsi_host_data *hostdata);
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
-                     u64 word1, u64 word2);
+
+struct ibmvscsi_ops {
+       int (*init_crq_queue)(struct crq_queue *queue,
+                             struct ibmvscsi_host_data *hostdata,
+                             int max_requests);
+       void (*release_crq_queue)(struct crq_queue *queue,
+                                 struct ibmvscsi_host_data *hostdata,
+                                 int max_requests);
+       int (*reset_crq_queue)(struct crq_queue *queue,
+                              struct ibmvscsi_host_data *hostdata);
+       int (*reenable_crq_queue)(struct crq_queue *queue,
+                                 struct ibmvscsi_host_data *hostdata);
+       int (*send_crq)(struct ibmvscsi_host_data *hostdata,
+                      u64 word1, u64 word2);
+};
+
+extern struct ibmvscsi_ops iseriesvscsi_ops;
+extern struct ibmvscsi_ops rpavscsi_ops;
 
 #endif                         /* IBMVSCSI_H */
index 6aeb5f003c3c912a0e53099d7d86c126f2ed505e..0775fdee5fa80cc4f9609167c8fc2e1769596d30 100644 (file)
@@ -53,7 +53,7 @@ struct srp_lp_event {
 /** 
  * standard interface for handling logical partition events.
  */
-static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
+static void iseriesvscsi_handle_event(struct HvLpEvent *lpevt)
 {
        struct srp_lp_event *evt = (struct srp_lp_event *)lpevt;
 
@@ -74,9 +74,9 @@ static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
 /* ------------------------------------------------------------
  * Routines for driver initialization
  */
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
-                           struct ibmvscsi_host_data *hostdata,
-                           int max_requests)
+static int iseriesvscsi_init_crq_queue(struct crq_queue *queue,
+                                      struct ibmvscsi_host_data *hostdata,
+                                      int max_requests)
 {
        int rc;
 
@@ -88,7 +88,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
                goto viopath_open_failed;
        }
 
-       rc = vio_setHandler(viomajorsubtype_scsi, ibmvscsi_handle_event);
+       rc = vio_setHandler(viomajorsubtype_scsi, iseriesvscsi_handle_event);
        if (rc < 0) {
                printk("vio_setHandler failed with rc %d in open_event_path\n",
                       rc);
@@ -102,9 +102,9 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
        return -1;
 }
 
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
-                               struct ibmvscsi_host_data *hostdata,
-                               int max_requests)
+static void iseriesvscsi_release_crq_queue(struct crq_queue *queue,
+                                          struct ibmvscsi_host_data *hostdata,
+                                          int max_requests)
 {
        vio_clearHandler(viomajorsubtype_scsi);
        viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
@@ -117,8 +117,8 @@ void ibmvscsi_release_crq_queue(struct crq_queue *queue,
  *
  * no-op for iSeries
  */
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
-                             struct ibmvscsi_host_data *hostdata)
+static int iseriesvscsi_reset_crq_queue(struct crq_queue *queue,
+                                       struct ibmvscsi_host_data *hostdata)
 {
        return 0;
 }
@@ -130,19 +130,20 @@ int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
  *
  * no-op for iSeries
  */
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
-                               struct ibmvscsi_host_data *hostdata)
+static int iseriesvscsi_reenable_crq_queue(struct crq_queue *queue,
+                                          struct ibmvscsi_host_data *hostdata)
 {
        return 0;
 }
 
 /**
- * ibmvscsi_send_crq: - Send a CRQ
+ * iseriesvscsi_send_crq: - Send a CRQ
  * @hostdata:  the adapter
  * @word1:     the first 64 bits of the data
  * @word2:     the second 64 bits of the data
  */
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+static int iseriesvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
+                                u64 word1, u64 word2)
 {
        single_host_data = hostdata;
        return HvCallEvent_signalLpEventFast(viopath_hostLp,
@@ -156,3 +157,11 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
                                             VIOVERSION << 16, word1, word2, 0,
                                             0);
 }
+
+struct ibmvscsi_ops iseriesvscsi_ops = {
+       .init_crq_queue = iseriesvscsi_init_crq_queue,
+       .release_crq_queue = iseriesvscsi_release_crq_queue,
+       .reset_crq_queue = iseriesvscsi_reset_crq_queue,
+       .reenable_crq_queue = iseriesvscsi_reenable_crq_queue,
+       .send_crq = iseriesvscsi_send_crq,
+};
index 9c14e789df5f875ad006ce179299a8fe864ace7c..182146100dc12220ee20e55d44cb8e0d3a7bf618 100644 (file)
@@ -42,14 +42,14 @@ static unsigned int partition_number = -1;
  * Routines for managing the command/response queue
  */
 /**
- * ibmvscsi_handle_event: - Interrupt handler for crq events
+ * rpavscsi_handle_event: - Interrupt handler for crq events
  * @irq:       number of irq to handle, not used
  * @dev_instance: ibmvscsi_host_data of host that received interrupt
  *
  * Disables interrupts and schedules srp_task
  * Always returns IRQ_HANDLED
  */
-static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
+static irqreturn_t rpavscsi_handle_event(int irq, void *dev_instance)
 {
        struct ibmvscsi_host_data *hostdata =
            (struct ibmvscsi_host_data *)dev_instance;
@@ -66,9 +66,9 @@ static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
  * Frees irq, deallocates a page for messages, unmaps dma, and unregisters
  * the crq with the hypervisor.
  */
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
-                               struct ibmvscsi_host_data *hostdata,
-                               int max_requests)
+static void rpavscsi_release_crq_queue(struct crq_queue *queue,
+                                      struct ibmvscsi_host_data *hostdata,
+                                      int max_requests)
 {
        long rc;
        struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -108,12 +108,13 @@ static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
 }
 
 /**
- * ibmvscsi_send_crq: - Send a CRQ
+ * rpavscsi_send_crq: - Send a CRQ
  * @hostdata:  the adapter
  * @word1:     the first 64 bits of the data
  * @word2:     the second 64 bits of the data
  */
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+static int rpavscsi_send_crq(struct ibmvscsi_host_data *hostdata,
+                            u64 word1, u64 word2)
 {
        struct vio_dev *vdev = to_vio_dev(hostdata->dev);
 
@@ -121,10 +122,10 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
 }
 
 /**
- * ibmvscsi_task: - Process srps asynchronously
+ * rpavscsi_task: - Process srps asynchronously
  * @data:      ibmvscsi_host_data of host
  */
-static void ibmvscsi_task(void *data)
+static void rpavscsi_task(void *data)
 {
        struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data;
        struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -189,6 +190,42 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
        hostdata->madapter_info.os_type = 2;
 }
 
+/**
+ * reset_crq_queue: - resets a crq after a failure
+ * @queue:     crq_queue to initialize and register
+ * @hostdata:  ibmvscsi_host_data of host
+ *
+ */
+static int rpavscsi_reset_crq_queue(struct crq_queue *queue,
+                                   struct ibmvscsi_host_data *hostdata)
+{
+       int rc;
+       struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+
+       /* Close the CRQ */
+       do {
+               rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+       } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
+
+       /* Clean out the queue */
+       memset(queue->msgs, 0x00, PAGE_SIZE);
+       queue->cur = 0;
+
+       set_adapter_info(hostdata);
+
+       /* And re-open it again */
+       rc = plpar_hcall_norets(H_REG_CRQ,
+                               vdev->unit_address,
+                               queue->msg_token, PAGE_SIZE);
+       if (rc == 2) {
+               /* Adapter is good, but other end is not ready */
+               dev_warn(hostdata->dev, "Partner adapter not ready\n");
+       } else if (rc != 0) {
+               dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
+       }
+       return rc;
+}
+
 /**
  * initialize_crq_queue: - Initializes and registers CRQ with hypervisor
  * @queue:     crq_queue to initialize and register
@@ -198,9 +235,9 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
  * the crq with the hypervisor.
  * Returns zero on success.
  */
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
-                           struct ibmvscsi_host_data *hostdata,
-                           int max_requests)
+static int rpavscsi_init_crq_queue(struct crq_queue *queue,
+                                  struct ibmvscsi_host_data *hostdata,
+                                  int max_requests)
 {
        int rc;
        int retrc;
@@ -227,7 +264,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
                                queue->msg_token, PAGE_SIZE);
        if (rc == H_RESOURCE)
                /* maybe kexecing and resource is busy. try a reset */
-               rc = ibmvscsi_reset_crq_queue(queue,
+               rc = rpavscsi_reset_crq_queue(queue,
                                              hostdata);
 
        if (rc == 2) {
@@ -240,7 +277,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
        }
 
        if (request_irq(vdev->irq,
-                       ibmvscsi_handle_event,
+                       rpavscsi_handle_event,
                        0, "ibmvscsi", (void *)hostdata) != 0) {
                dev_err(hostdata->dev, "couldn't register irq 0x%x\n",
                        vdev->irq);
@@ -256,7 +293,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
        queue->cur = 0;
        spin_lock_init(&queue->lock);
 
-       tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
+       tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task,
                     (unsigned long)hostdata);
 
        return retrc;
@@ -281,8 +318,8 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
  * @hostdata:  ibmvscsi_host_data of host
  *
  */
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
-                                struct ibmvscsi_host_data *hostdata)
+static int rpavscsi_reenable_crq_queue(struct crq_queue *queue,
+                                      struct ibmvscsi_host_data *hostdata)
 {
        int rc;
        struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -297,38 +334,10 @@ int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
        return rc;
 }
 
-/**
- * reset_crq_queue: - resets a crq after a failure
- * @queue:     crq_queue to initialize and register
- * @hostdata:  ibmvscsi_host_data of host
- *
- */
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
-                             struct ibmvscsi_host_data *hostdata)
-{
-       int rc;
-       struct vio_dev *vdev = to_vio_dev(hostdata->dev);
-
-       /* Close the CRQ */
-       do {
-               rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
-       } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
-
-       /* Clean out the queue */
-       memset(queue->msgs, 0x00, PAGE_SIZE);
-       queue->cur = 0;
-
-       set_adapter_info(hostdata);
-
-       /* And re-open it again */
-       rc = plpar_hcall_norets(H_REG_CRQ,
-                               vdev->unit_address,
-                               queue->msg_token, PAGE_SIZE);
-       if (rc == 2) {
-               /* Adapter is good, but other end is not ready */
-               dev_warn(hostdata->dev, "Partner adapter not ready\n");
-       } else if (rc != 0) {
-               dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
-       }
-       return rc;
-}
+struct ibmvscsi_ops rpavscsi_ops = {
+       .init_crq_queue = rpavscsi_init_crq_queue,
+       .release_crq_queue = rpavscsi_release_crq_queue,
+       .reset_crq_queue = rpavscsi_reset_crq_queue,
+       .reenable_crq_queue = rpavscsi_reenable_crq_queue,
+       .send_crq = rpavscsi_send_crq,
+};