diff options
author | Hannes Reinecke <hare@suse.de> | 2008-07-17 20:49:02 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-07-26 15:14:53 -0400 |
commit | ae11b1b36da726a8a93409b896704edc6b4f3402 (patch) | |
tree | 737e3602cb426c87f64ad26ccbfc12ce707d7b9e /drivers/scsi | |
parent | 057ea7c9683c3d684128cced796f03c179ecf1c2 (diff) |
[SCSI] scsi_dh: attach to hardware handler from dm-mpath
multipath keeps a separate device table which may be
more current than the built-in one.
So we should make sure to always call ->attach whenever
a multipath map with hardware handler is instantiated.
And we should call ->detach on removal, too.
[sekharan: update as per comments from agk]
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index e90df9dd3e65..a9159681ff27 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c | |||
@@ -369,6 +369,70 @@ int scsi_dh_handler_exist(const char *name) | |||
369 | } | 369 | } |
370 | EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); | 370 | EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); |
371 | 371 | ||
372 | /* | ||
373 | * scsi_dh_handler_attach - Attach device handler | ||
374 | * @sdev - sdev the handler should be attached to | ||
375 | * @name - name of the handler to attach | ||
376 | */ | ||
377 | int scsi_dh_attach(struct request_queue *q, const char *name) | ||
378 | { | ||
379 | unsigned long flags; | ||
380 | struct scsi_device *sdev; | ||
381 | struct scsi_device_handler *scsi_dh; | ||
382 | int err = 0; | ||
383 | |||
384 | scsi_dh = get_device_handler(name); | ||
385 | if (!scsi_dh) | ||
386 | return -EINVAL; | ||
387 | |||
388 | spin_lock_irqsave(q->queue_lock, flags); | ||
389 | sdev = q->queuedata; | ||
390 | if (!sdev || !get_device(&sdev->sdev_gendev)) | ||
391 | err = -ENODEV; | ||
392 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
393 | |||
394 | if (!err) { | ||
395 | err = scsi_dh_handler_attach(sdev, scsi_dh); | ||
396 | |||
397 | put_device(&sdev->sdev_gendev); | ||
398 | } | ||
399 | return err; | ||
400 | } | ||
401 | EXPORT_SYMBOL_GPL(scsi_dh_attach); | ||
402 | |||
403 | /* | ||
404 | * scsi_dh_handler_detach - Detach device handler | ||
405 | * @sdev - sdev the handler should be detached from | ||
406 | * | ||
407 | * This function will detach the device handler only | ||
408 | * if the sdev is not part of the internal list, ie | ||
409 | * if it has been attached manually. | ||
410 | */ | ||
411 | void scsi_dh_detach(struct request_queue *q) | ||
412 | { | ||
413 | unsigned long flags; | ||
414 | struct scsi_device *sdev; | ||
415 | struct scsi_device_handler *scsi_dh = NULL; | ||
416 | |||
417 | spin_lock_irqsave(q->queue_lock, flags); | ||
418 | sdev = q->queuedata; | ||
419 | if (!sdev || !get_device(&sdev->sdev_gendev)) | ||
420 | sdev = NULL; | ||
421 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
422 | |||
423 | if (!sdev) | ||
424 | return; | ||
425 | |||
426 | if (sdev->scsi_dh_data) { | ||
427 | /* if sdev is not on internal list, detach */ | ||
428 | scsi_dh = sdev->scsi_dh_data->scsi_dh; | ||
429 | if (!device_handler_match(scsi_dh, sdev)) | ||
430 | scsi_dh_handler_detach(sdev, scsi_dh); | ||
431 | } | ||
432 | put_device(&sdev->sdev_gendev); | ||
433 | } | ||
434 | EXPORT_SYMBOL_GPL(scsi_dh_detach); | ||
435 | |||
372 | static struct notifier_block scsi_dh_nb = { | 436 | static struct notifier_block scsi_dh_nb = { |
373 | .notifier_call = scsi_dh_notifier | 437 | .notifier_call = scsi_dh_notifier |
374 | }; | 438 | }; |