[SCSI] scsi_lib_dma: fix bug with dma maps on nested scsi objects
authorJames Bottomley <James.Bottomley@suse.de>
Thu, 5 Nov 2009 19:33:12 +0000 (13:33 -0600)
committerJames Bottomley <James.Bottomley@suse.de>
Fri, 4 Dec 2009 18:01:30 +0000 (12:01 -0600)
Some of our virtual SCSI hosts don't have a proper bus parent at the
top, which can be a problem for doing DMA on them

This patch makes the host device cache a pointer to the physical bus
device and provides an extra API for setting it (the normal API picks
it up from the parent).  This patch also modifies the qla2xxx and lpfc
vport logic to use the new DMA host setting API.

Acked-By: James Smart <james.smart@emulex.com>
Cc: Stable Tree <stable@kernel.org>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/hosts.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/scsi_lib_dma.c
include/scsi/scsi_host.h

index 5fd2da494d087da334b65b9bd88b2945191184ff..28a753d796f3a6303fb6b993da40ffe21e1db338 100644 (file)
@@ -180,14 +180,20 @@ void scsi_remove_host(struct Scsi_Host *shost)
 EXPORT_SYMBOL(scsi_remove_host);
 
 /**
- * scsi_add_host - add a scsi host
+ * scsi_add_host_with_dma - add a scsi host with dma device
  * @shost:     scsi host pointer to add
  * @dev:       a struct device of type scsi class
+ * @dma_dev:   dma device for the host
+ *
+ * Note: You rarely need to worry about this unless you're in a
+ * virtualised host environments, so use the simpler scsi_add_host()
+ * function instead.
  *
  * Return value: 
  *     0 on success / != 0 for error
  **/
-int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
+int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
+                          struct device *dma_dev)
 {
        struct scsi_host_template *sht = shost->hostt;
        int error = -EINVAL;
@@ -207,6 +213,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
 
        if (!shost->shost_gendev.parent)
                shost->shost_gendev.parent = dev ? dev : &platform_bus;
+       shost->dma_dev = dma_dev;
 
        error = device_add(&shost->shost_gendev);
        if (error)
@@ -262,7 +269,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
  fail:
        return error;
 }
-EXPORT_SYMBOL(scsi_add_host);
+EXPORT_SYMBOL(scsi_add_host_with_dma);
 
 static void scsi_host_dev_release(struct device *dev)
 {
index 562d8cee874bf42cb5aefcb6546da7aa7b1d1211..f913f1e936355d21cda68ef8b2d6c972bdd89262 100644 (file)
@@ -2408,7 +2408,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
        vport->els_tmofunc.function = lpfc_els_timeout;
        vport->els_tmofunc.data = (unsigned long)vport;
 
-       error = scsi_add_host(shost, dev);
+       error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
        if (error)
                goto out_put_shost;
 
index fbcb82a2f7f4c5b4e8dffc5573c0fa1b64e46719..21e2bc4d74013caa1446385a72f53c17eaa58391 100644 (file)
@@ -1654,7 +1654,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
                        fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
        }
 
-       if (scsi_add_host(vha->host, &fc_vport->dev)) {
+       if (scsi_add_host_with_dma(vha->host, &fc_vport->dev,
+                                  &ha->pdev->dev)) {
                DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n",
                        vha->host_no, vha->vp_idx));
                goto vport_create_failed_2;
index ac6855cd265747f96ef6b568d3de13966929ce2b..dcd128583b89795c6294d79c2b61df6fdc0f3dd5 100644 (file)
@@ -23,7 +23,7 @@ int scsi_dma_map(struct scsi_cmnd *cmd)
        int nseg = 0;
 
        if (scsi_sg_count(cmd)) {
-               struct device *dev = cmd->device->host->shost_gendev.parent;
+               struct device *dev = cmd->device->host->dma_dev;
 
                nseg = dma_map_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
                                  cmd->sc_data_direction);
@@ -41,7 +41,7 @@ EXPORT_SYMBOL(scsi_dma_map);
 void scsi_dma_unmap(struct scsi_cmnd *cmd)
 {
        if (scsi_sg_count(cmd)) {
-               struct device *dev = cmd->device->host->shost_gendev.parent;
+               struct device *dev = cmd->device->host->dma_dev;
 
                dma_unmap_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
                             cmd->sc_data_direction);
index 603054d8f40c42ffc1838e6c9c5af4050e29b95c..6ff6bc18e294ac9070358b256cc977d16e5fc8c5 100644 (file)
@@ -682,6 +682,12 @@ struct Scsi_Host {
         */
        void *shost_data;
 
+       /*
+        * Points to the physical bus device we'd use to do DMA
+        * Needed just in case we have virtual hosts.
+        */
+       struct device *dma_dev;
+
        /*
         * We should ensure that this is aligned, both for better performance
         * and also because some compilers (m68k) don't automatically force
@@ -726,7 +732,9 @@ extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);
 extern void scsi_flush_work(struct Scsi_Host *);
 
 extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
-extern int __must_check scsi_add_host(struct Scsi_Host *, struct device *);
+extern int __must_check scsi_add_host_with_dma(struct Scsi_Host *,
+                                              struct device *,
+                                              struct device *);
 extern void scsi_scan_host(struct Scsi_Host *);
 extern void scsi_rescan_device(struct device *);
 extern void scsi_remove_host(struct Scsi_Host *);
@@ -737,6 +745,12 @@ extern const char *scsi_host_state_name(enum scsi_host_state);
 
 extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
 
+static inline int __must_check scsi_add_host(struct Scsi_Host *host,
+                                            struct device *dev)
+{
+       return scsi_add_host_with_dma(host, dev, dev);
+}
+
 static inline struct device *scsi_get_device(struct Scsi_Host *shost)
 {
         return shost->shost_gendev.parent;