diff options
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_transport.c')
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_transport.c | 89 |
1 files changed, 87 insertions, 2 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index bd7ca2b49f8..2727c3b6510 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * SAS Transport Layer for MPT (Message Passing Technology) based controllers | 2 | * SAS Transport Layer for MPT (Message Passing Technology) based controllers |
3 | * | 3 | * |
4 | * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c | 4 | * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c |
5 | * Copyright (C) 2007-2009 LSI Corporation | 5 | * Copyright (C) 2007-2010 LSI Corporation |
6 | * (mailto:DL-MPTFusionLinux@lsi.com) | 6 | * (mailto:DL-MPTFusionLinux@lsi.com) |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
@@ -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 | } |
@@ -1341,7 +1425,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
1341 | memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); | 1425 | memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); |
1342 | req->sense_len = sizeof(*mpi_reply); | 1426 | req->sense_len = sizeof(*mpi_reply); |
1343 | req->resid_len = 0; | 1427 | req->resid_len = 0; |
1344 | rsp->resid_len -= mpi_reply->ResponseDataLength; | 1428 | rsp->resid_len -= |
1429 | le16_to_cpu(mpi_reply->ResponseDataLength); | ||
1345 | } else { | 1430 | } else { |
1346 | dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT | 1431 | dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT |
1347 | "%s - no reply\n", ioc->name, __func__)); | 1432 | "%s - no reply\n", ioc->name, __func__)); |