]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blame - src/patches/suse-2.6.27.39/patches.fixes/scsi-skip-nonscsi-device-for-dma
Imported linux-2.6.27.39 suse/xen patches.
[people/teissler/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.fixes / scsi-skip-nonscsi-device-for-dma
CommitLineData
2cb7cef9
BS
1From: James Smart <james.smart@emulex.com>
2Subject: scsi_lib_dma.c : fix bug w/ dma on virtual fc ports
3References: bnc#431294
4
5When the updated scsi dma code was introduced recently, it assumed
6the physical host/adapter was the parent of the scsi host.
7Unfortunately, on FC virtual ports, the parent of the scsi host is
8the virtual port, which does not have dma information.
9
10I have updated the dma routines to use a function that finds the
11first non-scsi object. A non-scsi object is defined to be an object
12that has a non-NULL type (assumes all transport objects have NULL
13types) or a non-scsi_host type.
14
15-- james s
16
17Unfortunately the original patch is not correct, as eg the PCI device
18doesn't set the 'type' pointer, so the system will crash miserably.
19We should rather check for the 'bus' argument, and return the original
20argument if we don't find anything.
21
22Signed-off-by: Hannes Reinecke <hare@suse.de>
23
24diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
25index 69321e3..208e7df 100644
26--- a/drivers/scsi/scsi_lib.c
27+++ b/drivers/scsi/scsi_lib.c
28@@ -1713,7 +1713,7 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
29 request_fn_proc *request_fn)
30 {
31 struct request_queue *q;
32- struct device *dev = shost->shost_gendev.parent;
33+ struct device *dev = dev_to_nonscsi_dev(shost->shost_gendev.parent);
34
35 q = blk_init_queue(request_fn, NULL);
36 if (!q)
37diff --git a/drivers/scsi/scsi_lib_dma.c b/drivers/scsi/scsi_lib_dma.c
38index ac6855c..567cdbc 100644
39--- a/drivers/scsi/scsi_lib_dma.c
40+++ b/drivers/scsi/scsi_lib_dma.c
41@@ -23,7 +23,8 @@ int scsi_dma_map(struct scsi_cmnd *cmd)
42 int nseg = 0;
43
44 if (scsi_sg_count(cmd)) {
45- struct device *dev = cmd->device->host->shost_gendev.parent;
46+ struct device *dev = dev_to_nonscsi_dev(
47+ cmd->device->host->shost_gendev.parent);
48
49 nseg = dma_map_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
50 cmd->sc_data_direction);
51@@ -41,10 +42,12 @@ EXPORT_SYMBOL(scsi_dma_map);
52 void scsi_dma_unmap(struct scsi_cmnd *cmd)
53 {
54 if (scsi_sg_count(cmd)) {
55- struct device *dev = cmd->device->host->shost_gendev.parent;
56+ struct device *dev = dev_to_nonscsi_dev(
57+ cmd->device->host->shost_gendev.parent);
58
59 dma_unmap_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
60 cmd->sc_data_direction);
61 }
62 }
63 EXPORT_SYMBOL(scsi_dma_unmap);
64+
65diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
66index d123ca8..55d74c8 100644
67--- a/include/scsi/scsi_host.h
68+++ b/include/scsi/scsi_host.h
69@@ -689,6 +689,10 @@ static inline void *shost_priv(struct Scsi_Host *shost)
70
71 int scsi_is_host_device(const struct device *);
72
73+/*
74+ * walks object list backward, to find the first shost object.
75+ * Skips over transport objects that may not be stargets, etc
76+ */
77 static inline struct Scsi_Host *dev_to_shost(struct device *dev)
78 {
79 while (!scsi_is_host_device(dev)) {
80@@ -699,6 +703,26 @@ static inline struct Scsi_Host *dev_to_shost(struct device *dev)
81 return container_of(dev, struct Scsi_Host, shost_gendev);
82 }
83
84+/*
85+ * walks object list backward, to find the first physical
86+ * device object. If none is found return the original device.
87+ */
88+static inline struct device *dev_to_nonscsi_dev(struct device *dev)
89+{
90+ struct device *orig = dev;
91+
92+ while (dev && (dev->bus == NULL || scsi_is_host_device(dev))) {
93+ if (dev->dma_parms) {
94+ dev_printk(KERN_WARNING, dev,
95+ "dma_parms set, bus %p\n",
96+ dev->bus);
97+ break;
98+ }
99+ dev = dev->parent;
100+ }
101+ return dev?dev:orig;
102+}
103+
104 static inline int scsi_host_in_recovery(struct Scsi_Host *shost)
105 {
106 return shost->shost_state == SHOST_RECOVERY ||