diff options
author | Kashyap, Desai <kashyap.desai@lsi.com> | 2009-05-29 07:17:26 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-06-09 18:41:36 -0400 |
commit | 3eb0822c6740c5564c37a2fe56449cdb4f3d800c (patch) | |
tree | 10c2a016020e4363b4db164b09f48530fbcaa517 /drivers | |
parent | ea2a788de4ce5ebab09276e25443f55592af2335 (diff) |
[SCSI] mpt fusion: Firmware event implementation using seperate WorkQueue
Now Firmware events are handled by firmware event queue.
Previously it was handled in interrupt context/WorkQueue of Linux.
Firmware Event handling is restructured and optimized.
Signed-off-by: Kashyap Desai <kadesai@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/message/fusion/mptbase.c | 10 | ||||
-rw-r--r-- | drivers/message/fusion/mptbase.h | 9 | ||||
-rw-r--r-- | drivers/message/fusion/mptsas.c | 1378 | ||||
-rw-r--r-- | drivers/message/fusion/mptsas.h | 33 |
4 files changed, 984 insertions, 446 deletions
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index ae203eca831..d67b26378a5 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c | |||
@@ -1931,6 +1931,11 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1931 | */ | 1931 | */ |
1932 | mpt_detect_bound_ports(ioc, pdev); | 1932 | mpt_detect_bound_ports(ioc, pdev); |
1933 | 1933 | ||
1934 | INIT_LIST_HEAD(&ioc->fw_event_list); | ||
1935 | spin_lock_init(&ioc->fw_event_lock); | ||
1936 | snprintf(ioc->fw_event_q_name, 20, "mpt/%d", ioc->id); | ||
1937 | ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name); | ||
1938 | |||
1934 | if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, | 1939 | if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, |
1935 | CAN_SLEEP)) != 0){ | 1940 | CAN_SLEEP)) != 0){ |
1936 | printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n", | 1941 | printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n", |
@@ -2010,6 +2015,11 @@ mpt_detach(struct pci_dev *pdev) | |||
2010 | cancel_delayed_work(&ioc->fault_reset_work); | 2015 | cancel_delayed_work(&ioc->fault_reset_work); |
2011 | destroy_workqueue(wq); | 2016 | destroy_workqueue(wq); |
2012 | 2017 | ||
2018 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
2019 | wq = ioc->fw_event_q; | ||
2020 | ioc->fw_event_q = NULL; | ||
2021 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
2022 | destroy_workqueue(wq); | ||
2013 | 2023 | ||
2014 | sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); | 2024 | sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); |
2015 | remove_proc_entry(pname, NULL); | 2025 | remove_proc_entry(pname, NULL); |
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 24d60128bfe..b6efc64e826 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h | |||
@@ -694,9 +694,18 @@ typedef struct _MPT_ADAPTER | |||
694 | struct net_device *netdev; | 694 | struct net_device *netdev; |
695 | struct list_head sas_topology; | 695 | struct list_head sas_topology; |
696 | struct mutex sas_topology_mutex; | 696 | struct mutex sas_topology_mutex; |
697 | |||
698 | struct workqueue_struct *fw_event_q; | ||
699 | struct list_head fw_event_list; | ||
700 | spinlock_t fw_event_lock; | ||
701 | u8 fw_events_off; /* if '1', then ignore events */ | ||
702 | char fw_event_q_name[20]; | ||
703 | |||
697 | struct mutex sas_discovery_mutex; | 704 | struct mutex sas_discovery_mutex; |
698 | u8 sas_discovery_runtime; | 705 | u8 sas_discovery_runtime; |
699 | u8 sas_discovery_ignore_events; | 706 | u8 sas_discovery_ignore_events; |
707 | struct list_head sas_device_info_list; | ||
708 | struct mutex sas_device_info_mutex; | ||
700 | u8 sas_discovery_quiesce_io; | 709 | u8 sas_discovery_quiesce_io; |
701 | int sas_index; /* index refrencing */ | 710 | int sas_index; /* index refrencing */ |
702 | MPT_MGMT sas_mgmt; | 711 | MPT_MGMT sas_mgmt; |
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index eb6b10eb11d..22a027ec9e5 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
@@ -95,7 +95,24 @@ static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for interna | |||
95 | static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; | 95 | static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; |
96 | static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; | 96 | static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; |
97 | 97 | ||
98 | static void mptsas_hotplug_work(struct work_struct *work); | 98 | static void mptsas_firmware_event_work(struct work_struct *work); |
99 | static void mptsas_send_sas_event(struct fw_event_work *fw_event); | ||
100 | static void mptsas_send_raid_event(struct fw_event_work *fw_event); | ||
101 | static void mptsas_send_ir2_event(struct fw_event_work *fw_event); | ||
102 | static void mptsas_parse_device_info(struct sas_identify *identify, | ||
103 | struct mptsas_devinfo *device_info); | ||
104 | static inline void mptsas_set_rphy(MPT_ADAPTER *ioc, | ||
105 | struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy); | ||
106 | static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address | ||
107 | (MPT_ADAPTER *ioc, u64 sas_address); | ||
108 | static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, | ||
109 | struct mptsas_devinfo *device_info, u32 form, u32 form_specific); | ||
110 | static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, | ||
111 | struct mptsas_enclosure *enclosure, u32 form, u32 form_specific); | ||
112 | static int mptsas_add_end_device(MPT_ADAPTER *ioc, | ||
113 | struct mptsas_phyinfo *phy_info); | ||
114 | static void mptsas_del_end_device(MPT_ADAPTER *ioc, | ||
115 | struct mptsas_phyinfo *phy_info); | ||
99 | 116 | ||
100 | static void mptsas_print_phy_data(MPT_ADAPTER *ioc, | 117 | static void mptsas_print_phy_data(MPT_ADAPTER *ioc, |
101 | MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) | 118 | MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) |
@@ -219,6 +236,100 @@ static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1) | |||
219 | le16_to_cpu(pg1->AttachedDevHandle))); | 236 | le16_to_cpu(pg1->AttachedDevHandle))); |
220 | } | 237 | } |
221 | 238 | ||
239 | /* inhibit sas firmware event handling */ | ||
240 | static void | ||
241 | mptsas_fw_event_off(MPT_ADAPTER *ioc) | ||
242 | { | ||
243 | unsigned long flags; | ||
244 | |||
245 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
246 | ioc->fw_events_off = 1; | ||
247 | ioc->sas_discovery_quiesce_io = 0; | ||
248 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
249 | |||
250 | } | ||
251 | |||
252 | /* enable sas firmware event handling */ | ||
253 | static void | ||
254 | mptsas_fw_event_on(MPT_ADAPTER *ioc) | ||
255 | { | ||
256 | unsigned long flags; | ||
257 | |||
258 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
259 | ioc->fw_events_off = 0; | ||
260 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
261 | } | ||
262 | |||
263 | /* queue a sas firmware event */ | ||
264 | static void | ||
265 | mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, | ||
266 | unsigned long delay) | ||
267 | { | ||
268 | unsigned long flags; | ||
269 | |||
270 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
271 | list_add_tail(&fw_event->list, &ioc->fw_event_list); | ||
272 | INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); | ||
273 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n", | ||
274 | ioc->name, __func__, fw_event)); | ||
275 | queue_delayed_work(ioc->fw_event_q, &fw_event->work, | ||
276 | delay); | ||
277 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
278 | } | ||
279 | |||
280 | /* free memory assoicated to a sas firmware event */ | ||
281 | static void | ||
282 | mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) | ||
283 | { | ||
284 | unsigned long flags; | ||
285 | |||
286 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
287 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n", | ||
288 | ioc->name, __func__, fw_event)); | ||
289 | list_del(&fw_event->list); | ||
290 | kfree(fw_event); | ||
291 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
292 | } | ||
293 | |||
294 | /* walk the firmware event queue, and either stop or wait for | ||
295 | * outstanding events to complete */ | ||
296 | static void | ||
297 | mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) | ||
298 | { | ||
299 | struct fw_event_work *fw_event, *next; | ||
300 | struct mptsas_target_reset_event *target_reset_list, *n; | ||
301 | u8 flush_q; | ||
302 | MPT_SCSI_HOST *hd = shost_priv(ioc->sh); | ||
303 | |||
304 | /* flush the target_reset_list */ | ||
305 | if (!list_empty(&hd->target_reset_list)) { | ||
306 | list_for_each_entry_safe(target_reset_list, n, | ||
307 | &hd->target_reset_list, list) { | ||
308 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
309 | "%s: removing target reset for id=%d\n", | ||
310 | ioc->name, __func__, | ||
311 | target_reset_list->sas_event_data.TargetID)); | ||
312 | list_del(&target_reset_list->list); | ||
313 | kfree(target_reset_list); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | if (list_empty(&ioc->fw_event_list) || | ||
318 | !ioc->fw_event_q || in_interrupt()) | ||
319 | return; | ||
320 | |||
321 | flush_q = 0; | ||
322 | list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { | ||
323 | if (cancel_delayed_work(&fw_event->work)) | ||
324 | mptsas_free_fw_event(ioc, fw_event); | ||
325 | else | ||
326 | flush_q = 1; | ||
327 | } | ||
328 | if (flush_q) | ||
329 | flush_workqueue(ioc->fw_event_q); | ||
330 | } | ||
331 | |||
332 | |||
222 | static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) | 333 | static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) |
223 | { | 334 | { |
224 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); | 335 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); |
@@ -309,6 +420,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai | |||
309 | if(phy_info->port_details != port_details) | 420 | if(phy_info->port_details != port_details) |
310 | continue; | 421 | continue; |
311 | memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); | 422 | memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); |
423 | mptsas_set_rphy(ioc, phy_info, NULL); | ||
312 | phy_info->port_details = NULL; | 424 | phy_info->port_details = NULL; |
313 | } | 425 | } |
314 | kfree(port_details); | 426 | kfree(port_details); |
@@ -380,6 +492,157 @@ starget) | |||
380 | phy_info->port_details->starget = starget; | 492 | phy_info->port_details->starget = starget; |
381 | } | 493 | } |
382 | 494 | ||
495 | /** | ||
496 | * mptsas_add_device_component - | ||
497 | * @ioc: Pointer to MPT_ADAPTER structure | ||
498 | * @channel: fw mapped id's | ||
499 | * @id: | ||
500 | * @sas_address: | ||
501 | * @device_info: | ||
502 | * | ||
503 | **/ | ||
504 | static void | ||
505 | mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id, | ||
506 | u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id) | ||
507 | { | ||
508 | struct mptsas_device_info *sas_info, *next; | ||
509 | struct scsi_device *sdev; | ||
510 | struct scsi_target *starget; | ||
511 | struct sas_rphy *rphy; | ||
512 | |||
513 | /* | ||
514 | * Delete all matching devices out of the list | ||
515 | */ | ||
516 | mutex_lock(&ioc->sas_device_info_mutex); | ||
517 | list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, | ||
518 | list) { | ||
519 | if ((sas_info->sas_address == sas_address || | ||
520 | (sas_info->fw.channel == channel && | ||
521 | sas_info->fw.id == id))) { | ||
522 | list_del(&sas_info->list); | ||
523 | kfree(sas_info); | ||
524 | } | ||
525 | } | ||
526 | |||
527 | sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); | ||
528 | if (!sas_info) | ||
529 | goto out; | ||
530 | |||
531 | /* | ||
532 | * Set Firmware mapping | ||
533 | */ | ||
534 | sas_info->fw.id = id; | ||
535 | sas_info->fw.channel = channel; | ||
536 | |||
537 | sas_info->sas_address = sas_address; | ||
538 | sas_info->device_info = device_info; | ||
539 | sas_info->slot = slot; | ||
540 | sas_info->enclosure_logical_id = enclosure_logical_id; | ||
541 | INIT_LIST_HEAD(&sas_info->list); | ||
542 | list_add_tail(&sas_info->list, &ioc->sas_device_info_list); | ||
543 | |||
544 | /* | ||
545 | * Set OS mapping | ||
546 | */ | ||
547 | shost_for_each_device(sdev, ioc->sh) { | ||
548 | starget = scsi_target(sdev); | ||
549 | rphy = dev_to_rphy(starget->dev.parent); | ||
550 | if (rphy->identify.sas_address == sas_address) { | ||
551 | sas_info->os.id = starget->id; | ||
552 | sas_info->os.channel = starget->channel; | ||
553 | } | ||
554 | } | ||
555 | |||
556 | out: | ||
557 | mutex_unlock(&ioc->sas_device_info_mutex); | ||
558 | return; | ||
559 | } | ||
560 | |||
561 | /** | ||
562 | * mptsas_add_device_component_by_fw - | ||
563 | * @ioc: Pointer to MPT_ADAPTER structure | ||
564 | * @channel: fw mapped id's | ||
565 | * @id: | ||
566 | * | ||
567 | **/ | ||
568 | static void | ||
569 | mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) | ||
570 | { | ||
571 | struct mptsas_devinfo sas_device; | ||
572 | struct mptsas_enclosure enclosure_info; | ||
573 | int rc; | ||
574 | |||
575 | rc = mptsas_sas_device_pg0(ioc, &sas_device, | ||
576 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | ||
577 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | ||
578 | (channel << 8) + id); | ||
579 | if (rc) | ||
580 | return; | ||
581 | |||
582 | memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); | ||
583 | mptsas_sas_enclosure_pg0(ioc, &enclosure_info, | ||
584 | (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << | ||
585 | MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), | ||
586 | sas_device.handle_enclosure); | ||
587 | |||
588 | mptsas_add_device_component(ioc, sas_device.channel, | ||
589 | sas_device.id, sas_device.sas_address, sas_device.device_info, | ||
590 | sas_device.slot, enclosure_info.enclosure_logical_id); | ||
591 | } | ||
592 | |||
593 | /** | ||
594 | * mptsas_add_device_component_starget - | ||
595 | * @ioc: Pointer to MPT_ADAPTER structure | ||
596 | * @starget: | ||
597 | * | ||
598 | **/ | ||
599 | static void | ||
600 | mptsas_add_device_component_starget(MPT_ADAPTER *ioc, | ||
601 | struct scsi_target *starget) | ||
602 | { | ||
603 | VirtTarget *vtarget; | ||
604 | struct sas_rphy *rphy; | ||
605 | struct mptsas_phyinfo *phy_info = NULL; | ||
606 | struct mptsas_enclosure enclosure_info; | ||
607 | |||
608 | rphy = dev_to_rphy(starget->dev.parent); | ||
609 | vtarget = starget->hostdata; | ||
610 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, | ||
611 | rphy->identify.sas_address); | ||
612 | if (!phy_info) | ||
613 | return; | ||
614 | |||
615 | memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); | ||
616 | mptsas_sas_enclosure_pg0(ioc, &enclosure_info, | ||
617 | (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << | ||
618 | MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), | ||
619 | phy_info->attached.handle_enclosure); | ||
620 | |||
621 | mptsas_add_device_component(ioc, phy_info->attached.channel, | ||
622 | phy_info->attached.id, phy_info->attached.sas_address, | ||
623 | phy_info->attached.device_info, | ||
624 | phy_info->attached.slot, enclosure_info.enclosure_logical_id); | ||
625 | } | ||
626 | |||
627 | /** | ||
628 | * mptsas_del_device_components - Cleaning the list | ||
629 | * @ioc: Pointer to MPT_ADAPTER structure | ||
630 | * | ||
631 | **/ | ||
632 | static void | ||
633 | mptsas_del_device_components(MPT_ADAPTER *ioc) | ||
634 | { | ||
635 | struct mptsas_device_info *sas_info, *next; | ||
636 | |||
637 | mutex_lock(&ioc->sas_device_info_mutex); | ||
638 | list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, | ||
639 | list) { | ||
640 | list_del(&sas_info->list); | ||
641 | kfree(sas_info); | ||
642 | } | ||
643 | mutex_unlock(&ioc->sas_device_info_mutex); | ||
644 | } | ||
645 | |||
383 | 646 | ||
384 | /* | 647 | /* |
385 | * mptsas_setup_wide_ports | 648 | * mptsas_setup_wide_ports |
@@ -535,6 +798,29 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
535 | return vtarget; | 798 | return vtarget; |
536 | } | 799 | } |
537 | 800 | ||
801 | static void | ||
802 | mptsas_queue_device_delete(MPT_ADAPTER *ioc, | ||
803 | MpiEventDataSasDeviceStatusChange_t *sas_event_data) | ||
804 | { | ||
805 | struct fw_event_work *fw_event; | ||
806 | int sz; | ||
807 | |||
808 | sz = offsetof(struct fw_event_work, event_data) + | ||
809 | sizeof(MpiEventDataSasDeviceStatusChange_t); | ||
810 | fw_event = kzalloc(sz, GFP_ATOMIC); | ||
811 | if (!fw_event) { | ||
812 | printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", | ||
813 | ioc->name, __func__, __LINE__); | ||
814 | return; | ||
815 | } | ||
816 | memcpy(fw_event->event_data, sas_event_data, | ||
817 | sizeof(MpiEventDataSasDeviceStatusChange_t)); | ||
818 | fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE; | ||
819 | fw_event->ioc = ioc; | ||
820 | mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); | ||
821 | } | ||
822 | |||
823 | |||
538 | /** | 824 | /** |
539 | * mptsas_target_reset | 825 | * mptsas_target_reset |
540 | * | 826 | * |
@@ -654,10 +940,8 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) | |||
654 | { | 940 | { |
655 | MPT_SCSI_HOST *hd = shost_priv(ioc->sh); | 941 | MPT_SCSI_HOST *hd = shost_priv(ioc->sh); |
656 | struct list_head *head = &hd->target_reset_list; | 942 | struct list_head *head = &hd->target_reset_list; |
657 | struct mptsas_hotplug_event *ev; | ||
658 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; | 943 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; |
659 | u8 id, channel; | 944 | u8 id, channel; |
660 | __le64 sas_address; | ||
661 | struct mptsas_target_reset_event *target_reset_list; | 945 | struct mptsas_target_reset_event *target_reset_list; |
662 | SCSITaskMgmtReply_t *pScsiTmReply; | 946 | SCSITaskMgmtReply_t *pScsiTmReply; |
663 | 947 | ||
@@ -729,41 +1013,9 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) | |||
729 | * enable work queue to remove device from upper layers | 1013 | * enable work queue to remove device from upper layers |
730 | */ | 1014 | */ |
731 | list_del(&target_reset_list->list); | 1015 | list_del(&target_reset_list->list); |
732 | 1016 | if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off) | |
733 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 1017 | mptsas_queue_device_delete(ioc, |
734 | if (!ev) { | 1018 | &target_reset_list->sas_event_data); |
735 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", | ||
736 | ioc->name,__func__, __LINE__)); | ||
737 | goto out_fail; | ||
738 | } | ||
739 | |||
740 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", | ||
741 | ioc->name, mf)); | ||
742 | |||
743 | INIT_WORK(&ev->work, mptsas_hotplug_work); | ||
744 | ev->ioc = ioc; | ||
745 | ev->handle = le16_to_cpu(sas_event_data->DevHandle); | ||
746 | ev->parent_handle = | ||
747 | le16_to_cpu(sas_event_data->ParentDevHandle); | ||
748 | ev->channel = channel; | ||
749 | ev->id =id; | ||
750 | ev->phy_id = sas_event_data->PhyNum; | ||
751 | memcpy(&sas_address, &sas_event_data->SASAddress, | ||
752 | sizeof(__le64)); | ||
753 | ev->sas_address = le64_to_cpu(sas_address); | ||
754 | ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo); | ||
755 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
756 | "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n", | ||
757 | ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id)); | ||
758 | |||
759 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
760 | schedule_work(&ev->work); | ||
761 | kfree(target_reset_list); | ||
762 | |||
763 | out_fail: | ||
764 | |||
765 | mpt_clear_taskmgmt_in_progress_flag(ioc); | ||
766 | return 0; | ||
767 | 1019 | ||
768 | 1020 | ||
769 | /* | 1021 | /* |
@@ -798,37 +1050,58 @@ static int | |||
798 | mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) | 1050 | mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) |
799 | { | 1051 | { |
800 | MPT_SCSI_HOST *hd; | 1052 | MPT_SCSI_HOST *hd; |
801 | struct mptsas_target_reset_event *target_reset_list, *n; | ||
802 | int rc; | 1053 | int rc; |
803 | 1054 | ||
804 | rc = mptscsih_ioc_reset(ioc, reset_phase); | 1055 | rc = mptscsih_ioc_reset(ioc, reset_phase); |
1056 | if ((ioc->bus_type != SAS) || (!rc)) | ||
1057 | return rc; | ||
805 | 1058 | ||
806 | if (ioc->bus_type != SAS) | ||
807 | goto out; | ||
808 | |||
809 | if (reset_phase != MPT_IOC_POST_RESET) | ||
810 | goto out; | ||
811 | |||
812 | if (!ioc->sh || !ioc->sh->hostdata) | ||
813 | goto out; | ||
814 | hd = shost_priv(ioc->sh); | 1059 | hd = shost_priv(ioc->sh); |
815 | if (!hd->ioc) | 1060 | if (!hd->ioc) |
816 | goto out; | 1061 | goto out; |
817 | 1062 | ||
818 | if (list_empty(&hd->target_reset_list)) | 1063 | switch (reset_phase) { |
819 | goto out; | 1064 | case MPT_IOC_SETUP_RESET: |
820 | 1065 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | |
821 | /* flush the target_reset_list */ | 1066 | "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); |
822 | list_for_each_entry_safe(target_reset_list, n, | 1067 | mptsas_fw_event_off(ioc); |
823 | &hd->target_reset_list, list) { | 1068 | break; |
824 | list_del(&target_reset_list->list); | 1069 | case MPT_IOC_PRE_RESET: |
825 | kfree(target_reset_list); | 1070 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
1071 | "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); | ||
1072 | break; | ||
1073 | case MPT_IOC_POST_RESET: | ||
1074 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
1075 | "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); | ||
1076 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { | ||
1077 | ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; | ||
1078 | complete(&ioc->sas_mgmt.done); | ||
1079 | } | ||
1080 | mptsas_cleanup_fw_event_q(ioc); | ||
1081 | mptsas_fw_event_on(ioc); | ||
1082 | break; | ||
1083 | default: | ||
1084 | break; | ||
826 | } | 1085 | } |
827 | 1086 | ||
828 | out: | 1087 | out: |
829 | return rc; | 1088 | return rc; |
830 | } | 1089 | } |
831 | 1090 | ||
1091 | |||
1092 | /** | ||
1093 | * enum device_state - | ||
1094 | * @DEVICE_RETRY: need to retry the TUR | ||
1095 | * @DEVICE_ERROR: TUR return error, don't add device | ||
1096 | * @DEVICE_READY: device can be added | ||
1097 | * | ||
1098 | */ | ||
1099 | enum device_state{ | ||
1100 | DEVICE_RETRY, | ||
1101 | DEVICE_ERROR, | ||
1102 | DEVICE_READY, | ||
1103 | }; | ||
1104 | |||
832 | static int | 1105 | static int |
833 | mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, | 1106 | mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, |
834 | u32 form, u32 form_specific) | 1107 | u32 form, u32 form_specific) |
@@ -894,15 +1167,268 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, | |||
894 | return error; | 1167 | return error; |
895 | } | 1168 | } |
896 | 1169 | ||
1170 | /** | ||
1171 | * mptsas_add_end_device - report a new end device to sas transport layer | ||
1172 | * @ioc: Pointer to MPT_ADAPTER structure | ||
1173 | * @phy_info: decribes attached device | ||
1174 | * | ||
1175 | * return (0) success (1) failure | ||
1176 | * | ||
1177 | **/ | ||
1178 | static int | ||
1179 | mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) | ||
1180 | { | ||
1181 | struct sas_rphy *rphy; | ||
1182 | struct sas_port *port; | ||
1183 | struct sas_identify identify; | ||
1184 | char *ds = NULL; | ||
1185 | u8 fw_id; | ||
1186 | |||
1187 | if (!phy_info) { | ||
1188 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1189 | "%s: exit at line=%d\n", ioc->name, | ||
1190 | __func__, __LINE__)); | ||
1191 | return 1; | ||
1192 | } | ||
1193 | |||
1194 | fw_id = phy_info->attached.id; | ||
1195 | |||
1196 | if (mptsas_get_rphy(phy_info)) { | ||
1197 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1198 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1199 | __func__, fw_id, __LINE__)); | ||
1200 | return 2; | ||
1201 | } | ||
1202 | |||
1203 | port = mptsas_get_port(phy_info); | ||
1204 | if (!port) { | ||
1205 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1206 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1207 | __func__, fw_id, __LINE__)); | ||
1208 | return 3; | ||
1209 | } | ||
1210 | |||
1211 | if (phy_info->attached.device_info & | ||
1212 | MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
1213 | ds = "ssp"; | ||
1214 | if (phy_info->attached.device_info & | ||
1215 | MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
1216 | ds = "stp"; | ||
1217 | if (phy_info->attached.device_info & | ||
1218 | MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
1219 | ds = "sata"; | ||
1220 | |||
1221 | printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d," | ||
1222 | " phy %d, sas_addr 0x%llx\n", ioc->name, ds, | ||
1223 | phy_info->attached.channel, phy_info->attached.id, | ||
1224 | phy_info->attached.phy_id, (unsigned long long) | ||
1225 | phy_info->attached.sas_address); | ||
1226 | |||
1227 | mptsas_parse_device_info(&identify, &phy_info->attached); | ||
1228 | rphy = sas_end_device_alloc(port); | ||
1229 | if (!rphy) { | ||
1230 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1231 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1232 | __func__, fw_id, __LINE__)); | ||
1233 | return 5; /* non-fatal: an rphy can be added later */ | ||
1234 | } | ||
1235 | |||
1236 | rphy->identify = identify; | ||
1237 | if (sas_rphy_add(rphy)) { | ||
1238 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1239 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1240 | __func__, fw_id, __LINE__)); | ||
1241 | sas_rphy_free(rphy); | ||
1242 | return 6; | ||
1243 | } | ||
1244 | mptsas_set_rphy(ioc, phy_info, rphy); | ||
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1248 | /** | ||
1249 | * mptsas_del_end_device - report a deleted end device to sas transport | ||
1250 | * layer | ||
1251 | * @ioc: Pointer to MPT_ADAPTER structure | ||
1252 | * @phy_info: decribes attached device | ||
1253 | * | ||
1254 | **/ | ||
1255 | static void | ||
1256 | mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) | ||
1257 | { | ||
1258 | struct sas_rphy *rphy; | ||
1259 | struct sas_port *port; | ||
1260 | struct mptsas_portinfo *port_info; | ||
1261 | struct mptsas_phyinfo *phy_info_parent; | ||
1262 | int i; | ||
1263 | char *ds = NULL; | ||
1264 | u8 fw_id; | ||
1265 | u64 sas_address; | ||
1266 | |||
1267 | if (!phy_info) | ||
1268 | return; | ||
1269 | |||
1270 | fw_id = phy_info->attached.id; | ||
1271 | sas_address = phy_info->attached.sas_address; | ||
1272 | |||
1273 | if (!phy_info->port_details) { | ||
1274 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1275 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1276 | __func__, fw_id, __LINE__)); | ||
1277 | return; | ||
1278 | } | ||
1279 | rphy = mptsas_get_rphy(phy_info); | ||
1280 | if (!rphy) { | ||
1281 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1282 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1283 | __func__, fw_id, __LINE__)); | ||
1284 | return; | ||
1285 | } | ||
1286 | |||
1287 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR | ||
1288 | || phy_info->attached.device_info | ||
1289 | & MPI_SAS_DEVICE_INFO_SMP_INITIATOR | ||
1290 | || phy_info->attached.device_info | ||
1291 | & MPI_SAS_DEVICE_INFO_STP_INITIATOR) | ||
1292 | ds = "initiator"; | ||
1293 | if (phy_info->attached.device_info & | ||
1294 | MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
1295 | ds = "ssp"; | ||
1296 | if (phy_info->attached.device_info & | ||
1297 | MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
1298 | ds = "stp"; | ||
1299 | if (phy_info->attached.device_info & | ||
1300 | MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
1301 | ds = "sata"; | ||
1302 | |||
1303 | dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT | ||
1304 | "removing %s device: fw_channel %d, fw_id %d, phy %d," | ||
1305 | "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel, | ||
1306 | phy_info->attached.id, phy_info->attached.phy_id, | ||
1307 | (unsigned long long) sas_address); | ||
1308 | |||
1309 | port = mptsas_get_port(phy_info); | ||
1310 | if (!port) { | ||
1311 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1312 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1313 | __func__, fw_id, __LINE__)); | ||
1314 | return; | ||
1315 | } | ||
1316 | port_info = phy_info->portinfo; | ||
1317 | phy_info_parent = port_info->phy_info; | ||
1318 | for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) { | ||
1319 | if (!phy_info_parent->phy) | ||
1320 | continue; | ||
1321 | if (phy_info_parent->attached.sas_address != | ||
1322 | sas_address) | ||
1323 | continue; | ||
1324 | dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev, | ||
1325 | MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", | ||
1326 | ioc->name, phy_info_parent->phy_id, | ||
1327 | phy_info_parent->phy); | ||
1328 | sas_port_delete_phy(port, phy_info_parent->phy); | ||
1329 | } | ||
1330 | |||
1331 | dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT | ||
1332 | "delete port %d, sas_addr (0x%llx)\n", ioc->name, | ||
1333 | port->port_identifier, (unsigned long long)sas_address); | ||
1334 | sas_port_delete(port); | ||
1335 | mptsas_set_port(ioc, phy_info, NULL); | ||
1336 | mptsas_port_delete(ioc, phy_info->port_details); | ||
1337 | } | ||
1338 | |||
1339 | struct mptsas_phyinfo * | ||
1340 | mptsas_refreshing_device_handles(MPT_ADAPTER *ioc, | ||
1341 | struct mptsas_devinfo *sas_device) | ||
1342 | { | ||
1343 | struct mptsas_phyinfo *phy_info; | ||
1344 | struct mptsas_portinfo *port_info; | ||
1345 | int i; | ||
1346 | |||
1347 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, | ||
1348 | sas_device->sas_address); | ||
1349 | if (!phy_info) | ||
1350 | goto out; | ||
1351 | port_info = phy_info->portinfo; | ||
1352 | if (!port_info) | ||
1353 | goto out; | ||
1354 | mutex_lock(&ioc->sas_topology_mutex); | ||
1355 | for (i = 0; i < port_info->num_phys; i++) { | ||
1356 | if (port_info->phy_info[i].attached.sas_address != | ||
1357 | sas_device->sas_address) | ||
1358 | continue; | ||
1359 | port_info->phy_info[i].attached.channel = sas_device->channel; | ||
1360 | port_info->phy_info[i].attached.id = sas_device->id; | ||
1361 | port_info->phy_info[i].attached.sas_address = | ||
1362 | sas_device->sas_address; | ||
1363 | port_info->phy_info[i].attached.handle = sas_device->handle; | ||
1364 | port_info->phy_info[i].attached.handle_parent = | ||
1365 | sas_device->handle_parent; | ||
1366 | port_info->phy_info[i].attached.handle_enclosure = | ||
1367 | sas_device->handle_enclosure; | ||
1368 | } | ||
1369 | mutex_unlock(&ioc->sas_topology_mutex); | ||
1370 | out: | ||
1371 | return phy_info; | ||
1372 | } | ||
1373 | |||
1374 | /** | ||
1375 | * mptsas_firmware_event_work - work thread for processing fw events | ||
1376 | * @work: work queue payload containing info describing the event | ||
1377 | * Context: user | ||
1378 | * | ||
1379 | */ | ||
1380 | static void | ||
1381 | mptsas_firmware_event_work(struct work_struct *work) | ||
1382 | { | ||
1383 | struct fw_event_work *fw_event = | ||
1384 | container_of(work, struct fw_event_work, work.work); | ||
1385 | MPT_ADAPTER *ioc = fw_event->ioc; | ||
1386 | |||
1387 | |||
1388 | /* events handling turned off during host reset */ | ||
1389 | if (ioc->fw_events_off) { | ||
1390 | mptsas_free_fw_event(ioc, fw_event); | ||
1391 | return; | ||
1392 | } | ||
1393 | |||
1394 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), " | ||
1395 | "event = (0x%02x)\n", ioc->name, __func__, fw_event, | ||
1396 | (fw_event->event & 0xFF))); | ||
1397 | |||
1398 | switch (fw_event->event) { | ||
1399 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | ||
1400 | mptsas_send_sas_event(fw_event); | ||
1401 | break; | ||
1402 | case MPI_EVENT_INTEGRATED_RAID: | ||
1403 | mptsas_send_raid_event(fw_event); | ||
1404 | break; | ||
1405 | case MPI_EVENT_IR2: | ||
1406 | mptsas_send_ir2_event(fw_event); | ||
1407 | break; | ||
1408 | case MPI_EVENT_PERSISTENT_TABLE_FULL: | ||
1409 | mptbase_sas_persist_operation(ioc, | ||
1410 | MPI_SAS_OP_CLEAR_NOT_PRESENT); | ||
1411 | mptsas_free_fw_event(ioc, fw_event); | ||
1412 | break; | ||
1413 | } | ||
1414 | } | ||
1415 | |||
1416 | |||
1417 | |||
897 | static int | 1418 | static int |
898 | mptsas_slave_configure(struct scsi_device *sdev) | 1419 | mptsas_slave_configure(struct scsi_device *sdev) |
899 | { | 1420 | { |
1421 | struct Scsi_Host *host = sdev->host; | ||
1422 | MPT_SCSI_HOST *hd = shost_priv(host); | ||
1423 | MPT_ADAPTER *ioc = hd->ioc; | ||
900 | 1424 | ||
901 | if (sdev->channel == MPTSAS_RAID_CHANNEL) | 1425 | if (sdev->channel == MPTSAS_RAID_CHANNEL) |
902 | goto out; | 1426 | goto out; |
903 | 1427 | ||
904 | sas_read_port_mode_page(sdev); | 1428 | sas_read_port_mode_page(sdev); |
905 | 1429 | ||
1430 | mptsas_add_device_component_starget(ioc, scsi_target(sdev)); | ||
1431 | |||
906 | out: | 1432 | out: |
907 | return mptscsih_slave_configure(sdev); | 1433 | return mptscsih_slave_configure(sdev); |
908 | } | 1434 | } |
@@ -984,11 +1510,15 @@ mptsas_target_destroy(struct scsi_target *starget) | |||
984 | struct sas_rphy *rphy; | 1510 | struct sas_rphy *rphy; |
985 | struct mptsas_portinfo *p; | 1511 | struct mptsas_portinfo *p; |
986 | int i; | 1512 | int i; |
987 | MPT_ADAPTER *ioc = hd->ioc; | 1513 | MPT_ADAPTER *ioc = hd->ioc; |
1514 | VirtTarget *vtarget; | ||
988 | 1515 | ||
989 | if (!starget->hostdata) | 1516 | if (!starget->hostdata) |
990 | return; | 1517 | return; |
991 | 1518 | ||
1519 | vtarget = starget->hostdata; | ||
1520 | |||
1521 | |||
992 | if (starget->channel == MPTSAS_RAID_CHANNEL) | 1522 | if (starget->channel == MPTSAS_RAID_CHANNEL) |
993 | goto out; | 1523 | goto out; |
994 | 1524 | ||
@@ -998,12 +1528,21 @@ mptsas_target_destroy(struct scsi_target *starget) | |||
998 | if (p->phy_info[i].attached.sas_address != | 1528 | if (p->phy_info[i].attached.sas_address != |
999 | rphy->identify.sas_address) | 1529 | rphy->identify.sas_address) |
1000 | continue; | 1530 | continue; |
1531 | |||
1532 | starget_printk(KERN_INFO, starget, MYIOC_s_FMT | ||
1533 | "delete device: fw_channel %d, fw_id %d, phy %d, " | ||
1534 | "sas_addr 0x%llx\n", ioc->name, | ||
1535 | p->phy_info[i].attached.channel, | ||
1536 | p->phy_info[i].attached.id, | ||
1537 | p->phy_info[i].attached.phy_id, (unsigned long long) | ||
1538 | p->phy_info[i].attached.sas_address); | ||
1539 | |||
1001 | mptsas_set_starget(&p->phy_info[i], NULL); | 1540 | mptsas_set_starget(&p->phy_info[i], NULL); |
1002 | goto out; | ||
1003 | } | 1541 | } |
1004 | } | 1542 | } |
1005 | 1543 | ||
1006 | out: | 1544 | out: |
1545 | vtarget->starget = NULL; | ||
1007 | kfree(starget->hostdata); | 1546 | kfree(starget->hostdata); |
1008 | starget->hostdata = NULL; | 1547 | starget->hostdata = NULL; |
1009 | } | 1548 | } |
@@ -2471,6 +3010,7 @@ mptsas_discovery_work(struct work_struct *work) | |||
2471 | kfree(ev); | 3010 | kfree(ev); |
2472 | } | 3011 | } |
2473 | 3012 | ||
3013 | |||
2474 | static struct mptsas_phyinfo * | 3014 | static struct mptsas_phyinfo * |
2475 | mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) | 3015 | mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) |
2476 | { | 3016 | { |
@@ -2495,30 +3035,6 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) | |||
2495 | return phy_info; | 3035 | return phy_info; |
2496 | } | 3036 | } |
2497 | 3037 | ||
2498 | static struct mptsas_phyinfo * | ||
2499 | mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id) | ||
2500 | { | ||
2501 | struct mptsas_portinfo *port_info; | ||
2502 | struct mptsas_phyinfo *phy_info = NULL; | ||
2503 | int i; | ||
2504 | |||
2505 | mutex_lock(&ioc->sas_topology_mutex); | ||
2506 | list_for_each_entry(port_info, &ioc->sas_topology, list) { | ||
2507 | for (i = 0; i < port_info->num_phys; i++) { | ||
2508 | if (!mptsas_is_end_device( | ||
2509 | &port_info->phy_info[i].attached)) | ||
2510 | continue; | ||
2511 | if (port_info->phy_info[i].attached.id != id) | ||
2512 | continue; | ||
2513 | if (port_info->phy_info[i].attached.channel != channel) | ||
2514 | continue; | ||
2515 | phy_info = &port_info->phy_info[i]; | ||
2516 | break; | ||
2517 | } | ||
2518 | } | ||
2519 | mutex_unlock(&ioc->sas_topology_mutex); | ||
2520 | return phy_info; | ||
2521 | } | ||
2522 | 3038 | ||
2523 | static struct mptsas_phyinfo * | 3039 | static struct mptsas_phyinfo * |
2524 | mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id) | 3040 | mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id) |
@@ -2547,17 +3063,6 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
2547 | return phy_info; | 3063 | return phy_info; |
2548 | } | 3064 | } |
2549 | 3065 | ||
2550 | /* | ||
2551 | * Work queue thread to clear the persitency table | ||
2552 | */ | ||
2553 | static void | ||
2554 | mptsas_persist_clear_table(struct work_struct *work) | ||
2555 | { | ||
2556 | MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task); | ||
2557 | |||
2558 | mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); | ||
2559 | } | ||
2560 | |||
2561 | static void | 3066 | static void |
2562 | mptsas_reprobe_lun(struct scsi_device *sdev, void *data) | 3067 | mptsas_reprobe_lun(struct scsi_device *sdev, void *data) |
2563 | { | 3068 | { |
@@ -2583,7 +3088,8 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
2583 | pRaidVolumePage0_t buffer = NULL; | 3088 | pRaidVolumePage0_t buffer = NULL; |
2584 | RaidPhysDiskPage0_t phys_disk; | 3089 | RaidPhysDiskPage0_t phys_disk; |
2585 | int i; | 3090 | int i; |
2586 | struct mptsas_hotplug_event *ev; | 3091 | struct mptsas_phyinfo *phy_info; |
3092 | struct mptsas_devinfo sas_device; | ||
2587 | 3093 | ||
2588 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); | 3094 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); |
2589 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); | 3095 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); |
@@ -2623,20 +3129,16 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
2623 | buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) | 3129 | buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) |
2624 | continue; | 3130 | continue; |
2625 | 3131 | ||
2626 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 3132 | if (mptsas_sas_device_pg0(ioc, &sas_device, |
2627 | if (!ev) { | 3133 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
2628 | printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name); | 3134 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
2629 | goto out; | 3135 | (phys_disk.PhysDiskBus << 8) + |
2630 | } | 3136 | phys_disk.PhysDiskID)) |
3137 | continue; | ||
2631 | 3138 | ||
2632 | INIT_WORK(&ev->work, mptsas_hotplug_work); | 3139 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
2633 | ev->ioc = ioc; | 3140 | sas_device.sas_address); |
2634 | ev->id = phys_disk.PhysDiskID; | 3141 | mptsas_add_end_device(ioc, phy_info); |
2635 | ev->channel = phys_disk.PhysDiskBus; | ||
2636 | ev->phys_disk_num_valid = 1; | ||
2637 | ev->phys_disk_num = phys_disk.PhysDiskNum; | ||
2638 | ev->event_type = MPTSAS_ADD_DEVICE; | ||
2639 | schedule_work(&ev->work); | ||
2640 | } | 3142 | } |
2641 | 3143 | ||
2642 | out: | 3144 | out: |
@@ -2648,417 +3150,385 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
2648 | * Work queue thread to handle SAS hotplug events | 3150 | * Work queue thread to handle SAS hotplug events |
2649 | */ | 3151 | */ |
2650 | static void | 3152 | static void |
2651 | mptsas_hotplug_work(struct work_struct *work) | 3153 | mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, |
3154 | struct mptsas_hotplug_event *hot_plug_info) | ||
2652 | { | 3155 | { |
2653 | struct mptsas_hotplug_event *ev = | ||
2654 | container_of(work, struct mptsas_hotplug_event, work); | ||
2655 | |||
2656 | MPT_ADAPTER *ioc = ev->ioc; | ||
2657 | struct mptsas_phyinfo *phy_info; | 3156 | struct mptsas_phyinfo *phy_info; |
2658 | struct sas_rphy *rphy; | ||
2659 | struct sas_port *port; | ||
2660 | struct scsi_device *sdev; | ||
2661 | struct scsi_target * starget; | 3157 | struct scsi_target * starget; |
2662 | struct sas_identify identify; | ||
2663 | char *ds = NULL; | ||
2664 | struct mptsas_devinfo sas_device; | 3158 | struct mptsas_devinfo sas_device; |
2665 | VirtTarget *vtarget; | 3159 | VirtTarget *vtarget; |
2666 | VirtDevice *vdevice; | 3160 | int i; |
2667 | 3161 | ||
2668 | mutex_lock(&ioc->sas_discovery_mutex); | 3162 | switch (hot_plug_info->event_type) { |
2669 | switch (ev->event_type) { | ||
2670 | case MPTSAS_DEL_DEVICE: | ||
2671 | 3163 | ||
2672 | phy_info = NULL; | 3164 | case MPTSAS_ADD_PHYSDISK: |
2673 | if (ev->phys_disk_num_valid) { | 3165 | |
2674 | if (ev->hidden_raid_component){ | 3166 | if (!ioc->raid_data.pIocPg2) |
2675 | if (mptsas_sas_device_pg0(ioc, &sas_device, | 3167 | break; |
2676 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | 3168 | |
2677 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 3169 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { |
2678 | (ev->channel << 8) + ev->id)) { | 3170 | if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == |
2679 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 3171 | hot_plug_info->id) { |
2680 | "%s: exit at line=%d\n", ioc->name, | 3172 | printk(MYIOC_s_WARN_FMT "firmware bug: unable " |
2681 | __func__, __LINE__)); | 3173 | "to add hidden disk - target_id matchs " |
2682 | break; | 3174 | "volume_id\n", ioc->name); |
2683 | } | 3175 | mptsas_free_fw_event(ioc, fw_event); |
2684 | phy_info = mptsas_find_phyinfo_by_sas_address( | 3176 | return; |
2685 | ioc, sas_device.sas_address); | 3177 | } |
2686 | }else | ||
2687 | phy_info = mptsas_find_phyinfo_by_phys_disk_num( | ||
2688 | ioc, ev->channel, ev->phys_disk_num); | ||
2689 | } | 3178 | } |
3179 | mpt_findImVolumes(ioc); | ||
2690 | 3180 | ||
3181 | case MPTSAS_ADD_DEVICE: | ||
3182 | memset(&sas_device, 0, sizeof(struct mptsas_devinfo)); | ||
3183 | mptsas_sas_device_pg0(ioc, &sas_device, | ||
3184 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | ||
3185 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | ||
3186 | (hot_plug_info->channel << 8) + | ||
3187 | hot_plug_info->id); | ||
3188 | |||
3189 | if (!sas_device.handle) | ||
3190 | return; | ||
3191 | |||
3192 | phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); | ||
2691 | if (!phy_info) | 3193 | if (!phy_info) |
2692 | phy_info = mptsas_find_phyinfo_by_target(ioc, | 3194 | break; |
2693 | ev->channel, ev->id); | ||
2694 | 3195 | ||
2695 | /* | 3196 | if (mptsas_get_rphy(phy_info)) |
2696 | * Sanity checks, for non-existing phys and remote rphys. | 3197 | break; |
2697 | */ | 3198 | |
2698 | if (!phy_info){ | 3199 | mptsas_add_end_device(ioc, phy_info); |
3200 | break; | ||
3201 | |||
3202 | case MPTSAS_DEL_DEVICE: | ||
3203 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, | ||
3204 | hot_plug_info->sas_address); | ||
3205 | mptsas_del_end_device(ioc, phy_info); | ||
3206 | break; | ||
3207 | |||
3208 | case MPTSAS_DEL_PHYSDISK: | ||
3209 | |||
3210 | mpt_findImVolumes(ioc); | ||
3211 | |||
3212 | phy_info = mptsas_find_phyinfo_by_phys_disk_num( | ||
3213 | ioc, hot_plug_info->channel, | ||
3214 | hot_plug_info->phys_disk_num); | ||
3215 | mptsas_del_end_device(ioc, phy_info); | ||
3216 | break; | ||
3217 | |||
3218 | case MPTSAS_ADD_PHYSDISK_REPROBE: | ||
3219 | |||
3220 | if (mptsas_sas_device_pg0(ioc, &sas_device, | ||
3221 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | ||
3222 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | ||
3223 | (hot_plug_info->channel << 8) + hot_plug_info->id)) { | ||
2699 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 3224 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2700 | "%s: exit at line=%d\n", ioc->name, | 3225 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2701 | __func__, __LINE__)); | 3226 | __func__, hot_plug_info->id, __LINE__)); |
2702 | break; | 3227 | break; |
2703 | } | 3228 | } |
2704 | if (!phy_info->port_details) { | 3229 | |
3230 | phy_info = mptsas_find_phyinfo_by_sas_address( | ||
3231 | ioc, sas_device.sas_address); | ||
3232 | |||
3233 | if (!phy_info) { | ||
2705 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 3234 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2706 | "%s: exit at line=%d\n", ioc->name, | 3235 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2707 | __func__, __LINE__)); | 3236 | __func__, hot_plug_info->id, __LINE__)); |
2708 | break; | 3237 | break; |
2709 | } | 3238 | } |
2710 | rphy = mptsas_get_rphy(phy_info); | 3239 | |
2711 | if (!rphy) { | 3240 | starget = mptsas_get_starget(phy_info); |
3241 | if (!starget) { | ||
2712 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 3242 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2713 | "%s: exit at line=%d\n", ioc->name, | 3243 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2714 | __func__, __LINE__)); | 3244 | __func__, hot_plug_info->id, __LINE__)); |
2715 | break; | 3245 | break; |
2716 | } | 3246 | } |
2717 | 3247 | ||
2718 | port = mptsas_get_port(phy_info); | 3248 | vtarget = starget->hostdata; |
2719 | if (!port) { | 3249 | if (!vtarget) { |
2720 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 3250 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2721 | "%s: exit at line=%d\n", ioc->name, | 3251 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2722 | __func__, __LINE__)); | 3252 | __func__, hot_plug_info->id, __LINE__)); |
2723 | break; | 3253 | break; |
2724 | } | 3254 | } |
2725 | 3255 | ||
2726 | starget = mptsas_get_starget(phy_info); | 3256 | mpt_findImVolumes(ioc); |
2727 | if (starget) { | ||
2728 | vtarget = starget->hostdata; | ||
2729 | |||
2730 | if (!vtarget) { | ||
2731 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
2732 | "%s: exit at line=%d\n", ioc->name, | ||
2733 | __func__, __LINE__)); | ||
2734 | break; | ||
2735 | } | ||
2736 | 3257 | ||
2737 | /* | 3258 | starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: " |
2738 | * Handling RAID components | 3259 | "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", |
2739 | */ | 3260 | ioc->name, hot_plug_info->channel, hot_plug_info->id, |
2740 | if (ev->phys_disk_num_valid && | 3261 | hot_plug_info->phys_disk_num, (unsigned long long) |
2741 | ev->hidden_raid_component) { | 3262 | sas_device.sas_address); |
2742 | printk(MYIOC_s_INFO_FMT | ||
2743 | "RAID Hidding: channel=%d, id=%d, " | ||
2744 | "physdsk %d \n", ioc->name, ev->channel, | ||
2745 | ev->id, ev->phys_disk_num); | ||
2746 | vtarget->id = ev->phys_disk_num; | ||
2747 | vtarget->tflags |= | ||
2748 | MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
2749 | mptsas_reprobe_target(starget, 1); | ||
2750 | phy_info->attached.phys_disk_num = | ||
2751 | ev->phys_disk_num; | ||
2752 | break; | ||
2753 | } | ||
2754 | } | ||
2755 | 3263 | ||
2756 | if (phy_info->attached.device_info & | 3264 | vtarget->id = hot_plug_info->phys_disk_num; |
2757 | MPI_SAS_DEVICE_INFO_SSP_TARGET) | 3265 | vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; |
2758 | ds = "ssp"; | 3266 | phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num; |
2759 | if (phy_info->attached.device_info & | 3267 | mptsas_reprobe_target(starget, 1); |
2760 | MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
2761 | ds = "stp"; | ||
2762 | if (phy_info->attached.device_info & | ||
2763 | MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
2764 | ds = "sata"; | ||
2765 | |||
2766 | printk(MYIOC_s_INFO_FMT | ||
2767 | "removing %s device, channel %d, id %d, phy %d\n", | ||
2768 | ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); | ||
2769 | dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT | ||
2770 | "delete port (%d)\n", ioc->name, port->port_identifier); | ||
2771 | sas_port_delete(port); | ||
2772 | mptsas_port_delete(ioc, phy_info->port_details); | ||
2773 | break; | 3268 | break; |
2774 | case MPTSAS_ADD_DEVICE: | ||
2775 | 3269 | ||
2776 | if (ev->phys_disk_num_valid) | 3270 | case MPTSAS_DEL_PHYSDISK_REPROBE: |
2777 | mpt_findImVolumes(ioc); | ||
2778 | 3271 | ||
2779 | /* | ||
2780 | * Refresh sas device pg0 data | ||
2781 | */ | ||
2782 | if (mptsas_sas_device_pg0(ioc, &sas_device, | 3272 | if (mptsas_sas_device_pg0(ioc, &sas_device, |
2783 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | 3273 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
2784 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 3274 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
2785 | (ev->channel << 8) + ev->id)) { | 3275 | (hot_plug_info->channel << 8) + hot_plug_info->id)) { |
2786 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 3276 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2787 | "%s: exit at line=%d\n", ioc->name, | 3277 | "%s: fw_id=%d exit at line=%d\n", |
2788 | __func__, __LINE__)); | 3278 | ioc->name, __func__, |
3279 | hot_plug_info->id, __LINE__)); | ||
2789 | break; | 3280 | break; |
2790 | } | 3281 | } |
2791 | 3282 | ||
2792 | __mptsas_discovery_work(ioc); | ||
2793 | |||
2794 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, | 3283 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
2795 | sas_device.sas_address); | 3284 | sas_device.sas_address); |
2796 | 3285 | if (!phy_info) { | |
2797 | if (!phy_info || !phy_info->port_details) { | ||
2798 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 3286 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2799 | "%s: exit at line=%d\n", ioc->name, | 3287 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2800 | __func__, __LINE__)); | 3288 | __func__, hot_plug_info->id, __LINE__)); |
2801 | break; | 3289 | break; |
2802 | } | 3290 | } |
2803 | 3291 | ||
2804 | starget = mptsas_get_starget(phy_info); | 3292 | starget = mptsas_get_starget(phy_info); |
2805 | if (starget && (!ev->hidden_raid_component)){ | 3293 | if (!starget) { |
2806 | 3294 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | |
2807 | vtarget = starget->hostdata; | 3295 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2808 | 3296 | __func__, hot_plug_info->id, __LINE__)); | |
2809 | if (!vtarget) { | ||
2810 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
2811 | "%s: exit at line=%d\n", ioc->name, | ||
2812 | __func__, __LINE__)); | ||
2813 | break; | ||
2814 | } | ||
2815 | /* | ||
2816 | * Handling RAID components | ||
2817 | */ | ||
2818 | if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { | ||
2819 | printk(MYIOC_s_INFO_FMT | ||
2820 | "RAID Exposing: channel=%d, id=%d, " | ||
2821 | "physdsk %d \n", ioc->name, ev->channel, | ||
2822 | ev->id, ev->phys_disk_num); | ||
2823 | vtarget->tflags &= | ||
2824 | ~MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
2825 | vtarget->id = ev->id; | ||
2826 | mptsas_reprobe_target(starget, 0); | ||
2827 | phy_info->attached.phys_disk_num = ~0; | ||
2828 | } | ||
2829 | break; | 3297 | break; |
2830 | } | 3298 | } |
2831 | 3299 | ||
2832 | if (mptsas_get_rphy(phy_info)) { | 3300 | vtarget = starget->hostdata; |
3301 | if (!vtarget) { | ||
2833 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 3302 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2834 | "%s: exit at line=%d\n", ioc->name, | 3303 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2835 | __func__, __LINE__)); | 3304 | __func__, hot_plug_info->id, __LINE__)); |
2836 | if (ev->channel) printk("%d\n", __LINE__); | ||
2837 | break; | 3305 | break; |
2838 | } | 3306 | } |
2839 | 3307 | ||
2840 | port = mptsas_get_port(phy_info); | 3308 | if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) { |
2841 | if (!port) { | ||
2842 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 3309 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2843 | "%s: exit at line=%d\n", ioc->name, | 3310 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2844 | __func__, __LINE__)); | 3311 | __func__, hot_plug_info->id, __LINE__)); |
2845 | break; | 3312 | break; |
2846 | } | 3313 | } |
2847 | memcpy(&phy_info->attached, &sas_device, | ||
2848 | sizeof(struct mptsas_devinfo)); | ||
2849 | |||
2850 | if (phy_info->attached.device_info & | ||
2851 | MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
2852 | ds = "ssp"; | ||
2853 | if (phy_info->attached.device_info & | ||
2854 | MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
2855 | ds = "stp"; | ||
2856 | if (phy_info->attached.device_info & | ||
2857 | MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
2858 | ds = "sata"; | ||
2859 | |||
2860 | printk(MYIOC_s_INFO_FMT | ||
2861 | "attaching %s device, channel %d, id %d, phy %d\n", | ||
2862 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | ||
2863 | 3314 | ||
2864 | mptsas_parse_device_info(&identify, &phy_info->attached); | 3315 | mpt_findImVolumes(ioc); |
2865 | rphy = sas_end_device_alloc(port); | ||
2866 | if (!rphy) { | ||
2867 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
2868 | "%s: exit at line=%d\n", ioc->name, | ||
2869 | __func__, __LINE__)); | ||
2870 | break; /* non-fatal: an rphy can be added later */ | ||
2871 | } | ||
2872 | 3316 | ||
2873 | rphy->identify = identify; | 3317 | starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:" |
2874 | if (sas_rphy_add(rphy)) { | 3318 | " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", |
2875 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 3319 | ioc->name, hot_plug_info->channel, hot_plug_info->id, |
2876 | "%s: exit at line=%d\n", ioc->name, | 3320 | hot_plug_info->phys_disk_num, (unsigned long long) |
2877 | __func__, __LINE__)); | 3321 | sas_device.sas_address); |
2878 | sas_rphy_free(rphy); | 3322 | |
2879 | break; | 3323 | vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; |
2880 | } | 3324 | vtarget->id = hot_plug_info->id; |
2881 | mptsas_set_rphy(ioc, phy_info, rphy); | 3325 | phy_info->attached.phys_disk_num = ~0; |
3326 | mptsas_reprobe_target(starget, 0); | ||
3327 | mptsas_add_device_component_by_fw(ioc, | ||
3328 | hot_plug_info->channel, hot_plug_info->id); | ||
2882 | break; | 3329 | break; |
3330 | |||
2883 | case MPTSAS_ADD_RAID: | 3331 | case MPTSAS_ADD_RAID: |
2884 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, | 3332 | |
2885 | ev->id, 0); | ||
2886 | if (sdev) { | ||
2887 | scsi_device_put(sdev); | ||
2888 | break; | ||
2889 | } | ||
2890 | printk(MYIOC_s_INFO_FMT | ||
2891 | "attaching raid volume, channel %d, id %d\n", | ||
2892 | ioc->name, MPTSAS_RAID_CHANNEL, ev->id); | ||
2893 | scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0); | ||
2894 | mpt_findImVolumes(ioc); | 3333 | mpt_findImVolumes(ioc); |
3334 | printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " | ||
3335 | "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, | ||
3336 | hot_plug_info->id); | ||
3337 | scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, | ||
3338 | hot_plug_info->id, 0); | ||
2895 | break; | 3339 | break; |
3340 | |||
2896 | case MPTSAS_DEL_RAID: | 3341 | case MPTSAS_DEL_RAID: |
2897 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, | 3342 | |
2898 | ev->id, 0); | ||
2899 | if (!sdev) | ||
2900 | break; | ||
2901 | printk(MYIOC_s_INFO_FMT | ||
2902 | "removing raid volume, channel %d, id %d\n", | ||
2903 | ioc->name, MPTSAS_RAID_CHANNEL, ev->id); | ||
2904 | vdevice = sdev->hostdata; | ||
2905 | scsi_remove_device(sdev); | ||
2906 | scsi_device_put(sdev); | ||
2907 | mpt_findImVolumes(ioc); | 3343 | mpt_findImVolumes(ioc); |
3344 | printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " | ||
3345 | "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, | ||
3346 | hot_plug_info->id); | ||
3347 | scsi_remove_device(hot_plug_info->sdev); | ||
3348 | scsi_device_put(hot_plug_info->sdev); | ||
2908 | break; | 3349 | break; |
3350 | |||
2909 | case MPTSAS_ADD_INACTIVE_VOLUME: | 3351 | case MPTSAS_ADD_INACTIVE_VOLUME: |
3352 | |||
3353 | mpt_findImVolumes(ioc); | ||
2910 | mptsas_adding_inactive_raid_components(ioc, | 3354 | mptsas_adding_inactive_raid_components(ioc, |
2911 | ev->channel, ev->id); | 3355 | hot_plug_info->channel, hot_plug_info->id); |
2912 | break; | 3356 | break; |
2913 | case MPTSAS_IGNORE_EVENT: | 3357 | |
2914 | default: | 3358 | default: |
2915 | break; | 3359 | break; |
2916 | } | 3360 | } |
2917 | 3361 | ||
2918 | mutex_unlock(&ioc->sas_discovery_mutex); | 3362 | mptsas_free_fw_event(ioc, fw_event); |
2919 | kfree(ev); | ||
2920 | } | 3363 | } |
2921 | 3364 | ||
2922 | static void | 3365 | static void |
2923 | mptsas_send_sas_event(MPT_ADAPTER *ioc, | 3366 | mptsas_send_sas_event(struct fw_event_work *fw_event) |
2924 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) | ||
2925 | { | 3367 | { |
2926 | struct mptsas_hotplug_event *ev; | 3368 | MPT_ADAPTER *ioc; |
2927 | u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo); | 3369 | struct mptsas_hotplug_event hot_plug_info; |
2928 | __le64 sas_address; | 3370 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; |
3371 | u32 device_info; | ||
3372 | u64 sas_address; | ||
3373 | |||
3374 | ioc = fw_event->ioc; | ||
3375 | sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) | ||
3376 | fw_event->event_data; | ||
3377 | device_info = le32_to_cpu(sas_event_data->DeviceInfo); | ||
2929 | 3378 | ||
2930 | if ((device_info & | 3379 | if ((device_info & |
2931 | (MPI_SAS_DEVICE_INFO_SSP_TARGET | | 3380 | (MPI_SAS_DEVICE_INFO_SSP_TARGET | |
2932 | MPI_SAS_DEVICE_INFO_STP_TARGET | | 3381 | MPI_SAS_DEVICE_INFO_STP_TARGET | |
2933 | MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) | 3382 | MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) { |
3383 | mptsas_free_fw_event(ioc, fw_event); | ||
3384 | return; | ||
3385 | } | ||
3386 | |||
3387 | if (sas_event_data->ReasonCode == | ||
3388 | MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) { | ||
3389 | mptbase_sas_persist_operation(ioc, | ||
3390 | MPI_SAS_OP_CLEAR_NOT_PRESENT); | ||
3391 | mptsas_free_fw_event(ioc, fw_event); | ||
2934 | return; | 3392 | return; |
3393 | } | ||
2935 | 3394 | ||
2936 | switch (sas_event_data->ReasonCode) { | 3395 | switch (sas_event_data->ReasonCode) { |
2937 | case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: | 3396 | case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: |
2938 | |||
2939 | mptsas_target_reset_queue(ioc, sas_event_data); | ||
2940 | break; | ||
2941 | |||
2942 | case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: | 3397 | case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: |
2943 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 3398 | memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); |
2944 | if (!ev) { | 3399 | hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle); |
2945 | printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); | 3400 | hot_plug_info.channel = sas_event_data->Bus; |
2946 | break; | 3401 | hot_plug_info.id = sas_event_data->TargetID; |
2947 | } | 3402 | hot_plug_info.phy_id = sas_event_data->PhyNum; |
2948 | |||
2949 | INIT_WORK(&ev->work, mptsas_hotplug_work); | ||
2950 | ev->ioc = ioc; | ||
2951 | ev->handle = le16_to_cpu(sas_event_data->DevHandle); | ||
2952 | ev->parent_handle = | ||
2953 | le16_to_cpu(sas_event_data->ParentDevHandle); | ||
2954 | ev->channel = sas_event_data->Bus; | ||
2955 | ev->id = sas_event_data->TargetID; | ||
2956 | ev->phy_id = sas_event_data->PhyNum; | ||
2957 | memcpy(&sas_address, &sas_event_data->SASAddress, | 3403 | memcpy(&sas_address, &sas_event_data->SASAddress, |
2958 | sizeof(__le64)); | 3404 | sizeof(u64)); |
2959 | ev->sas_address = le64_to_cpu(sas_address); | 3405 | hot_plug_info.sas_address = le64_to_cpu(sas_address); |
2960 | ev->device_info = device_info; | 3406 | hot_plug_info.device_info = device_info; |
2961 | |||
2962 | if (sas_event_data->ReasonCode & | 3407 | if (sas_event_data->ReasonCode & |
2963 | MPI_EVENT_SAS_DEV_STAT_RC_ADDED) | 3408 | MPI_EVENT_SAS_DEV_STAT_RC_ADDED) |
2964 | ev->event_type = MPTSAS_ADD_DEVICE; | 3409 | hot_plug_info.event_type = MPTSAS_ADD_DEVICE; |
2965 | else | 3410 | else |
2966 | ev->event_type = MPTSAS_DEL_DEVICE; | 3411 | hot_plug_info.event_type = MPTSAS_DEL_DEVICE; |
2967 | schedule_work(&ev->work); | 3412 | mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); |
2968 | break; | 3413 | break; |
3414 | |||
2969 | case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: | 3415 | case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: |
2970 | /* | 3416 | mptbase_sas_persist_operation(ioc, |
2971 | * Persistent table is full. | 3417 | MPI_SAS_OP_CLEAR_NOT_PRESENT); |
2972 | */ | 3418 | mptsas_free_fw_event(ioc, fw_event); |
2973 | INIT_WORK(&ioc->sas_persist_task, | ||
2974 | mptsas_persist_clear_table); | ||
2975 | schedule_work(&ioc->sas_persist_task); | ||
2976 | break; | 3419 | break; |
2977 | /* | 3420 | |
2978 | * TODO, handle other events | ||
2979 | */ | ||
2980 | case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: | 3421 | case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: |
2981 | case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: | 3422 | /* TODO */ |
2982 | case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: | 3423 | case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: |
2983 | case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: | 3424 | /* TODO */ |
2984 | case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: | ||
2985 | case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: | ||
2986 | case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: | ||
2987 | default: | 3425 | default: |
3426 | mptsas_free_fw_event(ioc, fw_event); | ||
2988 | break; | 3427 | break; |
2989 | } | 3428 | } |
2990 | } | 3429 | } |
3430 | |||
2991 | static void | 3431 | static void |
2992 | mptsas_send_raid_event(MPT_ADAPTER *ioc, | 3432 | mptsas_send_raid_event(struct fw_event_work *fw_event) |
2993 | EVENT_DATA_RAID *raid_event_data) | ||
2994 | { | 3433 | { |
2995 | struct mptsas_hotplug_event *ev; | 3434 | MPT_ADAPTER *ioc; |
2996 | int status = le32_to_cpu(raid_event_data->SettingsStatus); | 3435 | EVENT_DATA_RAID *raid_event_data; |
2997 | int state = (status >> 8) & 0xff; | 3436 | struct mptsas_hotplug_event hot_plug_info; |
2998 | 3437 | int status; | |
2999 | if (ioc->bus_type != SAS) | 3438 | int state; |
3000 | return; | 3439 | struct scsi_device *sdev = NULL; |
3001 | 3440 | VirtDevice *vdevice = NULL; | |
3002 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 3441 | RaidPhysDiskPage0_t phys_disk; |
3003 | if (!ev) { | 3442 | |
3004 | printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); | 3443 | ioc = fw_event->ioc; |
3005 | return; | 3444 | raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data; |
3445 | status = le32_to_cpu(raid_event_data->SettingsStatus); | ||
3446 | state = (status >> 8) & 0xff; | ||
3447 | |||
3448 | memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); | ||
3449 | hot_plug_info.id = raid_event_data->VolumeID; | ||
3450 | hot_plug_info.channel = raid_event_data->VolumeBus; | ||
3451 | hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum; | ||
3452 | |||
3453 | if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED || | ||
3454 | raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED || | ||
3455 | raid_event_data->ReasonCode == | ||
3456 | MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) { | ||
3457 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, | ||
3458 | hot_plug_info.id, 0); | ||
3459 | hot_plug_info.sdev = sdev; | ||
3460 | if (sdev) | ||
3461 | vdevice = sdev->hostdata; | ||
3006 | } | 3462 | } |
3007 | 3463 | ||
3008 | INIT_WORK(&ev->work, mptsas_hotplug_work); | 3464 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " |
3009 | ev->ioc = ioc; | 3465 | "ReasonCode=%02x\n", ioc->name, __func__, |
3010 | ev->id = raid_event_data->VolumeID; | 3466 | raid_event_data->ReasonCode)); |
3011 | ev->channel = raid_event_data->VolumeBus; | ||
3012 | ev->event_type = MPTSAS_IGNORE_EVENT; | ||
3013 | 3467 | ||
3014 | switch (raid_event_data->ReasonCode) { | 3468 | switch (raid_event_data->ReasonCode) { |
3015 | case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: | 3469 | case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: |
3016 | ev->phys_disk_num_valid = 1; | 3470 | hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE; |
3017 | ev->phys_disk_num = raid_event_data->PhysDiskNum; | ||
3018 | ev->event_type = MPTSAS_ADD_DEVICE; | ||
3019 | break; | 3471 | break; |
3020 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: | 3472 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: |
3021 | ev->phys_disk_num_valid = 1; | 3473 | hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE; |
3022 | ev->phys_disk_num = raid_event_data->PhysDiskNum; | ||
3023 | ev->hidden_raid_component = 1; | ||
3024 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
3025 | break; | 3474 | break; |
3026 | case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: | 3475 | case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: |
3027 | switch (state) { | 3476 | switch (state) { |
3028 | case MPI_PD_STATE_ONLINE: | 3477 | case MPI_PD_STATE_ONLINE: |
3029 | case MPI_PD_STATE_NOT_COMPATIBLE: | 3478 | case MPI_PD_STATE_NOT_COMPATIBLE: |
3030 | ev->phys_disk_num_valid = 1; | 3479 | mpt_raid_phys_disk_pg0(ioc, |
3031 | ev->phys_disk_num = raid_event_data->PhysDiskNum; | 3480 | raid_event_data->PhysDiskNum, &phys_disk); |
3032 | ev->hidden_raid_component = 1; | 3481 | hot_plug_info.id = phys_disk.PhysDiskID; |
3033 | ev->event_type = MPTSAS_ADD_DEVICE; | 3482 | hot_plug_info.channel = phys_disk.PhysDiskBus; |
3483 | hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; | ||
3034 | break; | 3484 | break; |
3485 | case MPI_PD_STATE_FAILED: | ||
3035 | case MPI_PD_STATE_MISSING: | 3486 | case MPI_PD_STATE_MISSING: |
3036 | case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: | 3487 | case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: |
3037 | case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: | 3488 | case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: |
3038 | case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: | 3489 | case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: |
3039 | ev->phys_disk_num_valid = 1; | 3490 | hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; |
3040 | ev->phys_disk_num = raid_event_data->PhysDiskNum; | ||
3041 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
3042 | break; | 3491 | break; |
3043 | default: | 3492 | default: |
3044 | break; | 3493 | break; |
3045 | } | 3494 | } |
3046 | break; | 3495 | break; |
3047 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: | 3496 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: |
3048 | ev->event_type = MPTSAS_DEL_RAID; | 3497 | if (!sdev) |
3498 | break; | ||
3499 | vdevice->vtarget->deleted = 1; /* block IO */ | ||
3500 | hot_plug_info.event_type = MPTSAS_DEL_RAID; | ||
3049 | break; | 3501 | break; |
3050 | case MPI_EVENT_RAID_RC_VOLUME_CREATED: | 3502 | case MPI_EVENT_RAID_RC_VOLUME_CREATED: |
3051 | ev->event_type = MPTSAS_ADD_RAID; | 3503 | if (sdev) { |
3504 | scsi_device_put(sdev); | ||
3505 | break; | ||
3506 | } | ||
3507 | hot_plug_info.event_type = MPTSAS_ADD_RAID; | ||
3052 | break; | 3508 | break; |
3053 | case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: | 3509 | case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: |
3510 | if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) { | ||
3511 | if (!sdev) | ||
3512 | break; | ||
3513 | vdevice->vtarget->deleted = 1; /* block IO */ | ||
3514 | hot_plug_info.event_type = MPTSAS_DEL_RAID; | ||
3515 | break; | ||
3516 | } | ||
3054 | switch (state) { | 3517 | switch (state) { |
3055 | case MPI_RAIDVOL0_STATUS_STATE_FAILED: | 3518 | case MPI_RAIDVOL0_STATUS_STATE_FAILED: |
3056 | case MPI_RAIDVOL0_STATUS_STATE_MISSING: | 3519 | case MPI_RAIDVOL0_STATUS_STATE_MISSING: |
3057 | ev->event_type = MPTSAS_DEL_RAID; | 3520 | if (!sdev) |
3521 | break; | ||
3522 | vdevice->vtarget->deleted = 1; /* block IO */ | ||
3523 | hot_plug_info.event_type = MPTSAS_DEL_RAID; | ||
3058 | break; | 3524 | break; |
3059 | case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: | 3525 | case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: |
3060 | case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: | 3526 | case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: |
3061 | ev->event_type = MPTSAS_ADD_RAID; | 3527 | if (sdev) { |
3528 | scsi_device_put(sdev); | ||
3529 | break; | ||
3530 | } | ||
3531 | hot_plug_info.event_type = MPTSAS_ADD_RAID; | ||
3062 | break; | 3532 | break; |
3063 | default: | 3533 | default: |
3064 | break; | 3534 | break; |
@@ -3067,7 +3537,11 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc, | |||
3067 | default: | 3537 | default: |
3068 | break; | 3538 | break; |
3069 | } | 3539 | } |
3070 | schedule_work(&ev->work); | 3540 | |
3541 | if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT) | ||
3542 | mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); | ||
3543 | else | ||
3544 | mptsas_free_fw_event(ioc, fw_event); | ||
3071 | } | 3545 | } |
3072 | 3546 | ||
3073 | static void | 3547 | static void |
@@ -3106,76 +3580,88 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc, | |||
3106 | * | 3580 | * |
3107 | */ | 3581 | */ |
3108 | static void | 3582 | static void |
3109 | mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data) | 3583 | mptsas_send_ir2_event(struct fw_event_work *fw_event) |
3110 | { | 3584 | { |
3111 | struct mptsas_hotplug_event *ev; | 3585 | MPT_ADAPTER *ioc; |
3112 | 3586 | struct mptsas_hotplug_event hot_plug_info; | |
3113 | if (ir2_data->ReasonCode != | 3587 | MPI_EVENT_DATA_IR2 *ir2_data; |
3114 | MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED) | 3588 | u8 reasonCode; |
3115 | return; | 3589 | |
3116 | 3590 | ioc = fw_event->ioc; | |
3117 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 3591 | ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data; |
3118 | if (!ev) | 3592 | reasonCode = ir2_data->ReasonCode; |
3593 | |||
3594 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " | ||
3595 | "ReasonCode=%02x\n", ioc->name, __func__, reasonCode)); | ||
3596 | |||
3597 | memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); | ||
3598 | hot_plug_info.id = ir2_data->TargetID; | ||
3599 | hot_plug_info.channel = ir2_data->Bus; | ||
3600 | switch (reasonCode) { | ||
3601 | case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: | ||
3602 | hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME; | ||
3603 | break; | ||
3604 | default: | ||
3605 | mptsas_free_fw_event(ioc, fw_event); | ||
3119 | return; | 3606 | return; |
3120 | 3607 | } | |
3121 | INIT_WORK(&ev->work, mptsas_hotplug_work); | 3608 | mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); |
3122 | ev->ioc = ioc; | 3609 | } |
3123 | ev->id = ir2_data->TargetID; | ||
3124 | ev->channel = ir2_data->Bus; | ||
3125 | ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME; | ||
3126 | |||
3127 | schedule_work(&ev->work); | ||
3128 | }; | ||
3129 | 3610 | ||
3130 | static int | 3611 | static int |
3131 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | 3612 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) |
3132 | { | 3613 | { |
3133 | int rc=1; | 3614 | u32 event = le32_to_cpu(reply->Event); |
3134 | u8 event = le32_to_cpu(reply->Event) & 0xFF; | 3615 | int sz, event_data_sz; |
3135 | 3616 | struct fw_event_work *fw_event; | |
3136 | if (!ioc->sh) | 3617 | unsigned long delay; |
3137 | goto out; | ||
3138 | 3618 | ||
3139 | /* | 3619 | /* events turned off due to host reset or driver unloading */ |
3140 | * sas_discovery_ignore_events | 3620 | if (ioc->fw_events_off) |
3141 | * | 3621 | return 0; |
3142 | * This flag is to prevent anymore processing of | ||
3143 | * sas events once mptsas_remove function is called. | ||
3144 | */ | ||
3145 | if (ioc->sas_discovery_ignore_events) { | ||
3146 | rc = mptscsih_event_process(ioc, reply); | ||
3147 | goto out; | ||
3148 | } | ||
3149 | 3622 | ||
3623 | delay = msecs_to_jiffies(1); | ||
3150 | switch (event) { | 3624 | switch (event) { |
3151 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | 3625 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: |
3152 | mptsas_send_sas_event(ioc, | 3626 | { |
3153 | (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); | 3627 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = |
3154 | break; | 3628 | (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data; |
3155 | case MPI_EVENT_INTEGRATED_RAID: | 3629 | |
3156 | mptsas_send_raid_event(ioc, | 3630 | if (sas_event_data->ReasonCode == |
3157 | (EVENT_DATA_RAID *)reply->Data); | 3631 | MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) { |
3158 | break; | 3632 | mptsas_target_reset_queue(ioc, sas_event_data); |
3159 | case MPI_EVENT_PERSISTENT_TABLE_FULL: | 3633 | return 0; |
3160 | INIT_WORK(&ioc->sas_persist_task, | 3634 | } |
3161 | mptsas_persist_clear_table); | ||
3162 | schedule_work(&ioc->sas_persist_task); | ||
3163 | break; | 3635 | break; |
3164 | case MPI_EVENT_SAS_DISCOVERY: | 3636 | } |
3637 | case MPI_EVENT_SAS_DISCOVERY: | ||
3165 | mptsas_send_discovery_event(ioc, | 3638 | mptsas_send_discovery_event(ioc, |
3166 | (EVENT_DATA_SAS_DISCOVERY *)reply->Data); | 3639 | (EVENT_DATA_SAS_DISCOVERY *)reply->Data); |
3167 | break; | 3640 | break; |
3641 | case MPI_EVENT_INTEGRATED_RAID: | ||
3642 | case MPI_EVENT_PERSISTENT_TABLE_FULL: | ||
3168 | case MPI_EVENT_IR2: | 3643 | case MPI_EVENT_IR2: |
3169 | mptsas_send_ir2_event(ioc, | 3644 | case MPI_EVENT_SAS_PHY_LINK_STATUS: |
3170 | (PTR_MPI_EVENT_DATA_IR2)reply->Data); | 3645 | case MPI_EVENT_QUEUE_FULL: |
3171 | break; | 3646 | break; |
3172 | default: | 3647 | default: |
3173 | rc = mptscsih_event_process(ioc, reply); | 3648 | return 0; |
3174 | break; | ||
3175 | } | 3649 | } |
3176 | out: | ||
3177 | 3650 | ||
3178 | return rc; | 3651 | event_data_sz = ((reply->MsgLength * 4) - |
3652 | offsetof(EventNotificationReply_t, Data)); | ||
3653 | sz = offsetof(struct fw_event_work, event_data) + event_data_sz; | ||
3654 | fw_event = kzalloc(sz, GFP_ATOMIC); | ||
3655 | if (!fw_event) { | ||
3656 | printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name, | ||
3657 | __func__, __LINE__); | ||
3658 | return 0; | ||
3659 | } | ||
3660 | memcpy(fw_event->event_data, reply->Data, event_data_sz); | ||
3661 | fw_event->event = event; | ||
3662 | fw_event->ioc = ioc; | ||
3663 | mptsas_add_fw_event(ioc, fw_event, delay); | ||
3664 | return 0; | ||
3179 | } | 3665 | } |
3180 | 3666 | ||
3181 | static int | 3667 | static int |
@@ -3197,6 +3683,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3197 | return r; | 3683 | return r; |
3198 | 3684 | ||
3199 | ioc = pci_get_drvdata(pdev); | 3685 | ioc = pci_get_drvdata(pdev); |
3686 | mptsas_fw_event_off(ioc); | ||
3200 | ioc->DoneCtx = mptsasDoneCtx; | 3687 | ioc->DoneCtx = mptsasDoneCtx; |
3201 | ioc->TaskCtx = mptsasTaskCtx; | 3688 | ioc->TaskCtx = mptsasTaskCtx; |
3202 | ioc->InternalCtx = mptsasInternalCtx; | 3689 | ioc->InternalCtx = mptsasInternalCtx; |
@@ -3339,6 +3826,9 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3339 | 3826 | ||
3340 | hd->last_queue_full = 0; | 3827 | hd->last_queue_full = 0; |
3341 | INIT_LIST_HEAD(&hd->target_reset_list); | 3828 | INIT_LIST_HEAD(&hd->target_reset_list); |
3829 | INIT_LIST_HEAD(&ioc->sas_device_info_list); | ||
3830 | mutex_init(&ioc->sas_device_info_mutex); | ||
3831 | |||
3342 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); | 3832 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); |
3343 | 3833 | ||
3344 | if (ioc->sas_data.ptClear==1) { | 3834 | if (ioc->sas_data.ptClear==1) { |
@@ -3354,7 +3844,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3354 | } | 3844 | } |
3355 | 3845 | ||
3356 | mptsas_scan_sas_topology(ioc); | 3846 | mptsas_scan_sas_topology(ioc); |
3357 | 3847 | mptsas_fw_event_on(ioc); | |
3358 | return 0; | 3848 | return 0; |
3359 | 3849 | ||
3360 | out_mptsas_probe: | 3850 | out_mptsas_probe: |
@@ -3368,7 +3858,8 @@ mptsas_shutdown(struct pci_dev *pdev) | |||
3368 | { | 3858 | { |
3369 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | 3859 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
3370 | 3860 | ||
3371 | ioc->sas_discovery_quiesce_io = 0; | 3861 | mptsas_fw_event_off(ioc); |
3862 | mptsas_cleanup_fw_event_q(ioc); | ||
3372 | } | 3863 | } |
3373 | 3864 | ||
3374 | static void __devexit mptsas_remove(struct pci_dev *pdev) | 3865 | static void __devexit mptsas_remove(struct pci_dev *pdev) |
@@ -3379,6 +3870,8 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) | |||
3379 | 3870 | ||
3380 | mptsas_shutdown(pdev); | 3871 | mptsas_shutdown(pdev); |
3381 | 3872 | ||
3873 | mptsas_del_device_components(ioc); | ||
3874 | |||
3382 | ioc->sas_discovery_ignore_events = 1; | 3875 | ioc->sas_discovery_ignore_events = 1; |
3383 | sas_remove_host(ioc->sh); | 3876 | sas_remove_host(ioc->sh); |
3384 | 3877 | ||
@@ -3387,6 +3880,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) | |||
3387 | list_del(&p->list); | 3880 | list_del(&p->list); |
3388 | for (i = 0 ; i < p->num_phys ; i++) | 3881 | for (i = 0 ; i < p->num_phys ; i++) |
3389 | mptsas_port_delete(ioc, p->phy_info[i].port_details); | 3882 | mptsas_port_delete(ioc, p->phy_info[i].port_details); |
3883 | |||
3390 | kfree(p->phy_info); | 3884 | kfree(p->phy_info); |
3391 | kfree(p); | 3885 | kfree(p); |
3392 | } | 3886 | } |
diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h index bf528a5b59b..9e0885a86d2 100644 --- a/drivers/message/fusion/mptsas.h +++ b/drivers/message/fusion/mptsas.h | |||
@@ -61,12 +61,30 @@ enum mptsas_hotplug_action { | |||
61 | MPTSAS_DEL_DEVICE, | 61 | MPTSAS_DEL_DEVICE, |
62 | MPTSAS_ADD_RAID, | 62 | MPTSAS_ADD_RAID, |
63 | MPTSAS_DEL_RAID, | 63 | MPTSAS_DEL_RAID, |
64 | MPTSAS_ADD_PHYSDISK, | ||
65 | MPTSAS_ADD_PHYSDISK_REPROBE, | ||
66 | MPTSAS_DEL_PHYSDISK, | ||
67 | MPTSAS_DEL_PHYSDISK_REPROBE, | ||
64 | MPTSAS_ADD_INACTIVE_VOLUME, | 68 | MPTSAS_ADD_INACTIVE_VOLUME, |
65 | MPTSAS_IGNORE_EVENT, | 69 | MPTSAS_IGNORE_EVENT, |
66 | }; | 70 | }; |
67 | 71 | ||
72 | struct mptsas_mapping{ | ||
73 | u8 id; | ||
74 | u8 channel; | ||
75 | }; | ||
76 | |||
77 | struct mptsas_device_info { | ||
78 | struct list_head list; | ||
79 | struct mptsas_mapping os; /* operating system mapping*/ | ||
80 | struct mptsas_mapping fw; /* firmware mapping */ | ||
81 | u64 sas_address; | ||
82 | u32 device_info; /* specific bits for devices */ | ||
83 | u16 slot; /* enclosure slot id */ | ||
84 | u64 enclosure_logical_id; /*enclosure address */ | ||
85 | }; | ||
86 | |||
68 | struct mptsas_hotplug_event { | 87 | struct mptsas_hotplug_event { |
69 | struct work_struct work; | ||
70 | MPT_ADAPTER *ioc; | 88 | MPT_ADAPTER *ioc; |
71 | enum mptsas_hotplug_action event_type; | 89 | enum mptsas_hotplug_action event_type; |
72 | u64 sas_address; | 90 | u64 sas_address; |
@@ -74,11 +92,18 @@ struct mptsas_hotplug_event { | |||
74 | u8 id; | 92 | u8 id; |
75 | u32 device_info; | 93 | u32 device_info; |
76 | u16 handle; | 94 | u16 handle; |
77 | u16 parent_handle; | ||
78 | u8 phy_id; | 95 | u8 phy_id; |
79 | u8 phys_disk_num_valid; /* hrc (hidden raid component) */ | ||
80 | u8 phys_disk_num; /* hrc - unique index*/ | 96 | u8 phys_disk_num; /* hrc - unique index*/ |
81 | u8 hidden_raid_component; /* hrc - don't expose*/ | 97 | struct scsi_device *sdev; |
98 | }; | ||
99 | |||
100 | struct fw_event_work { | ||
101 | struct list_head list; | ||
102 | struct delayed_work work; | ||
103 | MPT_ADAPTER *ioc; | ||
104 | u32 event; | ||
105 | u8 retries; | ||
106 | u8 event_data[1]; | ||
82 | }; | 107 | }; |
83 | 108 | ||
84 | struct mptsas_discovery_event { | 109 | struct mptsas_discovery_event { |