diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_sas.c')
-rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 125 |
1 files changed, 124 insertions, 1 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index b2ef71a86292..3120f4b3a11a 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/err.h> | 29 | #include <linux/err.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/string.h> | 31 | #include <linux/string.h> |
32 | #include <linux/blkdev.h> | ||
33 | #include <linux/bsg.h> | ||
32 | 34 | ||
33 | #include <scsi/scsi.h> | 35 | #include <scsi/scsi.h> |
34 | #include <scsi/scsi_device.h> | 36 | #include <scsi/scsi_device.h> |
@@ -40,6 +42,7 @@ | |||
40 | struct sas_host_attrs { | 42 | struct sas_host_attrs { |
41 | struct list_head rphy_list; | 43 | struct list_head rphy_list; |
42 | struct mutex lock; | 44 | struct mutex lock; |
45 | struct request_queue *q; | ||
43 | u32 next_target_id; | 46 | u32 next_target_id; |
44 | u32 next_expander_id; | 47 | u32 next_expander_id; |
45 | int next_port_id; | 48 | int next_port_id; |
@@ -152,6 +155,106 @@ static struct { | |||
152 | sas_bitfield_name_search(linkspeed, sas_linkspeed_names) | 155 | sas_bitfield_name_search(linkspeed, sas_linkspeed_names) |
153 | sas_bitfield_name_set(linkspeed, sas_linkspeed_names) | 156 | sas_bitfield_name_set(linkspeed, sas_linkspeed_names) |
154 | 157 | ||
158 | static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, | ||
159 | struct sas_rphy *rphy) | ||
160 | { | ||
161 | struct request *req; | ||
162 | int ret; | ||
163 | int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *); | ||
164 | |||
165 | while (!blk_queue_plugged(q)) { | ||
166 | req = elv_next_request(q); | ||
167 | if (!req) | ||
168 | break; | ||
169 | |||
170 | blkdev_dequeue_request(req); | ||
171 | |||
172 | spin_unlock_irq(q->queue_lock); | ||
173 | |||
174 | handler = to_sas_internal(shost->transportt)->f->smp_handler; | ||
175 | ret = handler(shost, rphy, req); | ||
176 | |||
177 | spin_lock_irq(q->queue_lock); | ||
178 | |||
179 | req->end_io(req, ret); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | static void sas_host_smp_request(struct request_queue *q) | ||
184 | { | ||
185 | sas_smp_request(q, (struct Scsi_Host *)q->queuedata, NULL); | ||
186 | } | ||
187 | |||
188 | static void sas_non_host_smp_request(struct request_queue *q) | ||
189 | { | ||
190 | struct sas_rphy *rphy = q->queuedata; | ||
191 | sas_smp_request(q, rphy_to_shost(rphy), rphy); | ||
192 | } | ||
193 | |||
194 | static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) | ||
195 | { | ||
196 | struct request_queue *q; | ||
197 | int error; | ||
198 | struct device *dev; | ||
199 | char namebuf[BUS_ID_SIZE]; | ||
200 | const char *name; | ||
201 | |||
202 | if (!to_sas_internal(shost->transportt)->f->smp_handler) { | ||
203 | printk("%s can't handle SMP requests\n", shost->hostt->name); | ||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | if (rphy) { | ||
208 | q = blk_init_queue(sas_non_host_smp_request, NULL); | ||
209 | dev = &rphy->dev; | ||
210 | name = dev->bus_id; | ||
211 | } else { | ||
212 | q = blk_init_queue(sas_host_smp_request, NULL); | ||
213 | dev = &shost->shost_gendev; | ||
214 | snprintf(namebuf, sizeof(namebuf), | ||
215 | "sas_host%d", shost->host_no); | ||
216 | name = namebuf; | ||
217 | } | ||
218 | if (!q) | ||
219 | return -ENOMEM; | ||
220 | |||
221 | error = bsg_register_queue(q, dev, name); | ||
222 | if (error) { | ||
223 | blk_cleanup_queue(q); | ||
224 | return -ENOMEM; | ||
225 | } | ||
226 | |||
227 | if (rphy) | ||
228 | rphy->q = q; | ||
229 | else | ||
230 | to_sas_host_attrs(shost)->q = q; | ||
231 | |||
232 | if (rphy) | ||
233 | q->queuedata = rphy; | ||
234 | else | ||
235 | q->queuedata = shost; | ||
236 | |||
237 | set_bit(QUEUE_FLAG_BIDI, &q->queue_flags); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy) | ||
243 | { | ||
244 | struct request_queue *q; | ||
245 | |||
246 | if (rphy) | ||
247 | q = rphy->q; | ||
248 | else | ||
249 | q = to_sas_host_attrs(shost)->q; | ||
250 | |||
251 | if (!q) | ||
252 | return; | ||
253 | |||
254 | bsg_unregister_queue(q); | ||
255 | blk_cleanup_queue(q); | ||
256 | } | ||
257 | |||
155 | /* | 258 | /* |
156 | * SAS host attributes | 259 | * SAS host attributes |
157 | */ | 260 | */ |
@@ -167,11 +270,26 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev, | |||
167 | sas_host->next_target_id = 0; | 270 | sas_host->next_target_id = 0; |
168 | sas_host->next_expander_id = 0; | 271 | sas_host->next_expander_id = 0; |
169 | sas_host->next_port_id = 0; | 272 | sas_host->next_port_id = 0; |
273 | |||
274 | if (sas_bsg_initialize(shost, NULL)) | ||
275 | dev_printk(KERN_ERR, dev, "fail to a bsg device %d\n", | ||
276 | shost->host_no); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static int sas_host_remove(struct transport_container *tc, struct device *dev, | ||
282 | struct class_device *cdev) | ||
283 | { | ||
284 | struct Scsi_Host *shost = dev_to_shost(dev); | ||
285 | |||
286 | sas_bsg_remove(shost, NULL); | ||
287 | |||
170 | return 0; | 288 | return 0; |
171 | } | 289 | } |
172 | 290 | ||
173 | static DECLARE_TRANSPORT_CLASS(sas_host_class, | 291 | static DECLARE_TRANSPORT_CLASS(sas_host_class, |
174 | "sas_host", sas_host_setup, NULL, NULL); | 292 | "sas_host", sas_host_setup, sas_host_remove, NULL); |
175 | 293 | ||
176 | static int sas_host_match(struct attribute_container *cont, | 294 | static int sas_host_match(struct attribute_container *cont, |
177 | struct device *dev) | 295 | struct device *dev) |
@@ -1287,6 +1405,9 @@ int sas_rphy_add(struct sas_rphy *rphy) | |||
1287 | return error; | 1405 | return error; |
1288 | transport_add_device(&rphy->dev); | 1406 | transport_add_device(&rphy->dev); |
1289 | transport_configure_device(&rphy->dev); | 1407 | transport_configure_device(&rphy->dev); |
1408 | if (sas_bsg_initialize(shost, rphy)) | ||
1409 | printk("fail to a bsg device %s\n", rphy->dev.bus_id); | ||
1410 | |||
1290 | 1411 | ||
1291 | mutex_lock(&sas_host->lock); | 1412 | mutex_lock(&sas_host->lock); |
1292 | list_add_tail(&rphy->list, &sas_host->rphy_list); | 1413 | list_add_tail(&rphy->list, &sas_host->rphy_list); |
@@ -1329,6 +1450,8 @@ void sas_rphy_free(struct sas_rphy *rphy) | |||
1329 | list_del(&rphy->list); | 1450 | list_del(&rphy->list); |
1330 | mutex_unlock(&sas_host->lock); | 1451 | mutex_unlock(&sas_host->lock); |
1331 | 1452 | ||
1453 | sas_bsg_remove(shost, rphy); | ||
1454 | |||
1332 | transport_destroy_device(dev); | 1455 | transport_destroy_device(dev); |
1333 | 1456 | ||
1334 | put_device(dev); | 1457 | put_device(dev); |