aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c84
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 */
370struct _sas_phy { 371struct _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 */
485static 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 */
534static 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 }