aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/message
diff options
context:
space:
mode:
authorEric Moore <eric.moore@lsi.com>2007-01-29 11:46:21 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-02-02 22:02:30 -0500
commitdf9e062ad994c4db683377b108c0dbed4690e4b0 (patch)
tree6953073b5fc45bc13b27847f0903f27dfe57f9bb /drivers/message
parentb506ade9f3c309ac2ce3ffc4039f731097506038 (diff)
[SCSI] fusion - serialize target resets in mptsas.c
Fusion firmware requires target reset following hotplug removal event, with purpose to flush target outstanding request in fw. Current implementation does the target resets from delayed work tasks, that in heavy load conditions, take too long to be invoked, resulting in command time outs This patch will issue target reset immediately from ISR context, and will queue remaining target resets to be issued after the previous one completes. The delayed work tasks are spawned during the target reset completion. Signed-off-by: Eric Moore <Eric.Moore@lsi.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/message')
-rw-r--r--drivers/message/fusion/mptbase.h1
-rw-r--r--drivers/message/fusion/mptsas.c325
2 files changed, 281 insertions, 45 deletions
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 07830d28e58d..7176944e201c 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -994,6 +994,7 @@ typedef struct _MPT_SCSI_HOST {
994 int scandv_wait_done; 994 int scandv_wait_done;
995 long last_queue_full; 995 long last_queue_full;
996 u16 tm_iocstatus; 996 u16 tm_iocstatus;
997 struct list_head target_reset_list;
997} MPT_SCSI_HOST; 998} MPT_SCSI_HOST;
998 999
999/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 1000/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index a8df06c422bd..3dbb5659f615 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -96,6 +96,12 @@ static int mptsasMgmtCtx = -1;
96 96
97static void mptsas_hotplug_work(struct work_struct *work); 97static void mptsas_hotplug_work(struct work_struct *work);
98 98
99struct mptsas_target_reset_event {
100 struct list_head list;
101 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
102 u8 target_reset_issued;
103};
104
99enum mptsas_hotplug_action { 105enum mptsas_hotplug_action {
100 MPTSAS_ADD_DEVICE, 106 MPTSAS_ADD_DEVICE,
101 MPTSAS_DEL_DEVICE, 107 MPTSAS_DEL_DEVICE,
@@ -571,20 +577,271 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
571 mutex_unlock(&ioc->sas_topology_mutex); 577 mutex_unlock(&ioc->sas_topology_mutex);
572} 578}
573 579
580/**
581 * csmisas_find_vtarget
582 *
583 * @ioc
584 * @volume_id
585 * @volume_bus
586 *
587 **/
588static VirtTarget *
589mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
590{
591 struct scsi_device *sdev;
592 VirtDevice *vdev;
593 VirtTarget *vtarget = NULL;
594
595 shost_for_each_device(sdev, ioc->sh) {
596 if ((vdev = sdev->hostdata) == NULL)
597 continue;
598 if (vdev->vtarget->id == id &&
599 vdev->vtarget->channel == channel)
600 vtarget = vdev->vtarget;
601 }
602 return vtarget;
603}
604
605/**
606 * mptsas_target_reset
607 *
608 * Issues TARGET_RESET to end device using handshaking method
609 *
610 * @ioc
611 * @channel
612 * @id
613 *
614 * Returns (1) success
615 * (0) failure
616 *
617 **/
618static int
619mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
620{
621 MPT_FRAME_HDR *mf;
622 SCSITaskMgmt_t *pScsiTm;
623
624 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
625 dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
626 ioc->name,__FUNCTION__, __LINE__));
627 return 0;
628 }
629
630 /* Format the Request
631 */
632 pScsiTm = (SCSITaskMgmt_t *) mf;
633 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
634 pScsiTm->TargetID = id;
635 pScsiTm->Bus = channel;
636 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
637 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
638 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
639
640 DBG_DUMP_TM_REQUEST_FRAME(mf);
641
642 if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
643 sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
644 mpt_free_msg_frame(ioc, mf);
645 dfailprintk((MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
646 ioc->name,__FUNCTION__, __LINE__));
647 return 0;
648 }
649
650 return 1;
651}
652
653/**
654 * mptsas_target_reset_queue
655 *
656 * Receive request for TARGET_RESET after recieving an firmware
657 * event NOT_RESPONDING_EVENT, then put command in link list
658 * and queue if task_queue already in use.
659 *
660 * @ioc
661 * @sas_event_data
662 *
663 **/
574static void 664static void
575mptsas_target_reset(MPT_ADAPTER *ioc, VirtTarget * vtarget) 665mptsas_target_reset_queue(MPT_ADAPTER *ioc,
666 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
576{ 667{
577 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; 668 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
669 VirtTarget *vtarget = NULL;
670 struct mptsas_target_reset_event *target_reset_list;
671 u8 id, channel;
578 672
579 if (mptscsih_TMHandler(hd, 673 id = sas_event_data->TargetID;
580 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 674 channel = sas_event_data->Bus;
581 vtarget->channel, vtarget->id, 0, 0, 5) < 0) { 675
582 hd->tmPending = 0; 676 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
583 hd->tmState = TM_STATE_NONE; 677 return;
584 printk(MYIOC_s_WARN_FMT 678
585 "Error processing TaskMgmt id=%d TARGET_RESET\n", 679 vtarget->deleted = 1; /* block IO */
586 ioc->name, vtarget->id); 680
681 target_reset_list = kzalloc(sizeof(*target_reset_list),
682 GFP_ATOMIC);
683 if (!target_reset_list) {
684 dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
685 ioc->name,__FUNCTION__, __LINE__));
686 return;
687 }
688
689 memcpy(&target_reset_list->sas_event_data, sas_event_data,
690 sizeof(*sas_event_data));
691 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
692
693 if (hd->resetPending)
694 return;
695
696 if (mptsas_target_reset(ioc, channel, id)) {
697 target_reset_list->target_reset_issued = 1;
698 hd->resetPending = 1;
699 }
700}
701
702/**
703 * mptsas_dev_reset_complete
704 *
705 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
706 * enable work queue to finish off removing device from upper layers.
707 * then send next TARGET_RESET in the queue.
708 *
709 * @ioc
710 *
711 **/
712static void
713mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
714{
715 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
716 struct list_head *head = &hd->target_reset_list;
717 struct mptsas_target_reset_event *target_reset_list;
718 struct mptsas_hotplug_event *ev;
719 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
720 u8 id, channel;
721 __le64 sas_address;
722
723 if (list_empty(head))
724 return;
725
726 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
727
728 sas_event_data = &target_reset_list->sas_event_data;
729 id = sas_event_data->TargetID;
730 channel = sas_event_data->Bus;
731 hd->resetPending = 0;
732
733 /*
734 * retry target reset
735 */
736 if (!target_reset_list->target_reset_issued) {
737 if (mptsas_target_reset(ioc, channel, id)) {
738 target_reset_list->target_reset_issued = 1;
739 hd->resetPending = 1;
740 }
741 return;
742 }
743
744 /*
745 * enable work queue to remove device from upper layers
746 */
747 list_del(&target_reset_list->list);
748
749 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
750 if (!ev) {
751 dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
752 ioc->name,__FUNCTION__, __LINE__));
753 return;
754 }
755
756 INIT_WORK(&ev->work, mptsas_hotplug_work);
757 ev->ioc = ioc;
758 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
759 ev->parent_handle =
760 le16_to_cpu(sas_event_data->ParentDevHandle);
761 ev->channel = channel;
762 ev->id =id;
763 ev->phy_id = sas_event_data->PhyNum;
764 memcpy(&sas_address, &sas_event_data->SASAddress,
765 sizeof(__le64));
766 ev->sas_address = le64_to_cpu(sas_address);
767 ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
768 ev->event_type = MPTSAS_DEL_DEVICE;
769 schedule_work(&ev->work);
770 kfree(target_reset_list);
771
772 /*
773 * issue target reset to next device in the queue
774 */
775
776 head = &hd->target_reset_list;
777 if (list_empty(head))
778 return;
779
780 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
781 list);
782
783 sas_event_data = &target_reset_list->sas_event_data;
784 id = sas_event_data->TargetID;
785 channel = sas_event_data->Bus;
786
787 if (mptsas_target_reset(ioc, channel, id)) {
788 target_reset_list->target_reset_issued = 1;
789 hd->resetPending = 1;
790 }
791}
792
793/**
794 * mptsas_taskmgmt_complete
795 *
796 * @ioc
797 * @mf
798 * @mr
799 *
800 **/
801static int
802mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
803{
804 mptsas_dev_reset_complete(ioc);
805 return mptscsih_taskmgmt_complete(ioc, mf, mr);
806}
807
808/**
809 * mptscsih_ioc_reset
810 *
811 * @ioc
812 * @reset_phase
813 *
814 **/
815static int
816mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
817{
818 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
819 struct mptsas_target_reset_event *target_reset_list, *n;
820 int rc;
821
822 rc = mptscsih_ioc_reset(ioc, reset_phase);
823
824 if (ioc->bus_type != SAS)
825 goto out;
826
827 if (reset_phase != MPT_IOC_POST_RESET)
828 goto out;
829
830 if (!hd || !hd->ioc)
831 goto out;
832
833 if (list_empty(&hd->target_reset_list))
834 goto out;
835
836 /* flush the target_reset_list */
837 list_for_each_entry_safe(target_reset_list, n,
838 &hd->target_reset_list, list) {
839 list_del(&target_reset_list->list);
840 kfree(target_reset_list);
587 } 841 }
842
843 out:
844 return rc;
588} 845}
589 846
590static int 847static int
@@ -1885,8 +2142,6 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
1885 struct mptsas_portinfo buffer; 2142 struct mptsas_portinfo buffer;
1886 struct mptsas_portinfo *port_info, *n, *parent; 2143 struct mptsas_portinfo *port_info, *n, *parent;
1887 struct mptsas_phyinfo *phy_info; 2144 struct mptsas_phyinfo *phy_info;
1888 struct scsi_target * starget;
1889 VirtTarget * vtarget;
1890 struct sas_port * port; 2145 struct sas_port * port;
1891 int i; 2146 int i;
1892 u64 expander_sas_address; 2147 u64 expander_sas_address;
@@ -1904,25 +2159,6 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
1904 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) { 2159 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {
1905 2160
1906 /* 2161 /*
1907 * Issue target reset to all child end devices
1908 * then mark them deleted to prevent further
1909 * IO going to them.
1910 */
1911 phy_info = port_info->phy_info;
1912 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
1913 starget = mptsas_get_starget(phy_info);
1914 if (!starget)
1915 continue;
1916 vtarget = starget->hostdata;
1917 if(vtarget->deleted)
1918 continue;
1919 vtarget->deleted = 1;
1920 mptsas_target_reset(ioc, vtarget);
1921 sas_port_delete(mptsas_get_port(phy_info));
1922 mptsas_port_delete(phy_info->port_details);
1923 }
1924
1925 /*
1926 * Obtain the port_info instance to the parent port 2162 * Obtain the port_info instance to the parent port
1927 */ 2163 */
1928 parent = mptsas_find_portinfo_by_handle(ioc, 2164 parent = mptsas_find_portinfo_by_handle(ioc,
@@ -2319,9 +2555,6 @@ mptsas_hotplug_work(struct work_struct *work)
2319 ev->phys_disk_num; 2555 ev->phys_disk_num;
2320 break; 2556 break;
2321 } 2557 }
2322
2323 vtarget->deleted = 1;
2324 mptsas_target_reset(ioc, vtarget);
2325 } 2558 }
2326 2559
2327 if (phy_info->attached.device_info & 2560 if (phy_info->attached.device_info &
@@ -2474,8 +2707,6 @@ mptsas_hotplug_work(struct work_struct *work)
2474 printk(MYIOC_s_INFO_FMT 2707 printk(MYIOC_s_INFO_FMT
2475 "removing raid volume, channel %d, id %d\n", 2708 "removing raid volume, channel %d, id %d\n",
2476 ioc->name, MPTSAS_RAID_CHANNEL, ev->id); 2709 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2477 vdevice->vtarget->deleted = 1;
2478 mptsas_target_reset(ioc, vdevice->vtarget);
2479 vdevice = sdev->hostdata; 2710 vdevice = sdev->hostdata;
2480 scsi_remove_device(sdev); 2711 scsi_remove_device(sdev);
2481 scsi_device_put(sdev); 2712 scsi_device_put(sdev);
@@ -2509,8 +2740,12 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc,
2509 return; 2740 return;
2510 2741
2511 switch (sas_event_data->ReasonCode) { 2742 switch (sas_event_data->ReasonCode) {
2512 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
2513 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: 2743 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
2744
2745 mptsas_target_reset_queue(ioc, sas_event_data);
2746 break;
2747
2748 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
2514 ev = kzalloc(sizeof(*ev), GFP_ATOMIC); 2749 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2515 if (!ev) { 2750 if (!ev) {
2516 printk(KERN_WARNING "mptsas: lost hotplug event\n"); 2751 printk(KERN_WARNING "mptsas: lost hotplug event\n");
@@ -2871,8 +3106,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2871 sh->sg_tablesize = numSGE; 3106 sh->sg_tablesize = numSGE;
2872 } 3107 }
2873 3108
2874 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2875
2876 hd = (MPT_SCSI_HOST *) sh->hostdata; 3109 hd = (MPT_SCSI_HOST *) sh->hostdata;
2877 hd->ioc = ioc; 3110 hd->ioc = ioc;
2878 3111
@@ -2912,15 +3145,17 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2912 3145
2913 ioc->sas_data.ptClear = mpt_pt_clear; 3146 ioc->sas_data.ptClear = mpt_pt_clear;
2914 3147
3148 init_waitqueue_head(&hd->scandv_waitq);
3149 hd->scandv_wait_done = 0;
3150 hd->last_queue_full = 0;
3151 INIT_LIST_HEAD(&hd->target_reset_list);
3152 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3153
2915 if (ioc->sas_data.ptClear==1) { 3154 if (ioc->sas_data.ptClear==1) {
2916 mptbase_sas_persist_operation( 3155 mptbase_sas_persist_operation(
2917 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT); 3156 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
2918 } 3157 }
2919 3158
2920 init_waitqueue_head(&hd->scandv_waitq);
2921 hd->scandv_wait_done = 0;
2922 hd->last_queue_full = 0;
2923
2924 error = scsi_add_host(sh, &ioc->pcidev->dev); 3159 error = scsi_add_host(sh, &ioc->pcidev->dev);
2925 if (error) { 3160 if (error) {
2926 dprintk((KERN_ERR MYNAM 3161 dprintk((KERN_ERR MYNAM
@@ -2999,7 +3234,7 @@ mptsas_init(void)
2999 return -ENODEV; 3234 return -ENODEV;
3000 3235
3001 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER); 3236 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
3002 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER); 3237 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
3003 mptsasInternalCtx = 3238 mptsasInternalCtx =
3004 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); 3239 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
3005 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); 3240 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
@@ -3009,7 +3244,7 @@ mptsas_init(void)
3009 ": Registered for IOC event notifications\n")); 3244 ": Registered for IOC event notifications\n"));
3010 } 3245 }
3011 3246
3012 if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) { 3247 if (mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset) == 0) {
3013 dprintk((KERN_INFO MYNAM 3248 dprintk((KERN_INFO MYNAM
3014 ": Registered for IOC reset notifications\n")); 3249 ": Registered for IOC reset notifications\n"));
3015 } 3250 }