aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKashyap, Desai <kashyap.desai@lsi.com>2010-04-05 04:48:34 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-04-11 14:41:50 -0400
commit38c2911449b19664e0dc46132a7b4cb249ff5e06 (patch)
treeda6bbf3f397a0f6c443dc9b20d4ccef67aa56204
parent78d4e5a07dca7374dd9db40b3346d727b65eb794 (diff)
[SCSI] mpt2sas: sanity added to remove duplicate port from topology
There are few special cases which needs to be handled deleting old port. CASE1: In topology you need cascaded expanders. Through sysfs just make sure topology is up. Erase the manufacturing image of the cascaded expander and reset the board. In some cases Adapter will receive Exapnder Add event before expander delete. In such a case, driver needs to delete duplicate port before adding new port. CASE2: Enable Device Missing delay of HBA through lsiutils. If expander or end device is hotswapped with different device before DMD timer expires, driver will get device add for new device first and then device deletion event for the original devices will arrive later at DMD timer expires. In this case also driver need to delete duplicate port before adding port for new device. Added new function which will make sure when new port is added, that its not claiming the same phy resources already in use by another port. If it does, then it will delete the other port before adding the new port. Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-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 }