Commit d139b9bd0e52dda14fd13412e7096e68b56d0076

Authored by James Bottomley
1 parent 5917290ce9

[SCSI] scsi_lib_dma: fix bug with dma maps on nested scsi objects

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>

Showing 5 changed files with 30 additions and 8 deletions Side-by-side Diff

drivers/scsi/hosts.c
... ... @@ -180,14 +180,20 @@
180 180 EXPORT_SYMBOL(scsi_remove_host);
181 181  
182 182 /**
183   - * scsi_add_host - add a scsi host
  183 + * scsi_add_host_with_dma - add a scsi host with dma device
184 184 * @shost: scsi host pointer to add
185 185 * @dev: a struct device of type scsi class
  186 + * @dma_dev: dma device for the host
186 187 *
  188 + * Note: You rarely need to worry about this unless you're in a
  189 + * virtualised host environments, so use the simpler scsi_add_host()
  190 + * function instead.
  191 + *
187 192 * Return value:
188 193 * 0 on success / != 0 for error
189 194 **/
190   -int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
  195 +int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
  196 + struct device *dma_dev)
191 197 {
192 198 struct scsi_host_template *sht = shost->hostt;
193 199 int error = -EINVAL;
... ... @@ -207,6 +213,7 @@
207 213  
208 214 if (!shost->shost_gendev.parent)
209 215 shost->shost_gendev.parent = dev ? dev : &platform_bus;
  216 + shost->dma_dev = dma_dev;
210 217  
211 218 error = device_add(&shost->shost_gendev);
212 219 if (error)
... ... @@ -262,7 +269,7 @@
262 269 fail:
263 270 return error;
264 271 }
265   -EXPORT_SYMBOL(scsi_add_host);
  272 +EXPORT_SYMBOL(scsi_add_host_with_dma);
266 273  
267 274 static void scsi_host_dev_release(struct device *dev)
268 275 {
drivers/scsi/lpfc/lpfc_init.c
... ... @@ -2408,7 +2408,7 @@
2408 2408 vport->els_tmofunc.function = lpfc_els_timeout;
2409 2409 vport->els_tmofunc.data = (unsigned long)vport;
2410 2410  
2411   - error = scsi_add_host(shost, dev);
  2411 + error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
2412 2412 if (error)
2413 2413 goto out_put_shost;
2414 2414  
drivers/scsi/qla2xxx/qla_attr.c
... ... @@ -1654,7 +1654,8 @@
1654 1654 fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
1655 1655 }
1656 1656  
1657   - if (scsi_add_host(vha->host, &fc_vport->dev)) {
  1657 + if (scsi_add_host_with_dma(vha->host, &fc_vport->dev,
  1658 + &ha->pdev->dev)) {
1658 1659 DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n",
1659 1660 vha->host_no, vha->vp_idx));
1660 1661 goto vport_create_failed_2;
drivers/scsi/scsi_lib_dma.c
... ... @@ -23,7 +23,7 @@
23 23 int nseg = 0;
24 24  
25 25 if (scsi_sg_count(cmd)) {
26   - struct device *dev = cmd->device->host->shost_gendev.parent;
  26 + struct device *dev = cmd->device->host->dma_dev;
27 27  
28 28 nseg = dma_map_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
29 29 cmd->sc_data_direction);
... ... @@ -41,7 +41,7 @@
41 41 void scsi_dma_unmap(struct scsi_cmnd *cmd)
42 42 {
43 43 if (scsi_sg_count(cmd)) {
44   - struct device *dev = cmd->device->host->shost_gendev.parent;
  44 + struct device *dev = cmd->device->host->dma_dev;
45 45  
46 46 dma_unmap_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
47 47 cmd->sc_data_direction);
include/scsi/scsi_host.h
... ... @@ -683,6 +683,12 @@
683 683 void *shost_data;
684 684  
685 685 /*
  686 + * Points to the physical bus device we'd use to do DMA
  687 + * Needed just in case we have virtual hosts.
  688 + */
  689 + struct device *dma_dev;
  690 +
  691 + /*
686 692 * We should ensure that this is aligned, both for better performance
687 693 * and also because some compilers (m68k) don't automatically force
688 694 * alignment to a long boundary.
... ... @@ -726,7 +732,9 @@
726 732 extern void scsi_flush_work(struct Scsi_Host *);
727 733  
728 734 extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
729   -extern int __must_check scsi_add_host(struct Scsi_Host *, struct device *);
  735 +extern int __must_check scsi_add_host_with_dma(struct Scsi_Host *,
  736 + struct device *,
  737 + struct device *);
730 738 extern void scsi_scan_host(struct Scsi_Host *);
731 739 extern void scsi_rescan_device(struct device *);
732 740 extern void scsi_remove_host(struct Scsi_Host *);
... ... @@ -736,6 +744,12 @@
736 744 extern const char *scsi_host_state_name(enum scsi_host_state);
737 745  
738 746 extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
  747 +
  748 +static inline int __must_check scsi_add_host(struct Scsi_Host *host,
  749 + struct device *dev)
  750 +{
  751 + return scsi_add_host_with_dma(host, dev, dev);
  752 +}
739 753  
740 754 static inline struct device *scsi_get_device(struct Scsi_Host *shost)
741 755 {