diff options
author | Michael Reed <mdr@sgi.com> | 2006-01-25 20:05:18 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2006-01-31 15:39:41 -0500 |
commit | 3bc7bf1d1294642f87c4f7df04c048dafa38ad51 (patch) | |
tree | 263a1466b905e3e3685f84975f4bd7850b489042 /drivers/message/fusion/mptfc.c | |
parent | 79de278e86121cd4473c276409f834aee87f3195 (diff) |
[SCSI] fusion: FC rport code fixes
This fix's problems with recent fc submission regarding
i/o being redirected to the wrong target.
Signed-off-by: Michael Reed <mdr@sgi.com>
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/message/fusion/mptfc.c')
-rw-r--r-- | drivers/message/fusion/mptfc.c | 203 |
1 files changed, 141 insertions, 62 deletions
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index b102c7666d0e..c3a3499bce2a 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c | |||
@@ -93,10 +93,11 @@ static int mptfcDoneCtx = -1; | |||
93 | static int mptfcTaskCtx = -1; | 93 | static int mptfcTaskCtx = -1; |
94 | static int mptfcInternalCtx = -1; /* Used only for internal commands */ | 94 | static int mptfcInternalCtx = -1; /* Used only for internal commands */ |
95 | 95 | ||
96 | int mptfc_slave_alloc(struct scsi_device *device); | 96 | static int mptfc_target_alloc(struct scsi_target *starget); |
97 | static int mptfc_slave_alloc(struct scsi_device *sdev); | ||
97 | static int mptfc_qcmd(struct scsi_cmnd *SCpnt, | 98 | static int mptfc_qcmd(struct scsi_cmnd *SCpnt, |
98 | void (*done)(struct scsi_cmnd *)); | 99 | void (*done)(struct scsi_cmnd *)); |
99 | 100 | static void mptfc_target_destroy(struct scsi_target *starget); | |
100 | static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout); | 101 | static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout); |
101 | static void __devexit mptfc_remove(struct pci_dev *pdev); | 102 | static void __devexit mptfc_remove(struct pci_dev *pdev); |
102 | 103 | ||
@@ -107,10 +108,10 @@ static struct scsi_host_template mptfc_driver_template = { | |||
107 | .name = "MPT FC Host", | 108 | .name = "MPT FC Host", |
108 | .info = mptscsih_info, | 109 | .info = mptscsih_info, |
109 | .queuecommand = mptfc_qcmd, | 110 | .queuecommand = mptfc_qcmd, |
110 | .target_alloc = mptscsih_target_alloc, | 111 | .target_alloc = mptfc_target_alloc, |
111 | .slave_alloc = mptfc_slave_alloc, | 112 | .slave_alloc = mptfc_slave_alloc, |
112 | .slave_configure = mptscsih_slave_configure, | 113 | .slave_configure = mptscsih_slave_configure, |
113 | .target_destroy = mptscsih_target_destroy, | 114 | .target_destroy = mptfc_target_destroy, |
114 | .slave_destroy = mptscsih_slave_destroy, | 115 | .slave_destroy = mptscsih_slave_destroy, |
115 | .change_queue_depth = mptscsih_change_queue_depth, | 116 | .change_queue_depth = mptscsih_change_queue_depth, |
116 | .eh_abort_handler = mptscsih_abort, | 117 | .eh_abort_handler = mptscsih_abort, |
@@ -348,14 +349,33 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid) | |||
348 | } | 349 | } |
349 | 350 | ||
350 | static void | 351 | static void |
352 | mptfc_remap_sdev(struct scsi_device *sdev, void *arg) | ||
353 | { | ||
354 | VirtDevice *vdev; | ||
355 | VirtTarget *vtarget; | ||
356 | struct scsi_target *starget; | ||
357 | |||
358 | starget = scsi_target(sdev); | ||
359 | if (starget->hostdata == arg) { | ||
360 | vtarget = arg; | ||
361 | vdev = sdev->hostdata; | ||
362 | if (vdev) { | ||
363 | vdev->bus_id = vtarget->bus_id; | ||
364 | vdev->target_id = vtarget->target_id; | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | |||
369 | static void | ||
351 | mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) | 370 | mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) |
352 | { | 371 | { |
353 | struct fc_rport_identifiers rport_ids; | 372 | struct fc_rport_identifiers rport_ids; |
354 | struct fc_rport *rport; | 373 | struct fc_rport *rport; |
355 | struct mptfc_rport_info *ri; | 374 | struct mptfc_rport_info *ri; |
356 | int match = 0; | 375 | int new_ri = 1; |
357 | u64 port_name; | 376 | u64 pn; |
358 | unsigned long flags; | 377 | unsigned long flags; |
378 | VirtTarget *vtarget; | ||
359 | 379 | ||
360 | if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) | 380 | if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) |
361 | return; | 381 | return; |
@@ -363,14 +383,14 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) | |||
363 | /* scan list looking for a match */ | 383 | /* scan list looking for a match */ |
364 | spin_lock_irqsave(&ioc->fc_rport_lock, flags); | 384 | spin_lock_irqsave(&ioc->fc_rport_lock, flags); |
365 | list_for_each_entry(ri, &ioc->fc_rports, list) { | 385 | list_for_each_entry(ri, &ioc->fc_rports, list) { |
366 | port_name = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; | 386 | pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; |
367 | if (port_name == rport_ids.port_name) { /* match */ | 387 | if (pn == rport_ids.port_name) { /* match */ |
368 | list_move_tail(&ri->list, &ioc->fc_rports); | 388 | list_move_tail(&ri->list, &ioc->fc_rports); |
369 | match = 1; | 389 | new_ri = 0; |
370 | break; | 390 | break; |
371 | } | 391 | } |
372 | } | 392 | } |
373 | if (!match) { /* allocate one */ | 393 | if (new_ri) { /* allocate one */ |
374 | spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); | 394 | spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); |
375 | ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL); | 395 | ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL); |
376 | if (!ri) | 396 | if (!ri) |
@@ -382,40 +402,43 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) | |||
382 | ri->pg0 = *pg0; /* add/update pg0 data */ | 402 | ri->pg0 = *pg0; /* add/update pg0 data */ |
383 | ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING; | 403 | ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING; |
384 | 404 | ||
405 | /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */ | ||
385 | if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) { | 406 | if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) { |
386 | ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED; | 407 | ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED; |
387 | spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); | 408 | spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); |
388 | rport = fc_remote_port_add(ioc->sh,channel, &rport_ids); | 409 | rport = fc_remote_port_add(ioc->sh, channel, &rport_ids); |
389 | spin_lock_irqsave(&ioc->fc_rport_lock, flags); | 410 | spin_lock_irqsave(&ioc->fc_rport_lock, flags); |
390 | if (rport) { | 411 | if (rport) { |
391 | if (*((struct mptfc_rport_info **)rport->dd_data) != ri) { | 412 | ri->rport = rport; |
392 | ri->flags &= ~MPT_RPORT_INFO_FLAGS_MAPPED_VDEV; | 413 | if (new_ri) /* may have been reset by user */ |
393 | ri->vdev = NULL; | 414 | rport->dev_loss_tmo = mptfc_dev_loss_tmo; |
394 | ri->rport = rport; | 415 | *((struct mptfc_rport_info **)rport->dd_data) = ri; |
395 | *((struct mptfc_rport_info **)rport->dd_data) = ri; | ||
396 | } | ||
397 | rport->dev_loss_tmo = mptfc_dev_loss_tmo; | ||
398 | /* | 416 | /* |
399 | * if already mapped, remap here. If not mapped, | 417 | * if already mapped, remap here. If not mapped, |
400 | * slave_alloc will allocate vdev and map | 418 | * target_alloc will allocate vtarget and map, |
419 | * slave_alloc will fill in vdev from vtarget. | ||
401 | */ | 420 | */ |
402 | if (ri->flags & MPT_RPORT_INFO_FLAGS_MAPPED_VDEV) { | 421 | if (ri->starget) { |
403 | ri->vdev->target_id = ri->pg0.CurrentTargetID; | 422 | vtarget = ri->starget->hostdata; |
404 | ri->vdev->bus_id = ri->pg0.CurrentBus; | 423 | if (vtarget) { |
405 | ri->vdev->vtarget->target_id = ri->vdev->target_id; | 424 | vtarget->target_id = pg0->CurrentTargetID; |
406 | ri->vdev->vtarget->bus_id = ri->vdev->bus_id; | 425 | vtarget->bus_id = pg0->CurrentBus; |
426 | starget_for_each_device(ri->starget, | ||
427 | vtarget,mptfc_remap_sdev); | ||
428 | } | ||
429 | ri->remap_needed = 0; | ||
407 | } | 430 | } |
408 | #ifdef MPT_DEBUG | 431 | dfcprintk ((MYIOC_s_INFO_FMT |
409 | printk ("mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, " | 432 | "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, " |
410 | "rport tid %d, tmo %d\n", | 433 | "rport tid %d, tmo %d\n", |
411 | ioc->sh->host_no, | 434 | ioc->name, |
435 | oc->sh->host_no, | ||
412 | pg0->PortIdentifier, | 436 | pg0->PortIdentifier, |
413 | pg0->WWNN, | 437 | pg0->WWNN, |
414 | pg0->WWPN, | 438 | pg0->WWPN, |
415 | pg0->CurrentTargetID, | 439 | pg0->CurrentTargetID, |
416 | ri->rport->scsi_target_id, | 440 | ri->rport->scsi_target_id, |
417 | ri->rport->dev_loss_tmo); | 441 | ri->rport->dev_loss_tmo)); |
418 | #endif | ||
419 | } else { | 442 | } else { |
420 | list_del(&ri->list); | 443 | list_del(&ri->list); |
421 | kfree(ri); | 444 | kfree(ri); |
@@ -427,6 +450,65 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) | |||
427 | } | 450 | } |
428 | 451 | ||
429 | /* | 452 | /* |
453 | * OS entry point to allow for host driver to free allocated memory | ||
454 | * Called if no device present or device being unloaded | ||
455 | */ | ||
456 | static void | ||
457 | mptfc_target_destroy(struct scsi_target *starget) | ||
458 | { | ||
459 | struct fc_rport *rport; | ||
460 | struct mptfc_rport_info *ri; | ||
461 | |||
462 | rport = starget_to_rport(starget); | ||
463 | if (rport) { | ||
464 | ri = *((struct mptfc_rport_info **)rport->dd_data); | ||
465 | if (ri) /* better be! */ | ||
466 | ri->starget = NULL; | ||
467 | } | ||
468 | if (starget->hostdata) | ||
469 | kfree(starget->hostdata); | ||
470 | starget->hostdata = NULL; | ||
471 | } | ||
472 | |||
473 | /* | ||
474 | * OS entry point to allow host driver to alloc memory | ||
475 | * for each scsi target. Called once per device the bus scan. | ||
476 | * Return non-zero if allocation fails. | ||
477 | */ | ||
478 | static int | ||
479 | mptfc_target_alloc(struct scsi_target *starget) | ||
480 | { | ||
481 | VirtTarget *vtarget; | ||
482 | struct fc_rport *rport; | ||
483 | struct mptfc_rport_info *ri; | ||
484 | int rc; | ||
485 | |||
486 | vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); | ||
487 | if (!vtarget) | ||
488 | return -ENOMEM; | ||
489 | starget->hostdata = vtarget; | ||
490 | |||
491 | rc = -ENODEV; | ||
492 | rport = starget_to_rport(starget); | ||
493 | if (rport) { | ||
494 | ri = *((struct mptfc_rport_info **)rport->dd_data); | ||
495 | if (ri) { /* better be! */ | ||
496 | vtarget->target_id = ri->pg0.CurrentTargetID; | ||
497 | vtarget->bus_id = ri->pg0.CurrentBus; | ||
498 | ri->starget = starget; | ||
499 | ri->remap_needed = 0; | ||
500 | rc = 0; | ||
501 | } | ||
502 | } | ||
503 | if (rc != 0) { | ||
504 | kfree(vtarget); | ||
505 | starget->hostdata = NULL; | ||
506 | } | ||
507 | |||
508 | return rc; | ||
509 | } | ||
510 | |||
511 | /* | ||
430 | * OS entry point to allow host driver to alloc memory | 512 | * OS entry point to allow host driver to alloc memory |
431 | * for each scsi device. Called once per device the bus scan. | 513 | * for each scsi device. Called once per device the bus scan. |
432 | * Return non-zero if allocation fails. | 514 | * Return non-zero if allocation fails. |
@@ -440,7 +522,6 @@ mptfc_slave_alloc(struct scsi_device *sdev) | |||
440 | VirtDevice *vdev; | 522 | VirtDevice *vdev; |
441 | struct scsi_target *starget; | 523 | struct scsi_target *starget; |
442 | struct fc_rport *rport; | 524 | struct fc_rport *rport; |
443 | struct mptfc_rport_info *ri; | ||
444 | unsigned long flags; | 525 | unsigned long flags; |
445 | 526 | ||
446 | 527 | ||
@@ -451,55 +532,44 @@ mptfc_slave_alloc(struct scsi_device *sdev) | |||
451 | 532 | ||
452 | hd = (MPT_SCSI_HOST *)sdev->host->hostdata; | 533 | hd = (MPT_SCSI_HOST *)sdev->host->hostdata; |
453 | 534 | ||
454 | vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL); | 535 | vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); |
455 | if (!vdev) { | 536 | if (!vdev) { |
456 | printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", | 537 | printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", |
457 | hd->ioc->name, sizeof(VirtDevice)); | 538 | hd->ioc->name, sizeof(VirtDevice)); |
458 | return -ENOMEM; | 539 | return -ENOMEM; |
459 | } | 540 | } |
460 | memset(vdev, 0, sizeof(VirtDevice)); | ||
461 | 541 | ||
462 | spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags); | 542 | spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags); |
463 | 543 | ||
464 | if (!(ri = *((struct mptfc_rport_info **)rport->dd_data))) { | ||
465 | spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags); | ||
466 | kfree(vdev); | ||
467 | return -ENODEV; | ||
468 | } | ||
469 | |||
470 | sdev->hostdata = vdev; | 544 | sdev->hostdata = vdev; |
471 | starget = scsi_target(sdev); | 545 | starget = scsi_target(sdev); |
472 | vtarget = starget->hostdata; | 546 | vtarget = starget->hostdata; |
547 | |||
473 | if (vtarget->num_luns == 0) { | 548 | if (vtarget->num_luns == 0) { |
549 | vtarget->ioc_id = hd->ioc->id; | ||
474 | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES | | 550 | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES | |
475 | MPT_TARGET_FLAGS_VALID_INQUIRY; | 551 | MPT_TARGET_FLAGS_VALID_INQUIRY; |
476 | hd->Targets[sdev->id] = vtarget; | 552 | hd->Targets[sdev->id] = vtarget; |
477 | } | 553 | } |
478 | 554 | ||
479 | vtarget->target_id = vdev->target_id; | ||
480 | vtarget->bus_id = vdev->bus_id; | ||
481 | |||
482 | vdev->vtarget = vtarget; | 555 | vdev->vtarget = vtarget; |
483 | vdev->ioc_id = hd->ioc->id; | 556 | vdev->ioc_id = hd->ioc->id; |
484 | vdev->lun = sdev->lun; | 557 | vdev->lun = sdev->lun; |
485 | vdev->target_id = ri->pg0.CurrentTargetID; | 558 | vdev->target_id = vtarget->target_id; |
486 | vdev->bus_id = ri->pg0.CurrentBus; | 559 | vdev->bus_id = vtarget->bus_id; |
487 | |||
488 | ri->flags |= MPT_RPORT_INFO_FLAGS_MAPPED_VDEV; | ||
489 | ri->vdev = vdev; | ||
490 | 560 | ||
491 | spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags); | 561 | spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags); |
492 | 562 | ||
493 | vtarget->num_luns++; | 563 | vtarget->num_luns++; |
494 | 564 | ||
495 | #ifdef MPT_DEBUG | 565 | dfcprintk ((MYIOC_s_INFO_FMT |
496 | printk ("mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, " | 566 | "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, " |
497 | "CurrentTargetID %d, %x %llx %llx\n", | 567 | "CurrentTargetID %d, %x %llx %llx\n", |
498 | sdev->host->host_no, | 568 | ioc->name, |
499 | vtarget->num_luns, | 569 | sdev->host->host_no, |
500 | sdev->id, ri->pg0.CurrentTargetID, | 570 | vtarget->num_luns, |
501 | ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN); | 571 | sdev->id, ri->pg0.CurrentTargetID, |
502 | #endif | 572 | ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN)); |
503 | 573 | ||
504 | return 0; | 574 | return 0; |
505 | } | 575 | } |
@@ -507,6 +577,7 @@ mptfc_slave_alloc(struct scsi_device *sdev) | |||
507 | static int | 577 | static int |
508 | mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | 578 | mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) |
509 | { | 579 | { |
580 | struct mptfc_rport_info *ri; | ||
510 | struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); | 581 | struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); |
511 | int err; | 582 | int err; |
512 | 583 | ||
@@ -516,6 +587,10 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | |||
516 | done(SCpnt); | 587 | done(SCpnt); |
517 | return 0; | 588 | return 0; |
518 | } | 589 | } |
590 | ri = *((struct mptfc_rport_info **)rport->dd_data); | ||
591 | if (unlikely(ri->remap_needed)) | ||
592 | return SCSI_MLQUEUE_HOST_BUSY; | ||
593 | |||
519 | return mptscsih_qcmd(SCpnt,done); | 594 | return mptscsih_qcmd(SCpnt,done); |
520 | } | 595 | } |
521 | 596 | ||
@@ -591,16 +666,20 @@ mptfc_rescan_devices(void *arg) | |||
591 | 666 | ||
592 | ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| | 667 | ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| |
593 | MPT_RPORT_INFO_FLAGS_MISSING); | 668 | MPT_RPORT_INFO_FLAGS_MISSING); |
669 | ri->remap_needed = 1; | ||
594 | fc_remote_port_delete(ri->rport); | 670 | fc_remote_port_delete(ri->rport); |
595 | /* | 671 | /* |
596 | * remote port not really deleted 'cause | 672 | * remote port not really deleted 'cause |
597 | * binding is by WWPN and driver only | 673 | * binding is by WWPN and driver only |
598 | * registers FCP_TARGETs | 674 | * registers FCP_TARGETs but cannot trust |
675 | * data structures. | ||
599 | */ | 676 | */ |
600 | #ifdef MPT_DEBUG | 677 | ri->rport = NULL; |
601 | printk ("mptfc_rescan.%d: %llx deleted\n", | 678 | dfcprintk ((MYIOC_s_INFO_FMT |
602 | ioc->sh->host_no, ri->pg0.WWPN); | 679 | "mptfc_rescan.%d: %llx deleted\n", |
603 | #endif | 680 | ioc->name, |
681 | ioc->sh->host_no, | ||
682 | ri->pg0.WWPN)); | ||
604 | } | 683 | } |
605 | } | 684 | } |
606 | spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); | 685 | spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); |
@@ -872,9 +951,8 @@ mptfc_init(void) | |||
872 | } | 951 | } |
873 | 952 | ||
874 | error = pci_register_driver(&mptfc_driver); | 953 | error = pci_register_driver(&mptfc_driver); |
875 | if (error) { | 954 | if (error) |
876 | fc_release_transport(mptfc_transport_template); | 955 | fc_release_transport(mptfc_transport_template); |
877 | } | ||
878 | 956 | ||
879 | return error; | 957 | return error; |
880 | } | 958 | } |
@@ -885,7 +963,8 @@ mptfc_init(void) | |||
885 | * @pdev: Pointer to pci_dev structure | 963 | * @pdev: Pointer to pci_dev structure |
886 | * | 964 | * |
887 | */ | 965 | */ |
888 | static void __devexit mptfc_remove(struct pci_dev *pdev) | 966 | static void __devexit |
967 | mptfc_remove(struct pci_dev *pdev) | ||
889 | { | 968 | { |
890 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | 969 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
891 | struct mptfc_rport_info *p, *n; | 970 | struct mptfc_rport_info *p, *n; |