+++ /dev/null
-From: James Smart <james.smart@emulex.com>
-Subject: scsi_lib_dma.c : fix bug w/ dma on virtual fc ports
-References: bnc#431294
-
-When the updated scsi dma code was introduced recently, it assumed
-the physical host/adapter was the parent of the scsi host.
-Unfortunately, on FC virtual ports, the parent of the scsi host is
-the virtual port, which does not have dma information.
-
-I have updated the dma routines to use a function that finds the
-first non-scsi object. A non-scsi object is defined to be an object
-that has a non-NULL type (assumes all transport objects have NULL
-types) or a non-scsi_host type.
-
--- james s
-
-Unfortunately the original patch is not correct, as eg the PCI device
-doesn't set the 'type' pointer, so the system will crash miserably.
-We should rather check for the 'bus' argument, and return the original
-argument if we don't find anything.
-
-Signed-off-by: Hannes Reinecke <hare@suse.de>
-
-diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
-index 69321e3..208e7df 100644
---- a/drivers/scsi/scsi_lib.c
-+++ b/drivers/scsi/scsi_lib.c
-@@ -1713,7 +1713,7 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
- request_fn_proc *request_fn)
- {
- struct request_queue *q;
-- struct device *dev = shost->shost_gendev.parent;
-+ struct device *dev = dev_to_nonscsi_dev(shost->shost_gendev.parent);
-
- q = blk_init_queue(request_fn, NULL);
- if (!q)
-diff --git a/drivers/scsi/scsi_lib_dma.c b/drivers/scsi/scsi_lib_dma.c
-index ac6855c..567cdbc 100644
---- a/drivers/scsi/scsi_lib_dma.c
-+++ b/drivers/scsi/scsi_lib_dma.c
-@@ -23,7 +23,8 @@ 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 = dev_to_nonscsi_dev(
-+ cmd->device->host->shost_gendev.parent);
-
- nseg = dma_map_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
- cmd->sc_data_direction);
-@@ -41,10 +42,12 @@ 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 = dev_to_nonscsi_dev(
-+ cmd->device->host->shost_gendev.parent);
-
- dma_unmap_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
- cmd->sc_data_direction);
- }
- }
- EXPORT_SYMBOL(scsi_dma_unmap);
-+
-diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
-index d123ca8..55d74c8 100644
---- a/include/scsi/scsi_host.h
-+++ b/include/scsi/scsi_host.h
-@@ -689,6 +689,10 @@ static inline void *shost_priv(struct Scsi_Host *shost)
-
- int scsi_is_host_device(const struct device *);
-
-+/*
-+ * walks object list backward, to find the first shost object.
-+ * Skips over transport objects that may not be stargets, etc
-+ */
- static inline struct Scsi_Host *dev_to_shost(struct device *dev)
- {
- while (!scsi_is_host_device(dev)) {
-@@ -699,6 +703,26 @@ static inline struct Scsi_Host *dev_to_shost(struct device *dev)
- return container_of(dev, struct Scsi_Host, shost_gendev);
- }
-
-+/*
-+ * walks object list backward, to find the first physical
-+ * device object. If none is found return the original device.
-+ */
-+static inline struct device *dev_to_nonscsi_dev(struct device *dev)
-+{
-+ struct device *orig = dev;
-+
-+ while (dev && (dev->bus == NULL || scsi_is_host_device(dev))) {
-+ if (dev->dma_parms) {
-+ dev_printk(KERN_WARNING, dev,
-+ "dma_parms set, bus %p\n",
-+ dev->bus);
-+ break;
-+ }
-+ dev = dev->parent;
-+ }
-+ return dev?dev:orig;
-+}
-+
- static inline int scsi_host_in_recovery(struct Scsi_Host *shost)
- {
- return shost->shost_state == SHOST_RECOVERY ||