diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_transport.c | 84 |
2 files changed, 86 insertions, 0 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 2616bb1597b0..454a74a3ec50 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h | |||
@@ -366,6 +366,7 @@ struct _sas_port { | |||
366 | * @phy_id: unique phy id | 366 | * @phy_id: unique phy id |
367 | * @handle: device handle for this phy | 367 | * @handle: device handle for this phy |
368 | * @attached_handle: device handle for attached device | 368 | * @attached_handle: device handle for attached device |
369 | * @phy_belongs_to_port: port has been created for this phy | ||
369 | */ | 370 | */ |
370 | struct _sas_phy { | 371 | struct _sas_phy { |
371 | struct list_head port_siblings; | 372 | struct list_head port_siblings; |
@@ -375,6 +376,7 @@ struct _sas_phy { | |||
375 | u8 phy_id; | 376 | u8 phy_id; |
376 | u16 handle; | 377 | u16 handle; |
377 | u16 attached_handle; | 378 | u16 attached_handle; |
379 | u8 phy_belongs_to_port; | ||
378 | }; | 380 | }; |
379 | 381 | ||
380 | /** | 382 | /** |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index bb2d2c93718b..2727c3b65104 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c | |||
@@ -465,6 +465,85 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, | |||
465 | return rc; | 465 | return rc; |
466 | } | 466 | } |
467 | 467 | ||
468 | |||
469 | /** | ||
470 | * _transport_delete_duplicate_port - (see below description) | ||
471 | * @ioc: per adapter object | ||
472 | * @sas_node: sas node object (either expander or sas host) | ||
473 | * @sas_address: sas address of device being added | ||
474 | * @phy_num: phy number | ||
475 | * | ||
476 | * This function is called when attempting to add a new port that is claiming | ||
477 | * the same phy resources already in use by another port. If we don't release | ||
478 | * the claimed phy resources, the sas transport layer will hang from the BUG | ||
479 | * in sas_port_add_phy. | ||
480 | * | ||
481 | * The reason we would hit this issue is becuase someone is changing the | ||
482 | * sas address of a device on the fly, meanwhile controller firmware sends | ||
483 | * EVENTs out of order when removing the previous instance of the device. | ||
484 | */ | ||
485 | static void | ||
486 | _transport_delete_duplicate_port(struct MPT2SAS_ADAPTER *ioc, | ||
487 | struct _sas_node *sas_node, u64 sas_address, int phy_num) | ||
488 | { | ||
489 | struct _sas_port *mpt2sas_port, *mpt2sas_port_duplicate; | ||
490 | struct _sas_phy *mpt2sas_phy; | ||
491 | |||
492 | printk(MPT2SAS_ERR_FMT "new device located at sas_addr(0x%016llx), " | ||
493 | "phy_id(%d)\n", ioc->name, (unsigned long long)sas_address, | ||
494 | phy_num); | ||
495 | |||
496 | mpt2sas_port_duplicate = NULL; | ||
497 | list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, port_list) { | ||
498 | dev_printk(KERN_ERR, &mpt2sas_port->port->dev, | ||
499 | "existing device at sas_addr(0x%016llx), num_phys(%d)\n", | ||
500 | (unsigned long long) | ||
501 | mpt2sas_port->remote_identify.sas_address, | ||
502 | mpt2sas_port->num_phys); | ||
503 | list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list, | ||
504 | port_siblings) { | ||
505 | dev_printk(KERN_ERR, &mpt2sas_phy->phy->dev, | ||
506 | "phy_number(%d)\n", mpt2sas_phy->phy_id); | ||
507 | if (mpt2sas_phy->phy_id == phy_num) | ||
508 | mpt2sas_port_duplicate = mpt2sas_port; | ||
509 | } | ||
510 | } | ||
511 | |||
512 | if (!mpt2sas_port_duplicate) | ||
513 | return; | ||
514 | |||
515 | dev_printk(KERN_ERR, &mpt2sas_port_duplicate->port->dev, | ||
516 | "deleting duplicate device at sas_addr(0x%016llx), phy(%d)!!!!\n", | ||
517 | (unsigned long long) | ||
518 | mpt2sas_port_duplicate->remote_identify.sas_address, phy_num); | ||
519 | ioc->logging_level |= MPT_DEBUG_TRANSPORT; | ||
520 | mpt2sas_transport_port_remove(ioc, | ||
521 | mpt2sas_port_duplicate->remote_identify.sas_address, | ||
522 | sas_node->sas_address); | ||
523 | ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; | ||
524 | } | ||
525 | |||
526 | /** | ||
527 | * _transport_sanity_check - sanity check when adding a new port | ||
528 | * @ioc: per adapter object | ||
529 | * @sas_node: sas node object (either expander or sas host) | ||
530 | * @sas_address: sas address of device being added | ||
531 | * | ||
532 | * See the explanation above from _transport_delete_duplicate_port | ||
533 | */ | ||
534 | static void | ||
535 | _transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node, | ||
536 | u64 sas_address) | ||
537 | { | ||
538 | int i; | ||
539 | |||
540 | for (i = 0; i < sas_node->num_phys; i++) | ||
541 | if (sas_node->phy[i].remote_identify.sas_address == sas_address) | ||
542 | if (sas_node->phy[i].phy_belongs_to_port) | ||
543 | _transport_delete_duplicate_port(ioc, sas_node, | ||
544 | sas_address, i); | ||
545 | } | ||
546 | |||
468 | /** | 547 | /** |
469 | * mpt2sas_transport_port_add - insert port to the list | 548 | * mpt2sas_transport_port_add - insert port to the list |
470 | * @ioc: per adapter object | 549 | * @ioc: per adapter object |
@@ -522,6 +601,9 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, | |||
522 | goto out_fail; | 601 | goto out_fail; |
523 | } | 602 | } |
524 | 603 | ||
604 | _transport_sanity_check(ioc, sas_node, | ||
605 | mpt2sas_port->remote_identify.sas_address); | ||
606 | |||
525 | for (i = 0; i < sas_node->num_phys; i++) { | 607 | for (i = 0; i < sas_node->num_phys; i++) { |
526 | if (sas_node->phy[i].remote_identify.sas_address != | 608 | if (sas_node->phy[i].remote_identify.sas_address != |
527 | mpt2sas_port->remote_identify.sas_address) | 609 | mpt2sas_port->remote_identify.sas_address) |
@@ -553,6 +635,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, | |||
553 | mpt2sas_port->remote_identify.sas_address, | 635 | mpt2sas_port->remote_identify.sas_address, |
554 | mpt2sas_phy->phy_id); | 636 | mpt2sas_phy->phy_id); |
555 | sas_port_add_phy(port, mpt2sas_phy->phy); | 637 | sas_port_add_phy(port, mpt2sas_phy->phy); |
638 | mpt2sas_phy->phy_belongs_to_port = 1; | ||
556 | } | 639 | } |
557 | 640 | ||
558 | mpt2sas_port->port = port; | 641 | mpt2sas_port->port = port; |
@@ -651,6 +734,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, | |||
651 | (unsigned long long) | 734 | (unsigned long long) |
652 | mpt2sas_port->remote_identify.sas_address, | 735 | mpt2sas_port->remote_identify.sas_address, |
653 | mpt2sas_phy->phy_id); | 736 | mpt2sas_phy->phy_id); |
737 | mpt2sas_phy->phy_belongs_to_port = 0; | ||
654 | sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); | 738 | sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); |
655 | list_del(&mpt2sas_phy->port_siblings); | 739 | list_del(&mpt2sas_phy->port_siblings); |
656 | } | 740 | } |