diff options
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
-rw-r--r-- | drivers/message/fusion/mptsas.c | 3136 |
1 files changed, 2363 insertions, 773 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index a9019f081b97..20e0b447e8e8 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
@@ -93,8 +93,37 @@ static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; | |||
93 | static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; | 93 | static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; |
94 | static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ | 94 | static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ |
95 | static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; | 95 | static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; |
96 | 96 | static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; | |
97 | static void mptsas_hotplug_work(struct work_struct *work); | 97 | |
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); | ||
116 | static void mptsas_send_link_status_event(struct fw_event_work *fw_event); | ||
117 | static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address | ||
118 | (MPT_ADAPTER *ioc, u64 sas_address); | ||
119 | static void mptsas_expander_delete(MPT_ADAPTER *ioc, | ||
120 | struct mptsas_portinfo *port_info, u8 force); | ||
121 | static void mptsas_send_expander_event(struct fw_event_work *fw_event); | ||
122 | static void mptsas_not_responding_devices(MPT_ADAPTER *ioc); | ||
123 | static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); | ||
124 | static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event); | ||
125 | static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); | ||
126 | static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); | ||
98 | 127 | ||
99 | static void mptsas_print_phy_data(MPT_ADAPTER *ioc, | 128 | static void mptsas_print_phy_data(MPT_ADAPTER *ioc, |
100 | MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) | 129 | MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) |
@@ -218,30 +247,125 @@ static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1) | |||
218 | le16_to_cpu(pg1->AttachedDevHandle))); | 247 | le16_to_cpu(pg1->AttachedDevHandle))); |
219 | } | 248 | } |
220 | 249 | ||
221 | static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) | 250 | /* inhibit sas firmware event handling */ |
251 | static void | ||
252 | mptsas_fw_event_off(MPT_ADAPTER *ioc) | ||
222 | { | 253 | { |
223 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); | 254 | unsigned long flags; |
224 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | 255 | |
256 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
257 | ioc->fw_events_off = 1; | ||
258 | ioc->sas_discovery_quiesce_io = 0; | ||
259 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
260 | |||
225 | } | 261 | } |
226 | 262 | ||
227 | static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) | 263 | /* enable sas firmware event handling */ |
264 | static void | ||
265 | mptsas_fw_event_on(MPT_ADAPTER *ioc) | ||
228 | { | 266 | { |
229 | struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); | 267 | unsigned long flags; |
230 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | 268 | |
269 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
270 | ioc->fw_events_off = 0; | ||
271 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
231 | } | 272 | } |
232 | 273 | ||
233 | static struct mptsas_portinfo * | 274 | /* queue a sas firmware event */ |
234 | mptsas_get_hba_portinfo(MPT_ADAPTER *ioc) | 275 | static void |
276 | mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, | ||
277 | unsigned long delay) | ||
235 | { | 278 | { |
236 | struct list_head *head = &ioc->sas_topology; | 279 | unsigned long flags; |
237 | struct mptsas_portinfo *pi = NULL; | 280 | |
281 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
282 | list_add_tail(&fw_event->list, &ioc->fw_event_list); | ||
283 | INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); | ||
284 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n", | ||
285 | ioc->name, __func__, fw_event)); | ||
286 | queue_delayed_work(ioc->fw_event_q, &fw_event->work, | ||
287 | delay); | ||
288 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
289 | } | ||
290 | |||
291 | /* requeue a sas firmware event */ | ||
292 | static void | ||
293 | mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, | ||
294 | unsigned long delay) | ||
295 | { | ||
296 | unsigned long flags; | ||
297 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
298 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task " | ||
299 | "(fw_event=0x%p)\n", ioc->name, __func__, fw_event)); | ||
300 | fw_event->retries++; | ||
301 | queue_delayed_work(ioc->fw_event_q, &fw_event->work, | ||
302 | msecs_to_jiffies(delay)); | ||
303 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
304 | } | ||
305 | |||
306 | /* free memory assoicated to a sas firmware event */ | ||
307 | static void | ||
308 | mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) | ||
309 | { | ||
310 | unsigned long flags; | ||
311 | |||
312 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
313 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n", | ||
314 | ioc->name, __func__, fw_event)); | ||
315 | list_del(&fw_event->list); | ||
316 | kfree(fw_event); | ||
317 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
318 | } | ||
319 | |||
320 | /* walk the firmware event queue, and either stop or wait for | ||
321 | * outstanding events to complete */ | ||
322 | static void | ||
323 | mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) | ||
324 | { | ||
325 | struct fw_event_work *fw_event, *next; | ||
326 | struct mptsas_target_reset_event *target_reset_list, *n; | ||
327 | u8 flush_q; | ||
328 | MPT_SCSI_HOST *hd = shost_priv(ioc->sh); | ||
329 | |||
330 | /* flush the target_reset_list */ | ||
331 | if (!list_empty(&hd->target_reset_list)) { | ||
332 | list_for_each_entry_safe(target_reset_list, n, | ||
333 | &hd->target_reset_list, list) { | ||
334 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
335 | "%s: removing target reset for id=%d\n", | ||
336 | ioc->name, __func__, | ||
337 | target_reset_list->sas_event_data.TargetID)); | ||
338 | list_del(&target_reset_list->list); | ||
339 | kfree(target_reset_list); | ||
340 | } | ||
341 | } | ||
342 | |||
343 | if (list_empty(&ioc->fw_event_list) || | ||
344 | !ioc->fw_event_q || in_interrupt()) | ||
345 | return; | ||
238 | 346 | ||
239 | /* always the first entry on sas_topology list */ | 347 | flush_q = 0; |
348 | list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { | ||
349 | if (cancel_delayed_work(&fw_event->work)) | ||
350 | mptsas_free_fw_event(ioc, fw_event); | ||
351 | else | ||
352 | flush_q = 1; | ||
353 | } | ||
354 | if (flush_q) | ||
355 | flush_workqueue(ioc->fw_event_q); | ||
356 | } | ||
240 | 357 | ||
241 | if (!list_empty(head)) | ||
242 | pi = list_entry(head->next, struct mptsas_portinfo, list); | ||
243 | 358 | ||
244 | return pi; | 359 | static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) |
360 | { | ||
361 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); | ||
362 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | ||
363 | } | ||
364 | |||
365 | static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) | ||
366 | { | ||
367 | struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); | ||
368 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | ||
245 | } | 369 | } |
246 | 370 | ||
247 | /* | 371 | /* |
@@ -265,6 +389,38 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) | |||
265 | return rc; | 389 | return rc; |
266 | } | 390 | } |
267 | 391 | ||
392 | /** | ||
393 | * mptsas_find_portinfo_by_sas_address - | ||
394 | * @ioc: Pointer to MPT_ADAPTER structure | ||
395 | * @handle: | ||
396 | * | ||
397 | * This function should be called with the sas_topology_mutex already held | ||
398 | * | ||
399 | **/ | ||
400 | static struct mptsas_portinfo * | ||
401 | mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) | ||
402 | { | ||
403 | struct mptsas_portinfo *port_info, *rc = NULL; | ||
404 | int i; | ||
405 | |||
406 | if (sas_address >= ioc->hba_port_sas_addr && | ||
407 | sas_address < (ioc->hba_port_sas_addr + | ||
408 | ioc->hba_port_num_phy)) | ||
409 | return ioc->hba_port_info; | ||
410 | |||
411 | mutex_lock(&ioc->sas_topology_mutex); | ||
412 | list_for_each_entry(port_info, &ioc->sas_topology, list) | ||
413 | for (i = 0; i < port_info->num_phys; i++) | ||
414 | if (port_info->phy_info[i].identify.sas_address == | ||
415 | sas_address) { | ||
416 | rc = port_info; | ||
417 | goto out; | ||
418 | } | ||
419 | out: | ||
420 | mutex_unlock(&ioc->sas_topology_mutex); | ||
421 | return rc; | ||
422 | } | ||
423 | |||
268 | /* | 424 | /* |
269 | * Returns true if there is a scsi end device | 425 | * Returns true if there is a scsi end device |
270 | */ | 426 | */ |
@@ -308,6 +464,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai | |||
308 | if(phy_info->port_details != port_details) | 464 | if(phy_info->port_details != port_details) |
309 | continue; | 465 | continue; |
310 | memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); | 466 | memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); |
467 | mptsas_set_rphy(ioc, phy_info, NULL); | ||
311 | phy_info->port_details = NULL; | 468 | phy_info->port_details = NULL; |
312 | } | 469 | } |
313 | kfree(port_details); | 470 | kfree(port_details); |
@@ -379,6 +536,285 @@ starget) | |||
379 | phy_info->port_details->starget = starget; | 536 | phy_info->port_details->starget = starget; |
380 | } | 537 | } |
381 | 538 | ||
539 | /** | ||
540 | * mptsas_add_device_component - | ||
541 | * @ioc: Pointer to MPT_ADAPTER structure | ||
542 | * @channel: fw mapped id's | ||
543 | * @id: | ||
544 | * @sas_address: | ||
545 | * @device_info: | ||
546 | * | ||
547 | **/ | ||
548 | static void | ||
549 | mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id, | ||
550 | u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id) | ||
551 | { | ||
552 | struct mptsas_device_info *sas_info, *next; | ||
553 | struct scsi_device *sdev; | ||
554 | struct scsi_target *starget; | ||
555 | struct sas_rphy *rphy; | ||
556 | |||
557 | /* | ||
558 | * Delete all matching devices out of the list | ||
559 | */ | ||
560 | mutex_lock(&ioc->sas_device_info_mutex); | ||
561 | list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, | ||
562 | list) { | ||
563 | if (!sas_info->is_logical_volume && | ||
564 | (sas_info->sas_address == sas_address || | ||
565 | (sas_info->fw.channel == channel && | ||
566 | sas_info->fw.id == id))) { | ||
567 | list_del(&sas_info->list); | ||
568 | kfree(sas_info); | ||
569 | } | ||
570 | } | ||
571 | |||
572 | sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); | ||
573 | if (!sas_info) | ||
574 | goto out; | ||
575 | |||
576 | /* | ||
577 | * Set Firmware mapping | ||
578 | */ | ||
579 | sas_info->fw.id = id; | ||
580 | sas_info->fw.channel = channel; | ||
581 | |||
582 | sas_info->sas_address = sas_address; | ||
583 | sas_info->device_info = device_info; | ||
584 | sas_info->slot = slot; | ||
585 | sas_info->enclosure_logical_id = enclosure_logical_id; | ||
586 | INIT_LIST_HEAD(&sas_info->list); | ||
587 | list_add_tail(&sas_info->list, &ioc->sas_device_info_list); | ||
588 | |||
589 | /* | ||
590 | * Set OS mapping | ||
591 | */ | ||
592 | shost_for_each_device(sdev, ioc->sh) { | ||
593 | starget = scsi_target(sdev); | ||
594 | rphy = dev_to_rphy(starget->dev.parent); | ||
595 | if (rphy->identify.sas_address == sas_address) { | ||
596 | sas_info->os.id = starget->id; | ||
597 | sas_info->os.channel = starget->channel; | ||
598 | } | ||
599 | } | ||
600 | |||
601 | out: | ||
602 | mutex_unlock(&ioc->sas_device_info_mutex); | ||
603 | return; | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * mptsas_add_device_component_by_fw - | ||
608 | * @ioc: Pointer to MPT_ADAPTER structure | ||
609 | * @channel: fw mapped id's | ||
610 | * @id: | ||
611 | * | ||
612 | **/ | ||
613 | static void | ||
614 | mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) | ||
615 | { | ||
616 | struct mptsas_devinfo sas_device; | ||
617 | struct mptsas_enclosure enclosure_info; | ||
618 | int rc; | ||
619 | |||
620 | rc = mptsas_sas_device_pg0(ioc, &sas_device, | ||
621 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | ||
622 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | ||
623 | (channel << 8) + id); | ||
624 | if (rc) | ||
625 | return; | ||
626 | |||
627 | memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); | ||
628 | mptsas_sas_enclosure_pg0(ioc, &enclosure_info, | ||
629 | (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << | ||
630 | MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), | ||
631 | sas_device.handle_enclosure); | ||
632 | |||
633 | mptsas_add_device_component(ioc, sas_device.channel, | ||
634 | sas_device.id, sas_device.sas_address, sas_device.device_info, | ||
635 | sas_device.slot, enclosure_info.enclosure_logical_id); | ||
636 | } | ||
637 | |||
638 | /** | ||
639 | * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list | ||
640 | * @ioc: Pointer to MPT_ADAPTER structure | ||
641 | * @channel: fw mapped id's | ||
642 | * @id: | ||
643 | * | ||
644 | **/ | ||
645 | static void | ||
646 | mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, | ||
647 | struct scsi_target *starget) | ||
648 | { | ||
649 | CONFIGPARMS cfg; | ||
650 | ConfigPageHeader_t hdr; | ||
651 | dma_addr_t dma_handle; | ||
652 | pRaidVolumePage0_t buffer = NULL; | ||
653 | int i; | ||
654 | RaidPhysDiskPage0_t phys_disk; | ||
655 | struct mptsas_device_info *sas_info, *next; | ||
656 | |||
657 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); | ||
658 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); | ||
659 | hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; | ||
660 | /* assumption that all volumes on channel = 0 */ | ||
661 | cfg.pageAddr = starget->id; | ||
662 | cfg.cfghdr.hdr = &hdr; | ||
663 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | ||
664 | cfg.timeout = 10; | ||
665 | |||
666 | if (mpt_config(ioc, &cfg) != 0) | ||
667 | goto out; | ||
668 | |||
669 | if (!hdr.PageLength) | ||
670 | goto out; | ||
671 | |||
672 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, | ||
673 | &dma_handle); | ||
674 | |||
675 | if (!buffer) | ||
676 | goto out; | ||
677 | |||
678 | cfg.physAddr = dma_handle; | ||
679 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | ||
680 | |||
681 | if (mpt_config(ioc, &cfg) != 0) | ||
682 | goto out; | ||
683 | |||
684 | if (!buffer->NumPhysDisks) | ||
685 | goto out; | ||
686 | |||
687 | /* | ||
688 | * Adding entry for hidden components | ||
689 | */ | ||
690 | for (i = 0; i < buffer->NumPhysDisks; i++) { | ||
691 | |||
692 | if (mpt_raid_phys_disk_pg0(ioc, | ||
693 | buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) | ||
694 | continue; | ||
695 | |||
696 | mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus, | ||
697 | phys_disk.PhysDiskID); | ||
698 | |||
699 | mutex_lock(&ioc->sas_device_info_mutex); | ||
700 | list_for_each_entry(sas_info, &ioc->sas_device_info_list, | ||
701 | list) { | ||
702 | if (!sas_info->is_logical_volume && | ||
703 | (sas_info->fw.channel == phys_disk.PhysDiskBus && | ||
704 | sas_info->fw.id == phys_disk.PhysDiskID)) { | ||
705 | sas_info->is_hidden_raid_component = 1; | ||
706 | sas_info->volume_id = starget->id; | ||
707 | } | ||
708 | } | ||
709 | mutex_unlock(&ioc->sas_device_info_mutex); | ||
710 | |||
711 | } | ||
712 | |||
713 | /* | ||
714 | * Delete all matching devices out of the list | ||
715 | */ | ||
716 | mutex_lock(&ioc->sas_device_info_mutex); | ||
717 | list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, | ||
718 | list) { | ||
719 | if (sas_info->is_logical_volume && sas_info->fw.id == | ||
720 | starget->id) { | ||
721 | list_del(&sas_info->list); | ||
722 | kfree(sas_info); | ||
723 | } | ||
724 | } | ||
725 | |||
726 | sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); | ||
727 | if (sas_info) { | ||
728 | sas_info->fw.id = starget->id; | ||
729 | sas_info->os.id = starget->id; | ||
730 | sas_info->os.channel = starget->channel; | ||
731 | sas_info->is_logical_volume = 1; | ||
732 | INIT_LIST_HEAD(&sas_info->list); | ||
733 | list_add_tail(&sas_info->list, &ioc->sas_device_info_list); | ||
734 | } | ||
735 | mutex_unlock(&ioc->sas_device_info_mutex); | ||
736 | |||
737 | out: | ||
738 | if (buffer) | ||
739 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, | ||
740 | dma_handle); | ||
741 | } | ||
742 | |||
743 | /** | ||
744 | * mptsas_add_device_component_starget - | ||
745 | * @ioc: Pointer to MPT_ADAPTER structure | ||
746 | * @starget: | ||
747 | * | ||
748 | **/ | ||
749 | static void | ||
750 | mptsas_add_device_component_starget(MPT_ADAPTER *ioc, | ||
751 | struct scsi_target *starget) | ||
752 | { | ||
753 | VirtTarget *vtarget; | ||
754 | struct sas_rphy *rphy; | ||
755 | struct mptsas_phyinfo *phy_info = NULL; | ||
756 | struct mptsas_enclosure enclosure_info; | ||
757 | |||
758 | rphy = dev_to_rphy(starget->dev.parent); | ||
759 | vtarget = starget->hostdata; | ||
760 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, | ||
761 | rphy->identify.sas_address); | ||
762 | if (!phy_info) | ||
763 | return; | ||
764 | |||
765 | memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); | ||
766 | mptsas_sas_enclosure_pg0(ioc, &enclosure_info, | ||
767 | (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << | ||
768 | MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), | ||
769 | phy_info->attached.handle_enclosure); | ||
770 | |||
771 | mptsas_add_device_component(ioc, phy_info->attached.channel, | ||
772 | phy_info->attached.id, phy_info->attached.sas_address, | ||
773 | phy_info->attached.device_info, | ||
774 | phy_info->attached.slot, enclosure_info.enclosure_logical_id); | ||
775 | } | ||
776 | |||
777 | /** | ||
778 | * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached | ||
779 | * @ioc: Pointer to MPT_ADAPTER structure | ||
780 | * @channel: os mapped id's | ||
781 | * @id: | ||
782 | * | ||
783 | **/ | ||
784 | static void | ||
785 | mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) | ||
786 | { | ||
787 | struct mptsas_device_info *sas_info, *next; | ||
788 | |||
789 | /* | ||
790 | * Set is_cached flag | ||
791 | */ | ||
792 | list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, | ||
793 | list) { | ||
794 | if (sas_info->os.channel == channel && sas_info->os.id == id) | ||
795 | sas_info->is_cached = 1; | ||
796 | } | ||
797 | } | ||
798 | |||
799 | /** | ||
800 | * mptsas_del_device_components - Cleaning the list | ||
801 | * @ioc: Pointer to MPT_ADAPTER structure | ||
802 | * | ||
803 | **/ | ||
804 | static void | ||
805 | mptsas_del_device_components(MPT_ADAPTER *ioc) | ||
806 | { | ||
807 | struct mptsas_device_info *sas_info, *next; | ||
808 | |||
809 | mutex_lock(&ioc->sas_device_info_mutex); | ||
810 | list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, | ||
811 | list) { | ||
812 | list_del(&sas_info->list); | ||
813 | kfree(sas_info); | ||
814 | } | ||
815 | mutex_unlock(&ioc->sas_device_info_mutex); | ||
816 | } | ||
817 | |||
382 | 818 | ||
383 | /* | 819 | /* |
384 | * mptsas_setup_wide_ports | 820 | * mptsas_setup_wide_ports |
@@ -434,8 +870,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) | |||
434 | * Forming a port | 870 | * Forming a port |
435 | */ | 871 | */ |
436 | if (!port_details) { | 872 | if (!port_details) { |
437 | port_details = kzalloc(sizeof(*port_details), | 873 | port_details = kzalloc(sizeof(struct |
438 | GFP_KERNEL); | 874 | mptsas_portinfo_details), GFP_KERNEL); |
439 | if (!port_details) | 875 | if (!port_details) |
440 | goto out; | 876 | goto out; |
441 | port_details->num_phys = 1; | 877 | port_details->num_phys = 1; |
@@ -523,15 +959,62 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
523 | VirtTarget *vtarget = NULL; | 959 | VirtTarget *vtarget = NULL; |
524 | 960 | ||
525 | shost_for_each_device(sdev, ioc->sh) { | 961 | shost_for_each_device(sdev, ioc->sh) { |
526 | if ((vdevice = sdev->hostdata) == NULL) | 962 | vdevice = sdev->hostdata; |
963 | if ((vdevice == NULL) || | ||
964 | (vdevice->vtarget == NULL)) | ||
965 | continue; | ||
966 | if ((vdevice->vtarget->tflags & | ||
967 | MPT_TARGET_FLAGS_RAID_COMPONENT || | ||
968 | vdevice->vtarget->raidVolume)) | ||
527 | continue; | 969 | continue; |
528 | if (vdevice->vtarget->id == id && | 970 | if (vdevice->vtarget->id == id && |
529 | vdevice->vtarget->channel == channel) | 971 | vdevice->vtarget->channel == channel) |
530 | vtarget = vdevice->vtarget; | 972 | vtarget = vdevice->vtarget; |
531 | } | 973 | } |
532 | return vtarget; | 974 | return vtarget; |
533 | } | 975 | } |
534 | 976 | ||
977 | static void | ||
978 | mptsas_queue_device_delete(MPT_ADAPTER *ioc, | ||
979 | MpiEventDataSasDeviceStatusChange_t *sas_event_data) | ||
980 | { | ||
981 | struct fw_event_work *fw_event; | ||
982 | int sz; | ||
983 | |||
984 | sz = offsetof(struct fw_event_work, event_data) + | ||
985 | sizeof(MpiEventDataSasDeviceStatusChange_t); | ||
986 | fw_event = kzalloc(sz, GFP_ATOMIC); | ||
987 | if (!fw_event) { | ||
988 | printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", | ||
989 | ioc->name, __func__, __LINE__); | ||
990 | return; | ||
991 | } | ||
992 | memcpy(fw_event->event_data, sas_event_data, | ||
993 | sizeof(MpiEventDataSasDeviceStatusChange_t)); | ||
994 | fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE; | ||
995 | fw_event->ioc = ioc; | ||
996 | mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); | ||
997 | } | ||
998 | |||
999 | static void | ||
1000 | mptsas_queue_rescan(MPT_ADAPTER *ioc) | ||
1001 | { | ||
1002 | struct fw_event_work *fw_event; | ||
1003 | int sz; | ||
1004 | |||
1005 | sz = offsetof(struct fw_event_work, event_data); | ||
1006 | fw_event = kzalloc(sz, GFP_ATOMIC); | ||
1007 | if (!fw_event) { | ||
1008 | printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", | ||
1009 | ioc->name, __func__, __LINE__); | ||
1010 | return; | ||
1011 | } | ||
1012 | fw_event->event = -1; | ||
1013 | fw_event->ioc = ioc; | ||
1014 | mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); | ||
1015 | } | ||
1016 | |||
1017 | |||
535 | /** | 1018 | /** |
536 | * mptsas_target_reset | 1019 | * mptsas_target_reset |
537 | * | 1020 | * |
@@ -550,13 +1033,21 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
550 | { | 1033 | { |
551 | MPT_FRAME_HDR *mf; | 1034 | MPT_FRAME_HDR *mf; |
552 | SCSITaskMgmt_t *pScsiTm; | 1035 | SCSITaskMgmt_t *pScsiTm; |
553 | 1036 | if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) | |
554 | if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { | ||
555 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n", | ||
556 | ioc->name,__func__, __LINE__)); | ||
557 | return 0; | 1037 | return 0; |
1038 | |||
1039 | |||
1040 | mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); | ||
1041 | if (mf == NULL) { | ||
1042 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT | ||
1043 | "%s, no msg frames @%d!!\n", ioc->name, | ||
1044 | __func__, __LINE__)); | ||
1045 | goto out_fail; | ||
558 | } | 1046 | } |
559 | 1047 | ||
1048 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", | ||
1049 | ioc->name, mf)); | ||
1050 | |||
560 | /* Format the Request | 1051 | /* Format the Request |
561 | */ | 1052 | */ |
562 | pScsiTm = (SCSITaskMgmt_t *) mf; | 1053 | pScsiTm = (SCSITaskMgmt_t *) mf; |
@@ -569,9 +1060,18 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
569 | 1060 | ||
570 | DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); | 1061 | DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); |
571 | 1062 | ||
572 | mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); | 1063 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
1064 | "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n", | ||
1065 | ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id)); | ||
1066 | |||
1067 | mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); | ||
573 | 1068 | ||
574 | return 1; | 1069 | return 1; |
1070 | |||
1071 | out_fail: | ||
1072 | |||
1073 | mpt_clear_taskmgmt_in_progress_flag(ioc); | ||
1074 | return 0; | ||
575 | } | 1075 | } |
576 | 1076 | ||
577 | /** | 1077 | /** |
@@ -602,11 +1102,12 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, | |||
602 | 1102 | ||
603 | vtarget->deleted = 1; /* block IO */ | 1103 | vtarget->deleted = 1; /* block IO */ |
604 | 1104 | ||
605 | target_reset_list = kzalloc(sizeof(*target_reset_list), | 1105 | target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), |
606 | GFP_ATOMIC); | 1106 | GFP_ATOMIC); |
607 | if (!target_reset_list) { | 1107 | if (!target_reset_list) { |
608 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", | 1108 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT |
609 | ioc->name,__func__, __LINE__)); | 1109 | "%s, failed to allocate mem @%d..!!\n", |
1110 | ioc->name, __func__, __LINE__)); | ||
610 | return; | 1111 | return; |
611 | } | 1112 | } |
612 | 1113 | ||
@@ -614,84 +1115,101 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, | |||
614 | sizeof(*sas_event_data)); | 1115 | sizeof(*sas_event_data)); |
615 | list_add_tail(&target_reset_list->list, &hd->target_reset_list); | 1116 | list_add_tail(&target_reset_list->list, &hd->target_reset_list); |
616 | 1117 | ||
617 | if (hd->resetPending) | 1118 | target_reset_list->time_count = jiffies; |
618 | return; | ||
619 | 1119 | ||
620 | if (mptsas_target_reset(ioc, channel, id)) { | 1120 | if (mptsas_target_reset(ioc, channel, id)) { |
621 | target_reset_list->target_reset_issued = 1; | 1121 | target_reset_list->target_reset_issued = 1; |
622 | hd->resetPending = 1; | ||
623 | } | 1122 | } |
624 | } | 1123 | } |
625 | 1124 | ||
626 | /** | 1125 | /** |
627 | * mptsas_dev_reset_complete | 1126 | * mptsas_taskmgmt_complete - complete SAS task management function |
628 | * | 1127 | * @ioc: Pointer to MPT_ADAPTER structure |
629 | * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, | ||
630 | * enable work queue to finish off removing device from upper layers. | ||
631 | * then send next TARGET_RESET in the queue. | ||
632 | * | ||
633 | * @ioc | ||
634 | * | 1128 | * |
1129 | * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work | ||
1130 | * queue to finish off removing device from upper layers. then send next | ||
1131 | * TARGET_RESET in the queue. | ||
635 | **/ | 1132 | **/ |
636 | static void | 1133 | static int |
637 | mptsas_dev_reset_complete(MPT_ADAPTER *ioc) | 1134 | mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) |
638 | { | 1135 | { |
639 | MPT_SCSI_HOST *hd = shost_priv(ioc->sh); | 1136 | MPT_SCSI_HOST *hd = shost_priv(ioc->sh); |
640 | struct list_head *head = &hd->target_reset_list; | 1137 | struct list_head *head = &hd->target_reset_list; |
641 | struct mptsas_target_reset_event *target_reset_list; | ||
642 | struct mptsas_hotplug_event *ev; | ||
643 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; | ||
644 | u8 id, channel; | 1138 | u8 id, channel; |
645 | __le64 sas_address; | 1139 | struct mptsas_target_reset_event *target_reset_list; |
1140 | SCSITaskMgmtReply_t *pScsiTmReply; | ||
1141 | |||
1142 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: " | ||
1143 | "(mf = %p, mr = %p)\n", ioc->name, mf, mr)); | ||
1144 | |||
1145 | pScsiTmReply = (SCSITaskMgmtReply_t *)mr; | ||
1146 | if (pScsiTmReply) { | ||
1147 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
1148 | "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n" | ||
1149 | "\ttask_type = 0x%02X, iocstatus = 0x%04X " | ||
1150 | "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, " | ||
1151 | "term_cmnds = %d\n", ioc->name, | ||
1152 | pScsiTmReply->Bus, pScsiTmReply->TargetID, | ||
1153 | pScsiTmReply->TaskType, | ||
1154 | le16_to_cpu(pScsiTmReply->IOCStatus), | ||
1155 | le32_to_cpu(pScsiTmReply->IOCLogInfo), | ||
1156 | pScsiTmReply->ResponseCode, | ||
1157 | le32_to_cpu(pScsiTmReply->TerminationCount))); | ||
1158 | |||
1159 | if (pScsiTmReply->ResponseCode) | ||
1160 | mptscsih_taskmgmt_response_code(ioc, | ||
1161 | pScsiTmReply->ResponseCode); | ||
1162 | } | ||
1163 | |||
1164 | if (pScsiTmReply && (pScsiTmReply->TaskType == | ||
1165 | MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType == | ||
1166 | MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) { | ||
1167 | ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; | ||
1168 | ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; | ||
1169 | memcpy(ioc->taskmgmt_cmds.reply, mr, | ||
1170 | min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); | ||
1171 | if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { | ||
1172 | ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; | ||
1173 | complete(&ioc->taskmgmt_cmds.done); | ||
1174 | return 1; | ||
1175 | } | ||
1176 | return 0; | ||
1177 | } | ||
1178 | |||
1179 | mpt_clear_taskmgmt_in_progress_flag(ioc); | ||
646 | 1180 | ||
647 | if (list_empty(head)) | 1181 | if (list_empty(head)) |
648 | return; | 1182 | return 1; |
649 | 1183 | ||
650 | target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list); | 1184 | target_reset_list = list_entry(head->next, |
1185 | struct mptsas_target_reset_event, list); | ||
651 | 1186 | ||
652 | sas_event_data = &target_reset_list->sas_event_data; | 1187 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
653 | id = sas_event_data->TargetID; | 1188 | "TaskMgmt: completed (%d seconds)\n", |
654 | channel = sas_event_data->Bus; | 1189 | ioc->name, jiffies_to_msecs(jiffies - |
655 | hd->resetPending = 0; | 1190 | target_reset_list->time_count)/1000)); |
1191 | |||
1192 | id = pScsiTmReply->TargetID; | ||
1193 | channel = pScsiTmReply->Bus; | ||
1194 | target_reset_list->time_count = jiffies; | ||
656 | 1195 | ||
657 | /* | 1196 | /* |
658 | * retry target reset | 1197 | * retry target reset |
659 | */ | 1198 | */ |
660 | if (!target_reset_list->target_reset_issued) { | 1199 | if (!target_reset_list->target_reset_issued) { |
661 | if (mptsas_target_reset(ioc, channel, id)) { | 1200 | if (mptsas_target_reset(ioc, channel, id)) |
662 | target_reset_list->target_reset_issued = 1; | 1201 | target_reset_list->target_reset_issued = 1; |
663 | hd->resetPending = 1; | 1202 | return 1; |
664 | } | ||
665 | return; | ||
666 | } | 1203 | } |
667 | 1204 | ||
668 | /* | 1205 | /* |
669 | * enable work queue to remove device from upper layers | 1206 | * enable work queue to remove device from upper layers |
670 | */ | 1207 | */ |
671 | list_del(&target_reset_list->list); | 1208 | list_del(&target_reset_list->list); |
1209 | if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off) | ||
1210 | mptsas_queue_device_delete(ioc, | ||
1211 | &target_reset_list->sas_event_data); | ||
672 | 1212 | ||
673 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | ||
674 | if (!ev) { | ||
675 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", | ||
676 | ioc->name,__func__, __LINE__)); | ||
677 | return; | ||
678 | } | ||
679 | |||
680 | INIT_WORK(&ev->work, mptsas_hotplug_work); | ||
681 | ev->ioc = ioc; | ||
682 | ev->handle = le16_to_cpu(sas_event_data->DevHandle); | ||
683 | ev->parent_handle = | ||
684 | le16_to_cpu(sas_event_data->ParentDevHandle); | ||
685 | ev->channel = channel; | ||
686 | ev->id =id; | ||
687 | ev->phy_id = sas_event_data->PhyNum; | ||
688 | memcpy(&sas_address, &sas_event_data->SASAddress, | ||
689 | sizeof(__le64)); | ||
690 | ev->sas_address = le64_to_cpu(sas_address); | ||
691 | ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo); | ||
692 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
693 | schedule_work(&ev->work); | ||
694 | kfree(target_reset_list); | ||
695 | 1213 | ||
696 | /* | 1214 | /* |
697 | * issue target reset to next device in the queue | 1215 | * issue target reset to next device in the queue |
@@ -699,34 +1217,19 @@ mptsas_dev_reset_complete(MPT_ADAPTER *ioc) | |||
699 | 1217 | ||
700 | head = &hd->target_reset_list; | 1218 | head = &hd->target_reset_list; |
701 | if (list_empty(head)) | 1219 | if (list_empty(head)) |
702 | return; | 1220 | return 1; |
703 | 1221 | ||
704 | target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, | 1222 | target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, |
705 | list); | 1223 | list); |
706 | 1224 | ||
707 | sas_event_data = &target_reset_list->sas_event_data; | 1225 | id = target_reset_list->sas_event_data.TargetID; |
708 | id = sas_event_data->TargetID; | 1226 | channel = target_reset_list->sas_event_data.Bus; |
709 | channel = sas_event_data->Bus; | 1227 | target_reset_list->time_count = jiffies; |
710 | 1228 | ||
711 | if (mptsas_target_reset(ioc, channel, id)) { | 1229 | if (mptsas_target_reset(ioc, channel, id)) |
712 | target_reset_list->target_reset_issued = 1; | 1230 | target_reset_list->target_reset_issued = 1; |
713 | hd->resetPending = 1; | ||
714 | } | ||
715 | } | ||
716 | 1231 | ||
717 | /** | 1232 | return 1; |
718 | * mptsas_taskmgmt_complete | ||
719 | * | ||
720 | * @ioc | ||
721 | * @mf | ||
722 | * @mr | ||
723 | * | ||
724 | **/ | ||
725 | static int | ||
726 | mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) | ||
727 | { | ||
728 | mptsas_dev_reset_complete(ioc); | ||
729 | return mptscsih_taskmgmt_complete(ioc, mf, mr); | ||
730 | } | 1233 | } |
731 | 1234 | ||
732 | /** | 1235 | /** |
@@ -740,37 +1243,59 @@ static int | |||
740 | mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) | 1243 | mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) |
741 | { | 1244 | { |
742 | MPT_SCSI_HOST *hd; | 1245 | MPT_SCSI_HOST *hd; |
743 | struct mptsas_target_reset_event *target_reset_list, *n; | ||
744 | int rc; | 1246 | int rc; |
745 | 1247 | ||
746 | rc = mptscsih_ioc_reset(ioc, reset_phase); | 1248 | rc = mptscsih_ioc_reset(ioc, reset_phase); |
1249 | if ((ioc->bus_type != SAS) || (!rc)) | ||
1250 | return rc; | ||
747 | 1251 | ||
748 | if (ioc->bus_type != SAS) | ||
749 | goto out; | ||
750 | |||
751 | if (reset_phase != MPT_IOC_POST_RESET) | ||
752 | goto out; | ||
753 | |||
754 | if (!ioc->sh || !ioc->sh->hostdata) | ||
755 | goto out; | ||
756 | hd = shost_priv(ioc->sh); | 1252 | hd = shost_priv(ioc->sh); |
757 | if (!hd->ioc) | 1253 | if (!hd->ioc) |
758 | goto out; | 1254 | goto out; |
759 | 1255 | ||
760 | if (list_empty(&hd->target_reset_list)) | 1256 | switch (reset_phase) { |
761 | goto out; | 1257 | case MPT_IOC_SETUP_RESET: |
762 | 1258 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | |
763 | /* flush the target_reset_list */ | 1259 | "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); |
764 | list_for_each_entry_safe(target_reset_list, n, | 1260 | mptsas_fw_event_off(ioc); |
765 | &hd->target_reset_list, list) { | 1261 | break; |
766 | list_del(&target_reset_list->list); | 1262 | case MPT_IOC_PRE_RESET: |
767 | kfree(target_reset_list); | 1263 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
1264 | "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); | ||
1265 | break; | ||
1266 | case MPT_IOC_POST_RESET: | ||
1267 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
1268 | "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); | ||
1269 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { | ||
1270 | ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; | ||
1271 | complete(&ioc->sas_mgmt.done); | ||
1272 | } | ||
1273 | mptsas_cleanup_fw_event_q(ioc); | ||
1274 | mptsas_queue_rescan(ioc); | ||
1275 | mptsas_fw_event_on(ioc); | ||
1276 | break; | ||
1277 | default: | ||
1278 | break; | ||
768 | } | 1279 | } |
769 | 1280 | ||
770 | out: | 1281 | out: |
771 | return rc; | 1282 | return rc; |
772 | } | 1283 | } |
773 | 1284 | ||
1285 | |||
1286 | /** | ||
1287 | * enum device_state - | ||
1288 | * @DEVICE_RETRY: need to retry the TUR | ||
1289 | * @DEVICE_ERROR: TUR return error, don't add device | ||
1290 | * @DEVICE_READY: device can be added | ||
1291 | * | ||
1292 | */ | ||
1293 | enum device_state{ | ||
1294 | DEVICE_RETRY, | ||
1295 | DEVICE_ERROR, | ||
1296 | DEVICE_READY, | ||
1297 | }; | ||
1298 | |||
774 | static int | 1299 | static int |
775 | mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, | 1300 | mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, |
776 | u32 form, u32 form_specific) | 1301 | u32 form, u32 form_specific) |
@@ -836,15 +1361,308 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, | |||
836 | return error; | 1361 | return error; |
837 | } | 1362 | } |
838 | 1363 | ||
1364 | /** | ||
1365 | * mptsas_add_end_device - report a new end device to sas transport layer | ||
1366 | * @ioc: Pointer to MPT_ADAPTER structure | ||
1367 | * @phy_info: decribes attached device | ||
1368 | * | ||
1369 | * return (0) success (1) failure | ||
1370 | * | ||
1371 | **/ | ||
1372 | static int | ||
1373 | mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) | ||
1374 | { | ||
1375 | struct sas_rphy *rphy; | ||
1376 | struct sas_port *port; | ||
1377 | struct sas_identify identify; | ||
1378 | char *ds = NULL; | ||
1379 | u8 fw_id; | ||
1380 | |||
1381 | if (!phy_info) { | ||
1382 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1383 | "%s: exit at line=%d\n", ioc->name, | ||
1384 | __func__, __LINE__)); | ||
1385 | return 1; | ||
1386 | } | ||
1387 | |||
1388 | fw_id = phy_info->attached.id; | ||
1389 | |||
1390 | if (mptsas_get_rphy(phy_info)) { | ||
1391 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1392 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1393 | __func__, fw_id, __LINE__)); | ||
1394 | return 2; | ||
1395 | } | ||
1396 | |||
1397 | port = mptsas_get_port(phy_info); | ||
1398 | if (!port) { | ||
1399 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1400 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1401 | __func__, fw_id, __LINE__)); | ||
1402 | return 3; | ||
1403 | } | ||
1404 | |||
1405 | if (phy_info->attached.device_info & | ||
1406 | MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
1407 | ds = "ssp"; | ||
1408 | if (phy_info->attached.device_info & | ||
1409 | MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
1410 | ds = "stp"; | ||
1411 | if (phy_info->attached.device_info & | ||
1412 | MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
1413 | ds = "sata"; | ||
1414 | |||
1415 | printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d," | ||
1416 | " phy %d, sas_addr 0x%llx\n", ioc->name, ds, | ||
1417 | phy_info->attached.channel, phy_info->attached.id, | ||
1418 | phy_info->attached.phy_id, (unsigned long long) | ||
1419 | phy_info->attached.sas_address); | ||
1420 | |||
1421 | mptsas_parse_device_info(&identify, &phy_info->attached); | ||
1422 | rphy = sas_end_device_alloc(port); | ||
1423 | if (!rphy) { | ||
1424 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1425 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1426 | __func__, fw_id, __LINE__)); | ||
1427 | return 5; /* non-fatal: an rphy can be added later */ | ||
1428 | } | ||
1429 | |||
1430 | rphy->identify = identify; | ||
1431 | if (sas_rphy_add(rphy)) { | ||
1432 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1433 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1434 | __func__, fw_id, __LINE__)); | ||
1435 | sas_rphy_free(rphy); | ||
1436 | return 6; | ||
1437 | } | ||
1438 | mptsas_set_rphy(ioc, phy_info, rphy); | ||
1439 | return 0; | ||
1440 | } | ||
1441 | |||
1442 | /** | ||
1443 | * mptsas_del_end_device - report a deleted end device to sas transport layer | ||
1444 | * @ioc: Pointer to MPT_ADAPTER structure | ||
1445 | * @phy_info: decribes attached device | ||
1446 | * | ||
1447 | **/ | ||
1448 | static void | ||
1449 | mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) | ||
1450 | { | ||
1451 | struct sas_rphy *rphy; | ||
1452 | struct sas_port *port; | ||
1453 | struct mptsas_portinfo *port_info; | ||
1454 | struct mptsas_phyinfo *phy_info_parent; | ||
1455 | int i; | ||
1456 | char *ds = NULL; | ||
1457 | u8 fw_id; | ||
1458 | u64 sas_address; | ||
1459 | |||
1460 | if (!phy_info) | ||
1461 | return; | ||
1462 | |||
1463 | fw_id = phy_info->attached.id; | ||
1464 | sas_address = phy_info->attached.sas_address; | ||
1465 | |||
1466 | if (!phy_info->port_details) { | ||
1467 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1468 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1469 | __func__, fw_id, __LINE__)); | ||
1470 | return; | ||
1471 | } | ||
1472 | rphy = mptsas_get_rphy(phy_info); | ||
1473 | if (!rphy) { | ||
1474 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1475 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1476 | __func__, fw_id, __LINE__)); | ||
1477 | return; | ||
1478 | } | ||
1479 | |||
1480 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR | ||
1481 | || phy_info->attached.device_info | ||
1482 | & MPI_SAS_DEVICE_INFO_SMP_INITIATOR | ||
1483 | || phy_info->attached.device_info | ||
1484 | & MPI_SAS_DEVICE_INFO_STP_INITIATOR) | ||
1485 | ds = "initiator"; | ||
1486 | if (phy_info->attached.device_info & | ||
1487 | MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
1488 | ds = "ssp"; | ||
1489 | if (phy_info->attached.device_info & | ||
1490 | MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
1491 | ds = "stp"; | ||
1492 | if (phy_info->attached.device_info & | ||
1493 | MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
1494 | ds = "sata"; | ||
1495 | |||
1496 | dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT | ||
1497 | "removing %s device: fw_channel %d, fw_id %d, phy %d," | ||
1498 | "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel, | ||
1499 | phy_info->attached.id, phy_info->attached.phy_id, | ||
1500 | (unsigned long long) sas_address); | ||
1501 | |||
1502 | port = mptsas_get_port(phy_info); | ||
1503 | if (!port) { | ||
1504 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
1505 | "%s: fw_id=%d exit at line=%d\n", ioc->name, | ||
1506 | __func__, fw_id, __LINE__)); | ||
1507 | return; | ||
1508 | } | ||
1509 | port_info = phy_info->portinfo; | ||
1510 | phy_info_parent = port_info->phy_info; | ||
1511 | for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) { | ||
1512 | if (!phy_info_parent->phy) | ||
1513 | continue; | ||
1514 | if (phy_info_parent->attached.sas_address != | ||
1515 | sas_address) | ||
1516 | continue; | ||
1517 | dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev, | ||
1518 | MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", | ||
1519 | ioc->name, phy_info_parent->phy_id, | ||
1520 | phy_info_parent->phy); | ||
1521 | sas_port_delete_phy(port, phy_info_parent->phy); | ||
1522 | } | ||
1523 | |||
1524 | dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT | ||
1525 | "delete port %d, sas_addr (0x%llx)\n", ioc->name, | ||
1526 | port->port_identifier, (unsigned long long)sas_address); | ||
1527 | sas_port_delete(port); | ||
1528 | mptsas_set_port(ioc, phy_info, NULL); | ||
1529 | mptsas_port_delete(ioc, phy_info->port_details); | ||
1530 | } | ||
1531 | |||
1532 | struct mptsas_phyinfo * | ||
1533 | mptsas_refreshing_device_handles(MPT_ADAPTER *ioc, | ||
1534 | struct mptsas_devinfo *sas_device) | ||
1535 | { | ||
1536 | struct mptsas_phyinfo *phy_info; | ||
1537 | struct mptsas_portinfo *port_info; | ||
1538 | int i; | ||
1539 | |||
1540 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, | ||
1541 | sas_device->sas_address); | ||
1542 | if (!phy_info) | ||
1543 | goto out; | ||
1544 | port_info = phy_info->portinfo; | ||
1545 | if (!port_info) | ||
1546 | goto out; | ||
1547 | mutex_lock(&ioc->sas_topology_mutex); | ||
1548 | for (i = 0; i < port_info->num_phys; i++) { | ||
1549 | if (port_info->phy_info[i].attached.sas_address != | ||
1550 | sas_device->sas_address) | ||
1551 | continue; | ||
1552 | port_info->phy_info[i].attached.channel = sas_device->channel; | ||
1553 | port_info->phy_info[i].attached.id = sas_device->id; | ||
1554 | port_info->phy_info[i].attached.sas_address = | ||
1555 | sas_device->sas_address; | ||
1556 | port_info->phy_info[i].attached.handle = sas_device->handle; | ||
1557 | port_info->phy_info[i].attached.handle_parent = | ||
1558 | sas_device->handle_parent; | ||
1559 | port_info->phy_info[i].attached.handle_enclosure = | ||
1560 | sas_device->handle_enclosure; | ||
1561 | } | ||
1562 | mutex_unlock(&ioc->sas_topology_mutex); | ||
1563 | out: | ||
1564 | return phy_info; | ||
1565 | } | ||
1566 | |||
1567 | /** | ||
1568 | * mptsas_firmware_event_work - work thread for processing fw events | ||
1569 | * @work: work queue payload containing info describing the event | ||
1570 | * Context: user | ||
1571 | * | ||
1572 | */ | ||
1573 | static void | ||
1574 | mptsas_firmware_event_work(struct work_struct *work) | ||
1575 | { | ||
1576 | struct fw_event_work *fw_event = | ||
1577 | container_of(work, struct fw_event_work, work.work); | ||
1578 | MPT_ADAPTER *ioc = fw_event->ioc; | ||
1579 | |||
1580 | /* special rescan topology handling */ | ||
1581 | if (fw_event->event == -1) { | ||
1582 | if (ioc->in_rescan) { | ||
1583 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
1584 | "%s: rescan ignored as it is in progress\n", | ||
1585 | ioc->name, __func__)); | ||
1586 | return; | ||
1587 | } | ||
1588 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after " | ||
1589 | "reset\n", ioc->name, __func__)); | ||
1590 | ioc->in_rescan = 1; | ||
1591 | mptsas_not_responding_devices(ioc); | ||
1592 | mptsas_scan_sas_topology(ioc); | ||
1593 | ioc->in_rescan = 0; | ||
1594 | mptsas_free_fw_event(ioc, fw_event); | ||
1595 | return; | ||
1596 | } | ||
1597 | |||
1598 | /* events handling turned off during host reset */ | ||
1599 | if (ioc->fw_events_off) { | ||
1600 | mptsas_free_fw_event(ioc, fw_event); | ||
1601 | return; | ||
1602 | } | ||
1603 | |||
1604 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), " | ||
1605 | "event = (0x%02x)\n", ioc->name, __func__, fw_event, | ||
1606 | (fw_event->event & 0xFF))); | ||
1607 | |||
1608 | switch (fw_event->event) { | ||
1609 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | ||
1610 | mptsas_send_sas_event(fw_event); | ||
1611 | break; | ||
1612 | case MPI_EVENT_INTEGRATED_RAID: | ||
1613 | mptsas_send_raid_event(fw_event); | ||
1614 | break; | ||
1615 | case MPI_EVENT_IR2: | ||
1616 | mptsas_send_ir2_event(fw_event); | ||
1617 | break; | ||
1618 | case MPI_EVENT_PERSISTENT_TABLE_FULL: | ||
1619 | mptbase_sas_persist_operation(ioc, | ||
1620 | MPI_SAS_OP_CLEAR_NOT_PRESENT); | ||
1621 | mptsas_free_fw_event(ioc, fw_event); | ||
1622 | break; | ||
1623 | case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: | ||
1624 | mptsas_broadcast_primative_work(fw_event); | ||
1625 | break; | ||
1626 | case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: | ||
1627 | mptsas_send_expander_event(fw_event); | ||
1628 | break; | ||
1629 | case MPI_EVENT_SAS_PHY_LINK_STATUS: | ||
1630 | mptsas_send_link_status_event(fw_event); | ||
1631 | break; | ||
1632 | case MPI_EVENT_QUEUE_FULL: | ||
1633 | mptsas_handle_queue_full_event(fw_event); | ||
1634 | break; | ||
1635 | } | ||
1636 | } | ||
1637 | |||
1638 | |||
1639 | |||
839 | static int | 1640 | static int |
840 | mptsas_slave_configure(struct scsi_device *sdev) | 1641 | mptsas_slave_configure(struct scsi_device *sdev) |
841 | { | 1642 | { |
1643 | struct Scsi_Host *host = sdev->host; | ||
1644 | MPT_SCSI_HOST *hd = shost_priv(host); | ||
1645 | MPT_ADAPTER *ioc = hd->ioc; | ||
1646 | VirtDevice *vdevice = sdev->hostdata; | ||
842 | 1647 | ||
843 | if (sdev->channel == MPTSAS_RAID_CHANNEL) | 1648 | if (vdevice->vtarget->deleted) { |
1649 | sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n"); | ||
1650 | vdevice->vtarget->deleted = 0; | ||
1651 | } | ||
1652 | |||
1653 | /* | ||
1654 | * RAID volumes placed beyond the last expected port. | ||
1655 | * Ignore sending sas mode pages in that case.. | ||
1656 | */ | ||
1657 | if (sdev->channel == MPTSAS_RAID_CHANNEL) { | ||
1658 | mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev)); | ||
844 | goto out; | 1659 | goto out; |
1660 | } | ||
845 | 1661 | ||
846 | sas_read_port_mode_page(sdev); | 1662 | sas_read_port_mode_page(sdev); |
847 | 1663 | ||
1664 | mptsas_add_device_component_starget(ioc, scsi_target(sdev)); | ||
1665 | |||
848 | out: | 1666 | out: |
849 | return mptscsih_slave_configure(sdev); | 1667 | return mptscsih_slave_configure(sdev); |
850 | } | 1668 | } |
@@ -875,9 +1693,18 @@ mptsas_target_alloc(struct scsi_target *starget) | |||
875 | * RAID volumes placed beyond the last expected port. | 1693 | * RAID volumes placed beyond the last expected port. |
876 | */ | 1694 | */ |
877 | if (starget->channel == MPTSAS_RAID_CHANNEL) { | 1695 | if (starget->channel == MPTSAS_RAID_CHANNEL) { |
878 | for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) | 1696 | if (!ioc->raid_data.pIocPg2) { |
879 | if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) | 1697 | kfree(vtarget); |
880 | channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; | 1698 | return -ENXIO; |
1699 | } | ||
1700 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { | ||
1701 | if (id == ioc->raid_data.pIocPg2-> | ||
1702 | RaidVolume[i].VolumeID) { | ||
1703 | channel = ioc->raid_data.pIocPg2-> | ||
1704 | RaidVolume[i].VolumeBus; | ||
1705 | } | ||
1706 | } | ||
1707 | vtarget->raidVolume = 1; | ||
881 | goto out; | 1708 | goto out; |
882 | } | 1709 | } |
883 | 1710 | ||
@@ -926,11 +1753,18 @@ mptsas_target_destroy(struct scsi_target *starget) | |||
926 | struct sas_rphy *rphy; | 1753 | struct sas_rphy *rphy; |
927 | struct mptsas_portinfo *p; | 1754 | struct mptsas_portinfo *p; |
928 | int i; | 1755 | int i; |
929 | MPT_ADAPTER *ioc = hd->ioc; | 1756 | MPT_ADAPTER *ioc = hd->ioc; |
1757 | VirtTarget *vtarget; | ||
930 | 1758 | ||
931 | if (!starget->hostdata) | 1759 | if (!starget->hostdata) |
932 | return; | 1760 | return; |
933 | 1761 | ||
1762 | vtarget = starget->hostdata; | ||
1763 | |||
1764 | mptsas_del_device_component_by_os(ioc, starget->channel, | ||
1765 | starget->id); | ||
1766 | |||
1767 | |||
934 | if (starget->channel == MPTSAS_RAID_CHANNEL) | 1768 | if (starget->channel == MPTSAS_RAID_CHANNEL) |
935 | goto out; | 1769 | goto out; |
936 | 1770 | ||
@@ -940,12 +1774,21 @@ mptsas_target_destroy(struct scsi_target *starget) | |||
940 | if (p->phy_info[i].attached.sas_address != | 1774 | if (p->phy_info[i].attached.sas_address != |
941 | rphy->identify.sas_address) | 1775 | rphy->identify.sas_address) |
942 | continue; | 1776 | continue; |
1777 | |||
1778 | starget_printk(KERN_INFO, starget, MYIOC_s_FMT | ||
1779 | "delete device: fw_channel %d, fw_id %d, phy %d, " | ||
1780 | "sas_addr 0x%llx\n", ioc->name, | ||
1781 | p->phy_info[i].attached.channel, | ||
1782 | p->phy_info[i].attached.id, | ||
1783 | p->phy_info[i].attached.phy_id, (unsigned long long) | ||
1784 | p->phy_info[i].attached.sas_address); | ||
1785 | |||
943 | mptsas_set_starget(&p->phy_info[i], NULL); | 1786 | mptsas_set_starget(&p->phy_info[i], NULL); |
944 | goto out; | ||
945 | } | 1787 | } |
946 | } | 1788 | } |
947 | 1789 | ||
948 | out: | 1790 | out: |
1791 | vtarget->starget = NULL; | ||
949 | kfree(starget->hostdata); | 1792 | kfree(starget->hostdata); |
950 | starget->hostdata = NULL; | 1793 | starget->hostdata = NULL; |
951 | } | 1794 | } |
@@ -1008,6 +1851,8 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
1008 | static int | 1851 | static int |
1009 | mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | 1852 | mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) |
1010 | { | 1853 | { |
1854 | MPT_SCSI_HOST *hd; | ||
1855 | MPT_ADAPTER *ioc; | ||
1011 | VirtDevice *vdevice = SCpnt->device->hostdata; | 1856 | VirtDevice *vdevice = SCpnt->device->hostdata; |
1012 | 1857 | ||
1013 | if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { | 1858 | if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { |
@@ -1016,6 +1861,12 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | |||
1016 | return 0; | 1861 | return 0; |
1017 | } | 1862 | } |
1018 | 1863 | ||
1864 | hd = shost_priv(SCpnt->device->host); | ||
1865 | ioc = hd->ioc; | ||
1866 | |||
1867 | if (ioc->sas_discovery_quiesce_io) | ||
1868 | return SCSI_MLQUEUE_HOST_BUSY; | ||
1869 | |||
1019 | // scsi_print_command(SCpnt); | 1870 | // scsi_print_command(SCpnt); |
1020 | 1871 | ||
1021 | return mptscsih_qcmd(SCpnt,done); | 1872 | return mptscsih_qcmd(SCpnt,done); |
@@ -1114,14 +1965,19 @@ static int mptsas_get_linkerrors(struct sas_phy *phy) | |||
1114 | static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, | 1965 | static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, |
1115 | MPT_FRAME_HDR *reply) | 1966 | MPT_FRAME_HDR *reply) |
1116 | { | 1967 | { |
1117 | ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD; | 1968 | ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD; |
1118 | if (reply != NULL) { | 1969 | if (reply != NULL) { |
1119 | ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID; | 1970 | ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID; |
1120 | memcpy(ioc->sas_mgmt.reply, reply, | 1971 | memcpy(ioc->sas_mgmt.reply, reply, |
1121 | min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); | 1972 | min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); |
1122 | } | 1973 | } |
1123 | complete(&ioc->sas_mgmt.done); | 1974 | |
1124 | return 1; | 1975 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { |
1976 | ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING; | ||
1977 | complete(&ioc->sas_mgmt.done); | ||
1978 | return 1; | ||
1979 | } | ||
1980 | return 0; | ||
1125 | } | 1981 | } |
1126 | 1982 | ||
1127 | static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) | 1983 | static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) |
@@ -1160,6 +2016,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) | |||
1160 | MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; | 2016 | MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; |
1161 | req->PhyNum = phy->identify.phy_identifier; | 2017 | req->PhyNum = phy->identify.phy_identifier; |
1162 | 2018 | ||
2019 | INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) | ||
1163 | mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); | 2020 | mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); |
1164 | 2021 | ||
1165 | timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, | 2022 | timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, |
@@ -1174,7 +2031,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) | |||
1174 | 2031 | ||
1175 | /* a reply frame is expected */ | 2032 | /* a reply frame is expected */ |
1176 | if ((ioc->sas_mgmt.status & | 2033 | if ((ioc->sas_mgmt.status & |
1177 | MPT_IOCTL_STATUS_RF_VALID) == 0) { | 2034 | MPT_MGMT_STATUS_RF_VALID) == 0) { |
1178 | error = -ENXIO; | 2035 | error = -ENXIO; |
1179 | goto out_unlock; | 2036 | goto out_unlock; |
1180 | } | 2037 | } |
@@ -1191,6 +2048,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) | |||
1191 | error = 0; | 2048 | error = 0; |
1192 | 2049 | ||
1193 | out_unlock: | 2050 | out_unlock: |
2051 | CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) | ||
1194 | mutex_unlock(&ioc->sas_mgmt.mutex); | 2052 | mutex_unlock(&ioc->sas_mgmt.mutex); |
1195 | out: | 2053 | out: |
1196 | return error; | 2054 | return error; |
@@ -1277,8 +2135,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
1277 | /* do we need to support multiple segments? */ | 2135 | /* do we need to support multiple segments? */ |
1278 | if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { | 2136 | if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { |
1279 | printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", | 2137 | printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", |
1280 | ioc->name, __func__, req->bio->bi_vcnt, req->data_len, | 2138 | ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req), |
1281 | rsp->bio->bi_vcnt, rsp->data_len); | 2139 | rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); |
1282 | return -EINVAL; | 2140 | return -EINVAL; |
1283 | } | 2141 | } |
1284 | 2142 | ||
@@ -1295,7 +2153,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
1295 | smpreq = (SmpPassthroughRequest_t *)mf; | 2153 | smpreq = (SmpPassthroughRequest_t *)mf; |
1296 | memset(smpreq, 0, sizeof(*smpreq)); | 2154 | memset(smpreq, 0, sizeof(*smpreq)); |
1297 | 2155 | ||
1298 | smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4); | 2156 | smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); |
1299 | smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; | 2157 | smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; |
1300 | 2158 | ||
1301 | if (rphy) | 2159 | if (rphy) |
@@ -1304,7 +2162,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
1304 | struct mptsas_portinfo *port_info; | 2162 | struct mptsas_portinfo *port_info; |
1305 | 2163 | ||
1306 | mutex_lock(&ioc->sas_topology_mutex); | 2164 | mutex_lock(&ioc->sas_topology_mutex); |
1307 | port_info = mptsas_get_hba_portinfo(ioc); | 2165 | port_info = ioc->hba_port_info; |
1308 | if (port_info && port_info->phy_info) | 2166 | if (port_info && port_info->phy_info) |
1309 | sas_address = | 2167 | sas_address = |
1310 | port_info->phy_info[0].phy->identify.sas_address; | 2168 | port_info->phy_info[0].phy->identify.sas_address; |
@@ -1319,26 +2177,32 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
1319 | /* request */ | 2177 | /* request */ |
1320 | flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | | 2178 | flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | |
1321 | MPI_SGE_FLAGS_END_OF_BUFFER | | 2179 | MPI_SGE_FLAGS_END_OF_BUFFER | |
1322 | MPI_SGE_FLAGS_DIRECTION | | 2180 | MPI_SGE_FLAGS_DIRECTION) |
1323 | mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT; | 2181 | << MPI_SGE_FLAGS_SHIFT; |
1324 | flagsLength |= (req->data_len - 4); | 2182 | flagsLength |= (blk_rq_bytes(req) - 4); |
1325 | 2183 | ||
1326 | dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio), | 2184 | dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio), |
1327 | req->data_len, PCI_DMA_BIDIRECTIONAL); | 2185 | blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); |
1328 | if (!dma_addr_out) | 2186 | if (!dma_addr_out) |
1329 | goto put_mf; | 2187 | goto put_mf; |
1330 | mpt_add_sge(psge, flagsLength, dma_addr_out); | 2188 | ioc->add_sge(psge, flagsLength, dma_addr_out); |
1331 | psge += (sizeof(u32) + sizeof(dma_addr_t)); | 2189 | psge += ioc->SGE_size; |
1332 | 2190 | ||
1333 | /* response */ | 2191 | /* response */ |
1334 | flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; | 2192 | flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | |
1335 | flagsLength |= rsp->data_len + 4; | 2193 | MPI_SGE_FLAGS_SYSTEM_ADDRESS | |
2194 | MPI_SGE_FLAGS_IOC_TO_HOST | | ||
2195 | MPI_SGE_FLAGS_END_OF_BUFFER; | ||
2196 | |||
2197 | flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; | ||
2198 | flagsLength |= blk_rq_bytes(rsp) + 4; | ||
1336 | dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio), | 2199 | dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio), |
1337 | rsp->data_len, PCI_DMA_BIDIRECTIONAL); | 2200 | blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); |
1338 | if (!dma_addr_in) | 2201 | if (!dma_addr_in) |
1339 | goto unmap; | 2202 | goto unmap; |
1340 | mpt_add_sge(psge, flagsLength, dma_addr_in); | 2203 | ioc->add_sge(psge, flagsLength, dma_addr_in); |
1341 | 2204 | ||
2205 | INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) | ||
1342 | mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); | 2206 | mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); |
1343 | 2207 | ||
1344 | timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); | 2208 | timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); |
@@ -1351,30 +2215,32 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
1351 | } | 2215 | } |
1352 | mf = NULL; | 2216 | mf = NULL; |
1353 | 2217 | ||
1354 | if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) { | 2218 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { |
1355 | SmpPassthroughReply_t *smprep; | 2219 | SmpPassthroughReply_t *smprep; |
1356 | 2220 | ||
1357 | smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; | 2221 | smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; |
1358 | memcpy(req->sense, smprep, sizeof(*smprep)); | 2222 | memcpy(req->sense, smprep, sizeof(*smprep)); |
1359 | req->sense_len = sizeof(*smprep); | 2223 | req->sense_len = sizeof(*smprep); |
1360 | req->data_len = 0; | 2224 | req->resid_len = 0; |
1361 | rsp->data_len -= smprep->ResponseDataLength; | 2225 | rsp->resid_len -= smprep->ResponseDataLength; |
1362 | } else { | 2226 | } else { |
1363 | printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", | 2227 | printk(MYIOC_s_ERR_FMT |
2228 | "%s: smp passthru reply failed to be returned\n", | ||
1364 | ioc->name, __func__); | 2229 | ioc->name, __func__); |
1365 | ret = -ENXIO; | 2230 | ret = -ENXIO; |
1366 | } | 2231 | } |
1367 | unmap: | 2232 | unmap: |
1368 | if (dma_addr_out) | 2233 | if (dma_addr_out) |
1369 | pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len, | 2234 | pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req), |
1370 | PCI_DMA_BIDIRECTIONAL); | 2235 | PCI_DMA_BIDIRECTIONAL); |
1371 | if (dma_addr_in) | 2236 | if (dma_addr_in) |
1372 | pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len, | 2237 | pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp), |
1373 | PCI_DMA_BIDIRECTIONAL); | 2238 | PCI_DMA_BIDIRECTIONAL); |
1374 | put_mf: | 2239 | put_mf: |
1375 | if (mf) | 2240 | if (mf) |
1376 | mpt_free_msg_frame(ioc, mf); | 2241 | mpt_free_msg_frame(ioc, mf); |
1377 | out_unlock: | 2242 | out_unlock: |
2243 | CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) | ||
1378 | mutex_unlock(&ioc->sas_mgmt.mutex); | 2244 | mutex_unlock(&ioc->sas_mgmt.mutex); |
1379 | out: | 2245 | out: |
1380 | return ret; | 2246 | return ret; |
@@ -1438,7 +2304,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) | |||
1438 | 2304 | ||
1439 | port_info->num_phys = buffer->NumPhys; | 2305 | port_info->num_phys = buffer->NumPhys; |
1440 | port_info->phy_info = kcalloc(port_info->num_phys, | 2306 | port_info->phy_info = kcalloc(port_info->num_phys, |
1441 | sizeof(*port_info->phy_info),GFP_KERNEL); | 2307 | sizeof(struct mptsas_phyinfo), GFP_KERNEL); |
1442 | if (!port_info->phy_info) { | 2308 | if (!port_info->phy_info) { |
1443 | error = -ENOMEM; | 2309 | error = -ENOMEM; |
1444 | goto out_free_consistent; | 2310 | goto out_free_consistent; |
@@ -1600,10 +2466,6 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, | |||
1600 | __le64 sas_address; | 2466 | __le64 sas_address; |
1601 | int error=0; | 2467 | int error=0; |
1602 | 2468 | ||
1603 | if (ioc->sas_discovery_runtime && | ||
1604 | mptsas_is_end_device(device_info)) | ||
1605 | goto out; | ||
1606 | |||
1607 | hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; | 2469 | hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; |
1608 | hdr.ExtPageLength = 0; | 2470 | hdr.ExtPageLength = 0; |
1609 | hdr.PageNumber = 0; | 2471 | hdr.PageNumber = 0; |
@@ -1644,6 +2506,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, | |||
1644 | 2506 | ||
1645 | mptsas_print_device_pg0(ioc, buffer); | 2507 | mptsas_print_device_pg0(ioc, buffer); |
1646 | 2508 | ||
2509 | memset(device_info, 0, sizeof(struct mptsas_devinfo)); | ||
1647 | device_info->handle = le16_to_cpu(buffer->DevHandle); | 2510 | device_info->handle = le16_to_cpu(buffer->DevHandle); |
1648 | device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); | 2511 | device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); |
1649 | device_info->handle_enclosure = | 2512 | device_info->handle_enclosure = |
@@ -1675,7 +2538,9 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, | |||
1675 | SasExpanderPage0_t *buffer; | 2538 | SasExpanderPage0_t *buffer; |
1676 | dma_addr_t dma_handle; | 2539 | dma_addr_t dma_handle; |
1677 | int i, error; | 2540 | int i, error; |
2541 | __le64 sas_address; | ||
1678 | 2542 | ||
2543 | memset(port_info, 0, sizeof(struct mptsas_portinfo)); | ||
1679 | hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; | 2544 | hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; |
1680 | hdr.ExtPageLength = 0; | 2545 | hdr.ExtPageLength = 0; |
1681 | hdr.PageNumber = 0; | 2546 | hdr.PageNumber = 0; |
@@ -1721,18 +2586,23 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, | |||
1721 | } | 2586 | } |
1722 | 2587 | ||
1723 | /* save config data */ | 2588 | /* save config data */ |
1724 | port_info->num_phys = buffer->NumPhys; | 2589 | port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1; |
1725 | port_info->phy_info = kcalloc(port_info->num_phys, | 2590 | port_info->phy_info = kcalloc(port_info->num_phys, |
1726 | sizeof(*port_info->phy_info),GFP_KERNEL); | 2591 | sizeof(struct mptsas_phyinfo), GFP_KERNEL); |
1727 | if (!port_info->phy_info) { | 2592 | if (!port_info->phy_info) { |
1728 | error = -ENOMEM; | 2593 | error = -ENOMEM; |
1729 | goto out_free_consistent; | 2594 | goto out_free_consistent; |
1730 | } | 2595 | } |
1731 | 2596 | ||
2597 | memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); | ||
1732 | for (i = 0; i < port_info->num_phys; i++) { | 2598 | for (i = 0; i < port_info->num_phys; i++) { |
1733 | port_info->phy_info[i].portinfo = port_info; | 2599 | port_info->phy_info[i].portinfo = port_info; |
1734 | port_info->phy_info[i].handle = | 2600 | port_info->phy_info[i].handle = |
1735 | le16_to_cpu(buffer->DevHandle); | 2601 | le16_to_cpu(buffer->DevHandle); |
2602 | port_info->phy_info[i].identify.sas_address = | ||
2603 | le64_to_cpu(sas_address); | ||
2604 | port_info->phy_info[i].identify.handle_parent = | ||
2605 | le16_to_cpu(buffer->ParentDevHandle); | ||
1736 | } | 2606 | } |
1737 | 2607 | ||
1738 | out_free_consistent: | 2608 | out_free_consistent: |
@@ -1752,11 +2622,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, | |||
1752 | dma_addr_t dma_handle; | 2622 | dma_addr_t dma_handle; |
1753 | int error=0; | 2623 | int error=0; |
1754 | 2624 | ||
1755 | if (ioc->sas_discovery_runtime && | 2625 | hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION; |
1756 | mptsas_is_end_device(&phy_info->attached)) | ||
1757 | goto out; | ||
1758 | |||
1759 | hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; | ||
1760 | hdr.ExtPageLength = 0; | 2626 | hdr.ExtPageLength = 0; |
1761 | hdr.PageNumber = 1; | 2627 | hdr.PageNumber = 1; |
1762 | hdr.Reserved1 = 0; | 2628 | hdr.Reserved1 = 0; |
@@ -1791,6 +2657,12 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, | |||
1791 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 2657 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
1792 | 2658 | ||
1793 | error = mpt_config(ioc, &cfg); | 2659 | error = mpt_config(ioc, &cfg); |
2660 | |||
2661 | if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { | ||
2662 | error = -ENODEV; | ||
2663 | goto out; | ||
2664 | } | ||
2665 | |||
1794 | if (error) | 2666 | if (error) |
1795 | goto out_free_consistent; | 2667 | goto out_free_consistent; |
1796 | 2668 | ||
@@ -2010,16 +2882,21 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
2010 | goto out; | 2882 | goto out; |
2011 | } | 2883 | } |
2012 | mptsas_set_port(ioc, phy_info, port); | 2884 | mptsas_set_port(ioc, phy_info, port); |
2013 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 2885 | devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev, |
2014 | "sas_port_alloc: port=%p dev=%p port_id=%d\n", | 2886 | MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n", |
2015 | ioc->name, port, dev, port->port_identifier)); | 2887 | ioc->name, port->port_identifier, |
2888 | (unsigned long long)phy_info-> | ||
2889 | attached.sas_address)); | ||
2016 | } | 2890 | } |
2017 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n", | 2891 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
2018 | ioc->name, phy_info->phy_id)); | 2892 | "sas_port_add_phy: phy_id=%d\n", |
2893 | ioc->name, phy_info->phy_id)); | ||
2019 | sas_port_add_phy(port, phy_info->phy); | 2894 | sas_port_add_phy(port, phy_info->phy); |
2020 | phy_info->sas_port_add_phy = 0; | 2895 | phy_info->sas_port_add_phy = 0; |
2896 | devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev, | ||
2897 | MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name, | ||
2898 | phy_info->phy_id, phy_info->phy)); | ||
2021 | } | 2899 | } |
2022 | |||
2023 | if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { | 2900 | if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { |
2024 | 2901 | ||
2025 | struct sas_rphy *rphy; | 2902 | struct sas_rphy *rphy; |
@@ -2032,18 +2909,17 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
2032 | * the adding/removing of devices that occur | 2909 | * the adding/removing of devices that occur |
2033 | * after start of day. | 2910 | * after start of day. |
2034 | */ | 2911 | */ |
2035 | if (ioc->sas_discovery_runtime && | 2912 | if (mptsas_is_end_device(&phy_info->attached) && |
2036 | mptsas_is_end_device(&phy_info->attached)) | 2913 | phy_info->attached.handle_parent) { |
2037 | goto out; | 2914 | goto out; |
2915 | } | ||
2038 | 2916 | ||
2039 | mptsas_parse_device_info(&identify, &phy_info->attached); | 2917 | mptsas_parse_device_info(&identify, &phy_info->attached); |
2040 | if (scsi_is_host_device(parent)) { | 2918 | if (scsi_is_host_device(parent)) { |
2041 | struct mptsas_portinfo *port_info; | 2919 | struct mptsas_portinfo *port_info; |
2042 | int i; | 2920 | int i; |
2043 | 2921 | ||
2044 | mutex_lock(&ioc->sas_topology_mutex); | 2922 | port_info = ioc->hba_port_info; |
2045 | port_info = mptsas_get_hba_portinfo(ioc); | ||
2046 | mutex_unlock(&ioc->sas_topology_mutex); | ||
2047 | 2923 | ||
2048 | for (i = 0; i < port_info->num_phys; i++) | 2924 | for (i = 0; i < port_info->num_phys; i++) |
2049 | if (port_info->phy_info[i].identify.sas_address == | 2925 | if (port_info->phy_info[i].identify.sas_address == |
@@ -2102,7 +2978,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) | |||
2102 | struct mptsas_portinfo *port_info, *hba; | 2978 | struct mptsas_portinfo *port_info, *hba; |
2103 | int error = -ENOMEM, i; | 2979 | int error = -ENOMEM, i; |
2104 | 2980 | ||
2105 | hba = kzalloc(sizeof(*port_info), GFP_KERNEL); | 2981 | hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); |
2106 | if (! hba) | 2982 | if (! hba) |
2107 | goto out; | 2983 | goto out; |
2108 | 2984 | ||
@@ -2112,9 +2988,10 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) | |||
2112 | 2988 | ||
2113 | mptsas_sas_io_unit_pg1(ioc); | 2989 | mptsas_sas_io_unit_pg1(ioc); |
2114 | mutex_lock(&ioc->sas_topology_mutex); | 2990 | mutex_lock(&ioc->sas_topology_mutex); |
2115 | port_info = mptsas_get_hba_portinfo(ioc); | 2991 | port_info = ioc->hba_port_info; |
2116 | if (!port_info) { | 2992 | if (!port_info) { |
2117 | port_info = hba; | 2993 | ioc->hba_port_info = port_info = hba; |
2994 | ioc->hba_port_num_phy = port_info->num_phys; | ||
2118 | list_add_tail(&port_info->list, &ioc->sas_topology); | 2995 | list_add_tail(&port_info->list, &ioc->sas_topology); |
2119 | } else { | 2996 | } else { |
2120 | for (i = 0; i < hba->num_phys; i++) { | 2997 | for (i = 0; i < hba->num_phys; i++) { |
@@ -2130,15 +3007,22 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) | |||
2130 | hba = NULL; | 3007 | hba = NULL; |
2131 | } | 3008 | } |
2132 | mutex_unlock(&ioc->sas_topology_mutex); | 3009 | mutex_unlock(&ioc->sas_topology_mutex); |
3010 | #if defined(CPQ_CIM) | ||
3011 | ioc->num_ports = port_info->num_phys; | ||
3012 | #endif | ||
2133 | for (i = 0; i < port_info->num_phys; i++) { | 3013 | for (i = 0; i < port_info->num_phys; i++) { |
2134 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], | 3014 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], |
2135 | (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << | 3015 | (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << |
2136 | MPI_SAS_PHY_PGAD_FORM_SHIFT), i); | 3016 | MPI_SAS_PHY_PGAD_FORM_SHIFT), i); |
2137 | 3017 | port_info->phy_info[i].identify.handle = | |
3018 | port_info->phy_info[i].handle; | ||
2138 | mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, | 3019 | mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, |
2139 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | 3020 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
2140 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 3021 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
2141 | port_info->phy_info[i].handle); | 3022 | port_info->phy_info[i].identify.handle); |
3023 | if (!ioc->hba_port_sas_addr) | ||
3024 | ioc->hba_port_sas_addr = | ||
3025 | port_info->phy_info[i].identify.sas_address; | ||
2142 | port_info->phy_info[i].identify.phy_id = | 3026 | port_info->phy_info[i].identify.phy_id = |
2143 | port_info->phy_info[i].phy_id = i; | 3027 | port_info->phy_info[i].phy_id = i; |
2144 | if (port_info->phy_info[i].attached.handle) | 3028 | if (port_info->phy_info[i].attached.handle) |
@@ -2163,248 +3047,721 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) | |||
2163 | return error; | 3047 | return error; |
2164 | } | 3048 | } |
2165 | 3049 | ||
2166 | static int | 3050 | static void |
2167 | mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) | 3051 | mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) |
2168 | { | 3052 | { |
2169 | struct mptsas_portinfo *port_info, *p, *ex; | 3053 | struct mptsas_portinfo *parent; |
2170 | struct device *parent; | 3054 | struct device *parent_dev; |
2171 | struct sas_rphy *rphy; | 3055 | struct sas_rphy *rphy; |
2172 | int error = -ENOMEM, i, j; | 3056 | int i; |
2173 | 3057 | u64 sas_address; /* expander sas address */ | |
2174 | ex = kzalloc(sizeof(*port_info), GFP_KERNEL); | 3058 | u32 handle; |
2175 | if (!ex) | 3059 | |
2176 | goto out; | 3060 | handle = port_info->phy_info[0].handle; |
2177 | 3061 | sas_address = port_info->phy_info[0].identify.sas_address; | |
2178 | error = mptsas_sas_expander_pg0(ioc, ex, | ||
2179 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << | ||
2180 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); | ||
2181 | if (error) | ||
2182 | goto out_free_port_info; | ||
2183 | |||
2184 | *handle = ex->phy_info[0].handle; | ||
2185 | |||
2186 | mutex_lock(&ioc->sas_topology_mutex); | ||
2187 | port_info = mptsas_find_portinfo_by_handle(ioc, *handle); | ||
2188 | if (!port_info) { | ||
2189 | port_info = ex; | ||
2190 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
2191 | } else { | ||
2192 | for (i = 0; i < ex->num_phys; i++) { | ||
2193 | port_info->phy_info[i].handle = | ||
2194 | ex->phy_info[i].handle; | ||
2195 | port_info->phy_info[i].port_id = | ||
2196 | ex->phy_info[i].port_id; | ||
2197 | } | ||
2198 | kfree(ex->phy_info); | ||
2199 | kfree(ex); | ||
2200 | ex = NULL; | ||
2201 | } | ||
2202 | mutex_unlock(&ioc->sas_topology_mutex); | ||
2203 | |||
2204 | for (i = 0; i < port_info->num_phys; i++) { | 3062 | for (i = 0; i < port_info->num_phys; i++) { |
2205 | mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], | 3063 | mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], |
2206 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << | 3064 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << |
2207 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle); | 3065 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle); |
2208 | 3066 | ||
2209 | if (port_info->phy_info[i].identify.handle) { | 3067 | mptsas_sas_device_pg0(ioc, |
2210 | mptsas_sas_device_pg0(ioc, | 3068 | &port_info->phy_info[i].identify, |
2211 | &port_info->phy_info[i].identify, | 3069 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
2212 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | 3070 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
2213 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 3071 | port_info->phy_info[i].identify.handle); |
2214 | port_info->phy_info[i].identify.handle); | 3072 | port_info->phy_info[i].identify.phy_id = |
2215 | port_info->phy_info[i].identify.phy_id = | 3073 | port_info->phy_info[i].phy_id; |
2216 | port_info->phy_info[i].phy_id; | ||
2217 | } | ||
2218 | 3074 | ||
2219 | if (port_info->phy_info[i].attached.handle) { | 3075 | if (port_info->phy_info[i].attached.handle) { |
2220 | mptsas_sas_device_pg0(ioc, | 3076 | mptsas_sas_device_pg0(ioc, |
2221 | &port_info->phy_info[i].attached, | 3077 | &port_info->phy_info[i].attached, |
2222 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | 3078 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
2223 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 3079 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
2224 | port_info->phy_info[i].attached.handle); | 3080 | port_info->phy_info[i].attached.handle); |
2225 | port_info->phy_info[i].attached.phy_id = | 3081 | port_info->phy_info[i].attached.phy_id = |
2226 | port_info->phy_info[i].phy_id; | 3082 | port_info->phy_info[i].phy_id; |
2227 | } | 3083 | } |
2228 | } | 3084 | } |
2229 | 3085 | ||
2230 | parent = &ioc->sh->shost_gendev; | 3086 | mutex_lock(&ioc->sas_topology_mutex); |
2231 | for (i = 0; i < port_info->num_phys; i++) { | 3087 | parent = mptsas_find_portinfo_by_handle(ioc, |
2232 | mutex_lock(&ioc->sas_topology_mutex); | 3088 | port_info->phy_info[0].identify.handle_parent); |
2233 | list_for_each_entry(p, &ioc->sas_topology, list) { | 3089 | if (!parent) { |
2234 | for (j = 0; j < p->num_phys; j++) { | ||
2235 | if (port_info->phy_info[i].identify.handle != | ||
2236 | p->phy_info[j].attached.handle) | ||
2237 | continue; | ||
2238 | rphy = mptsas_get_rphy(&p->phy_info[j]); | ||
2239 | parent = &rphy->dev; | ||
2240 | } | ||
2241 | } | ||
2242 | mutex_unlock(&ioc->sas_topology_mutex); | 3090 | mutex_unlock(&ioc->sas_topology_mutex); |
3091 | return; | ||
2243 | } | 3092 | } |
3093 | for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev; | ||
3094 | i++) { | ||
3095 | if (parent->phy_info[i].attached.sas_address == sas_address) { | ||
3096 | rphy = mptsas_get_rphy(&parent->phy_info[i]); | ||
3097 | parent_dev = &rphy->dev; | ||
3098 | } | ||
3099 | } | ||
3100 | mutex_unlock(&ioc->sas_topology_mutex); | ||
2244 | 3101 | ||
2245 | mptsas_setup_wide_ports(ioc, port_info); | 3102 | mptsas_setup_wide_ports(ioc, port_info); |
2246 | |||
2247 | for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) | 3103 | for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) |
2248 | mptsas_probe_one_phy(parent, &port_info->phy_info[i], | 3104 | mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i], |
2249 | ioc->sas_index, 0); | 3105 | ioc->sas_index, 0); |
3106 | } | ||
2250 | 3107 | ||
2251 | return 0; | 3108 | static void |
3109 | mptsas_expander_event_add(MPT_ADAPTER *ioc, | ||
3110 | MpiEventDataSasExpanderStatusChange_t *expander_data) | ||
3111 | { | ||
3112 | struct mptsas_portinfo *port_info; | ||
3113 | int i; | ||
3114 | __le64 sas_address; | ||
2252 | 3115 | ||
2253 | out_free_port_info: | 3116 | port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); |
2254 | if (ex) { | 3117 | if (!port_info) |
2255 | kfree(ex->phy_info); | 3118 | BUG(); |
2256 | kfree(ex); | 3119 | port_info->num_phys = (expander_data->NumPhys) ? |
3120 | expander_data->NumPhys : 1; | ||
3121 | port_info->phy_info = kcalloc(port_info->num_phys, | ||
3122 | sizeof(struct mptsas_phyinfo), GFP_KERNEL); | ||
3123 | if (!port_info->phy_info) | ||
3124 | BUG(); | ||
3125 | memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); | ||
3126 | for (i = 0; i < port_info->num_phys; i++) { | ||
3127 | port_info->phy_info[i].portinfo = port_info; | ||
3128 | port_info->phy_info[i].handle = | ||
3129 | le16_to_cpu(expander_data->DevHandle); | ||
3130 | port_info->phy_info[i].identify.sas_address = | ||
3131 | le64_to_cpu(sas_address); | ||
3132 | port_info->phy_info[i].identify.handle_parent = | ||
3133 | le16_to_cpu(expander_data->ParentDevHandle); | ||
3134 | } | ||
3135 | |||
3136 | mutex_lock(&ioc->sas_topology_mutex); | ||
3137 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
3138 | mutex_unlock(&ioc->sas_topology_mutex); | ||
3139 | |||
3140 | printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " | ||
3141 | "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, | ||
3142 | (unsigned long long)sas_address); | ||
3143 | |||
3144 | mptsas_expander_refresh(ioc, port_info); | ||
3145 | } | ||
3146 | |||
3147 | /** | ||
3148 | * mptsas_delete_expander_siblings - remove siblings attached to expander | ||
3149 | * @ioc: Pointer to MPT_ADAPTER structure | ||
3150 | * @parent: the parent port_info object | ||
3151 | * @expander: the expander port_info object | ||
3152 | **/ | ||
3153 | static void | ||
3154 | mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo | ||
3155 | *parent, struct mptsas_portinfo *expander) | ||
3156 | { | ||
3157 | struct mptsas_phyinfo *phy_info; | ||
3158 | struct mptsas_portinfo *port_info; | ||
3159 | struct sas_rphy *rphy; | ||
3160 | int i; | ||
3161 | |||
3162 | phy_info = expander->phy_info; | ||
3163 | for (i = 0; i < expander->num_phys; i++, phy_info++) { | ||
3164 | rphy = mptsas_get_rphy(phy_info); | ||
3165 | if (!rphy) | ||
3166 | continue; | ||
3167 | if (rphy->identify.device_type == SAS_END_DEVICE) | ||
3168 | mptsas_del_end_device(ioc, phy_info); | ||
3169 | } | ||
3170 | |||
3171 | phy_info = expander->phy_info; | ||
3172 | for (i = 0; i < expander->num_phys; i++, phy_info++) { | ||
3173 | rphy = mptsas_get_rphy(phy_info); | ||
3174 | if (!rphy) | ||
3175 | continue; | ||
3176 | if (rphy->identify.device_type == | ||
3177 | MPI_SAS_DEVICE_INFO_EDGE_EXPANDER || | ||
3178 | rphy->identify.device_type == | ||
3179 | MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) { | ||
3180 | port_info = mptsas_find_portinfo_by_sas_address(ioc, | ||
3181 | rphy->identify.sas_address); | ||
3182 | if (!port_info) | ||
3183 | continue; | ||
3184 | if (port_info == parent) /* backlink rphy */ | ||
3185 | continue; | ||
3186 | /* | ||
3187 | Delete this expander even if the expdevpage is exists | ||
3188 | because the parent expander is already deleted | ||
3189 | */ | ||
3190 | mptsas_expander_delete(ioc, port_info, 1); | ||
3191 | } | ||
3192 | } | ||
3193 | } | ||
3194 | |||
3195 | |||
3196 | /** | ||
3197 | * mptsas_expander_delete - remove this expander | ||
3198 | * @ioc: Pointer to MPT_ADAPTER structure | ||
3199 | * @port_info: expander port_info struct | ||
3200 | * @force: Flag to forcefully delete the expander | ||
3201 | * | ||
3202 | **/ | ||
3203 | |||
3204 | static void mptsas_expander_delete(MPT_ADAPTER *ioc, | ||
3205 | struct mptsas_portinfo *port_info, u8 force) | ||
3206 | { | ||
3207 | |||
3208 | struct mptsas_portinfo *parent; | ||
3209 | int i; | ||
3210 | u64 expander_sas_address; | ||
3211 | struct mptsas_phyinfo *phy_info; | ||
3212 | struct mptsas_portinfo buffer; | ||
3213 | struct mptsas_portinfo_details *port_details; | ||
3214 | struct sas_port *port; | ||
3215 | |||
3216 | if (!port_info) | ||
3217 | return; | ||
3218 | |||
3219 | /* see if expander is still there before deleting */ | ||
3220 | mptsas_sas_expander_pg0(ioc, &buffer, | ||
3221 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << | ||
3222 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), | ||
3223 | port_info->phy_info[0].identify.handle); | ||
3224 | |||
3225 | if (buffer.num_phys) { | ||
3226 | kfree(buffer.phy_info); | ||
3227 | if (!force) | ||
3228 | return; | ||
3229 | } | ||
3230 | |||
3231 | |||
3232 | /* | ||
3233 | * Obtain the port_info instance to the parent port | ||
3234 | */ | ||
3235 | port_details = NULL; | ||
3236 | expander_sas_address = | ||
3237 | port_info->phy_info[0].identify.sas_address; | ||
3238 | parent = mptsas_find_portinfo_by_handle(ioc, | ||
3239 | port_info->phy_info[0].identify.handle_parent); | ||
3240 | mptsas_delete_expander_siblings(ioc, parent, port_info); | ||
3241 | if (!parent) | ||
3242 | goto out; | ||
3243 | |||
3244 | /* | ||
3245 | * Delete rphys in the parent that point | ||
3246 | * to this expander. | ||
3247 | */ | ||
3248 | phy_info = parent->phy_info; | ||
3249 | port = NULL; | ||
3250 | for (i = 0; i < parent->num_phys; i++, phy_info++) { | ||
3251 | if (!phy_info->phy) | ||
3252 | continue; | ||
3253 | if (phy_info->attached.sas_address != | ||
3254 | expander_sas_address) | ||
3255 | continue; | ||
3256 | if (!port) { | ||
3257 | port = mptsas_get_port(phy_info); | ||
3258 | port_details = phy_info->port_details; | ||
3259 | } | ||
3260 | dev_printk(KERN_DEBUG, &phy_info->phy->dev, | ||
3261 | MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, | ||
3262 | phy_info->phy_id, phy_info->phy); | ||
3263 | sas_port_delete_phy(port, phy_info->phy); | ||
3264 | } | ||
3265 | if (port) { | ||
3266 | dev_printk(KERN_DEBUG, &port->dev, | ||
3267 | MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n", | ||
3268 | ioc->name, port->port_identifier, | ||
3269 | (unsigned long long)expander_sas_address); | ||
3270 | sas_port_delete(port); | ||
3271 | mptsas_port_delete(ioc, port_details); | ||
2257 | } | 3272 | } |
2258 | out: | 3273 | out: |
2259 | return error; | 3274 | |
3275 | printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, " | ||
3276 | "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, | ||
3277 | (unsigned long long)expander_sas_address); | ||
3278 | |||
3279 | /* | ||
3280 | * free link | ||
3281 | */ | ||
3282 | list_del(&port_info->list); | ||
3283 | kfree(port_info->phy_info); | ||
3284 | kfree(port_info); | ||
2260 | } | 3285 | } |
2261 | 3286 | ||
2262 | /* | 3287 | |
2263 | * mptsas_delete_expander_phys | 3288 | /** |
3289 | * mptsas_send_expander_event - expanders events | ||
3290 | * @ioc: Pointer to MPT_ADAPTER structure | ||
3291 | * @expander_data: event data | ||
2264 | * | 3292 | * |
2265 | * | 3293 | * |
2266 | * This will traverse topology, and remove expanders | 3294 | * This function handles adding, removing, and refreshing |
2267 | * that are no longer present | 3295 | * device handles within the expander objects. |
2268 | */ | 3296 | */ |
2269 | static void | 3297 | static void |
2270 | mptsas_delete_expander_phys(MPT_ADAPTER *ioc) | 3298 | mptsas_send_expander_event(struct fw_event_work *fw_event) |
2271 | { | 3299 | { |
2272 | struct mptsas_portinfo buffer; | 3300 | MPT_ADAPTER *ioc; |
2273 | struct mptsas_portinfo *port_info, *n, *parent; | 3301 | MpiEventDataSasExpanderStatusChange_t *expander_data; |
2274 | struct mptsas_phyinfo *phy_info; | 3302 | struct mptsas_portinfo *port_info; |
2275 | struct sas_port * port; | 3303 | __le64 sas_address; |
2276 | int i; | 3304 | int i; |
2277 | u64 expander_sas_address; | ||
2278 | 3305 | ||
3306 | ioc = fw_event->ioc; | ||
3307 | expander_data = (MpiEventDataSasExpanderStatusChange_t *) | ||
3308 | fw_event->event_data; | ||
3309 | memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); | ||
3310 | port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); | ||
3311 | |||
3312 | if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { | ||
3313 | if (port_info) { | ||
3314 | for (i = 0; i < port_info->num_phys; i++) { | ||
3315 | port_info->phy_info[i].portinfo = port_info; | ||
3316 | port_info->phy_info[i].handle = | ||
3317 | le16_to_cpu(expander_data->DevHandle); | ||
3318 | port_info->phy_info[i].identify.sas_address = | ||
3319 | le64_to_cpu(sas_address); | ||
3320 | port_info->phy_info[i].identify.handle_parent = | ||
3321 | le16_to_cpu(expander_data->ParentDevHandle); | ||
3322 | } | ||
3323 | mptsas_expander_refresh(ioc, port_info); | ||
3324 | } else if (!port_info && expander_data->NumPhys) | ||
3325 | mptsas_expander_event_add(ioc, expander_data); | ||
3326 | } else if (expander_data->ReasonCode == | ||
3327 | MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) | ||
3328 | mptsas_expander_delete(ioc, port_info, 0); | ||
3329 | |||
3330 | mptsas_free_fw_event(ioc, fw_event); | ||
3331 | } | ||
3332 | |||
3333 | |||
3334 | /** | ||
3335 | * mptsas_expander_add - | ||
3336 | * @ioc: Pointer to MPT_ADAPTER structure | ||
3337 | * @handle: | ||
3338 | * | ||
3339 | */ | ||
3340 | struct mptsas_portinfo * | ||
3341 | mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle) | ||
3342 | { | ||
3343 | struct mptsas_portinfo buffer, *port_info; | ||
3344 | int i; | ||
3345 | |||
3346 | if ((mptsas_sas_expander_pg0(ioc, &buffer, | ||
3347 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << | ||
3348 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle))) | ||
3349 | return NULL; | ||
3350 | |||
3351 | port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC); | ||
3352 | if (!port_info) { | ||
3353 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
3354 | "%s: exit at line=%d\n", ioc->name, | ||
3355 | __func__, __LINE__)); | ||
3356 | return NULL; | ||
3357 | } | ||
3358 | port_info->num_phys = buffer.num_phys; | ||
3359 | port_info->phy_info = buffer.phy_info; | ||
3360 | for (i = 0; i < port_info->num_phys; i++) | ||
3361 | port_info->phy_info[i].portinfo = port_info; | ||
2279 | mutex_lock(&ioc->sas_topology_mutex); | 3362 | mutex_lock(&ioc->sas_topology_mutex); |
2280 | list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { | 3363 | list_add_tail(&port_info->list, &ioc->sas_topology); |
3364 | mutex_unlock(&ioc->sas_topology_mutex); | ||
3365 | printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " | ||
3366 | "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, | ||
3367 | (unsigned long long)buffer.phy_info[0].identify.sas_address); | ||
3368 | mptsas_expander_refresh(ioc, port_info); | ||
3369 | return port_info; | ||
3370 | } | ||
2281 | 3371 | ||
2282 | if (!(port_info->phy_info[0].identify.device_info & | 3372 | static void |
2283 | MPI_SAS_DEVICE_INFO_SMP_TARGET)) | 3373 | mptsas_send_link_status_event(struct fw_event_work *fw_event) |
3374 | { | ||
3375 | MPT_ADAPTER *ioc; | ||
3376 | MpiEventDataSasPhyLinkStatus_t *link_data; | ||
3377 | struct mptsas_portinfo *port_info; | ||
3378 | struct mptsas_phyinfo *phy_info = NULL; | ||
3379 | __le64 sas_address; | ||
3380 | u8 phy_num; | ||
3381 | u8 link_rate; | ||
3382 | |||
3383 | ioc = fw_event->ioc; | ||
3384 | link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data; | ||
3385 | |||
3386 | memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64)); | ||
3387 | sas_address = le64_to_cpu(sas_address); | ||
3388 | link_rate = link_data->LinkRates >> 4; | ||
3389 | phy_num = link_data->PhyNum; | ||
3390 | |||
3391 | port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); | ||
3392 | if (port_info) { | ||
3393 | phy_info = &port_info->phy_info[phy_num]; | ||
3394 | if (phy_info) | ||
3395 | phy_info->negotiated_link_rate = link_rate; | ||
3396 | } | ||
3397 | |||
3398 | if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 || | ||
3399 | link_rate == MPI_SAS_IOUNIT0_RATE_3_0) { | ||
3400 | |||
3401 | if (!port_info) { | ||
3402 | if (ioc->old_sas_discovery_protocal) { | ||
3403 | port_info = mptsas_expander_add(ioc, | ||
3404 | le16_to_cpu(link_data->DevHandle)); | ||
3405 | if (port_info) | ||
3406 | goto out; | ||
3407 | } | ||
3408 | goto out; | ||
3409 | } | ||
3410 | |||
3411 | if (port_info == ioc->hba_port_info) | ||
3412 | mptsas_probe_hba_phys(ioc); | ||
3413 | else | ||
3414 | mptsas_expander_refresh(ioc, port_info); | ||
3415 | } else if (phy_info && phy_info->phy) { | ||
3416 | if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED) | ||
3417 | phy_info->phy->negotiated_linkrate = | ||
3418 | SAS_PHY_DISABLED; | ||
3419 | else if (link_rate == | ||
3420 | MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION) | ||
3421 | phy_info->phy->negotiated_linkrate = | ||
3422 | SAS_LINK_RATE_FAILED; | ||
3423 | else | ||
3424 | phy_info->phy->negotiated_linkrate = | ||
3425 | SAS_LINK_RATE_UNKNOWN; | ||
3426 | } | ||
3427 | out: | ||
3428 | mptsas_free_fw_event(ioc, fw_event); | ||
3429 | } | ||
3430 | |||
3431 | static void | ||
3432 | mptsas_not_responding_devices(MPT_ADAPTER *ioc) | ||
3433 | { | ||
3434 | struct mptsas_portinfo buffer, *port_info; | ||
3435 | struct mptsas_device_info *sas_info; | ||
3436 | struct mptsas_devinfo sas_device; | ||
3437 | u32 handle; | ||
3438 | VirtTarget *vtarget = NULL; | ||
3439 | struct mptsas_phyinfo *phy_info; | ||
3440 | u8 found_expander; | ||
3441 | int retval, retry_count; | ||
3442 | unsigned long flags; | ||
3443 | |||
3444 | mpt_findImVolumes(ioc); | ||
3445 | |||
3446 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | ||
3447 | if (ioc->ioc_reset_in_progress) { | ||
3448 | dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
3449 | "%s: exiting due to a parallel reset \n", ioc->name, | ||
3450 | __func__)); | ||
3451 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | ||
3452 | return; | ||
3453 | } | ||
3454 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | ||
3455 | |||
3456 | /* devices, logical volumes */ | ||
3457 | mutex_lock(&ioc->sas_device_info_mutex); | ||
3458 | redo_device_scan: | ||
3459 | list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) { | ||
3460 | if (sas_info->is_cached) | ||
2284 | continue; | 3461 | continue; |
3462 | if (!sas_info->is_logical_volume) { | ||
3463 | sas_device.handle = 0; | ||
3464 | retry_count = 0; | ||
3465 | retry_page: | ||
3466 | retval = mptsas_sas_device_pg0(ioc, &sas_device, | ||
3467 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID | ||
3468 | << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | ||
3469 | (sas_info->fw.channel << 8) + | ||
3470 | sas_info->fw.id); | ||
3471 | |||
3472 | if (sas_device.handle) | ||
3473 | continue; | ||
3474 | if (retval == -EBUSY) { | ||
3475 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | ||
3476 | if (ioc->ioc_reset_in_progress) { | ||
3477 | dfailprintk(ioc, | ||
3478 | printk(MYIOC_s_DEBUG_FMT | ||
3479 | "%s: exiting due to reset\n", | ||
3480 | ioc->name, __func__)); | ||
3481 | spin_unlock_irqrestore | ||
3482 | (&ioc->taskmgmt_lock, flags); | ||
3483 | mutex_unlock(&ioc-> | ||
3484 | sas_device_info_mutex); | ||
3485 | return; | ||
3486 | } | ||
3487 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, | ||
3488 | flags); | ||
3489 | } | ||
2285 | 3490 | ||
2286 | if (mptsas_sas_expander_pg0(ioc, &buffer, | 3491 | if (retval && (retval != -ENODEV)) { |
2287 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << | 3492 | if (retry_count < 10) { |
2288 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), | 3493 | retry_count++; |
2289 | port_info->phy_info[0].handle)) { | 3494 | goto retry_page; |
3495 | } else { | ||
3496 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
3497 | "%s: Config page retry exceeded retry " | ||
3498 | "count deleting device 0x%llx\n", | ||
3499 | ioc->name, __func__, | ||
3500 | sas_info->sas_address)); | ||
3501 | } | ||
3502 | } | ||
2290 | 3503 | ||
2291 | /* | 3504 | /* delete device */ |
2292 | * Obtain the port_info instance to the parent port | 3505 | vtarget = mptsas_find_vtarget(ioc, |
2293 | */ | 3506 | sas_info->fw.channel, sas_info->fw.id); |
2294 | parent = mptsas_find_portinfo_by_handle(ioc, | ||
2295 | port_info->phy_info[0].identify.handle_parent); | ||
2296 | 3507 | ||
2297 | if (!parent) | 3508 | if (vtarget) |
2298 | goto next_port; | 3509 | vtarget->deleted = 1; |
2299 | 3510 | ||
2300 | expander_sas_address = | 3511 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
2301 | port_info->phy_info[0].identify.sas_address; | 3512 | sas_info->sas_address); |
2302 | 3513 | ||
2303 | /* | 3514 | if (phy_info) { |
2304 | * Delete rphys in the parent that point | 3515 | mptsas_del_end_device(ioc, phy_info); |
2305 | * to this expander. The transport layer will | 3516 | goto redo_device_scan; |
2306 | * cleanup all the children. | ||
2307 | */ | ||
2308 | phy_info = parent->phy_info; | ||
2309 | for (i = 0; i < parent->num_phys; i++, phy_info++) { | ||
2310 | port = mptsas_get_port(phy_info); | ||
2311 | if (!port) | ||
2312 | continue; | ||
2313 | if (phy_info->attached.sas_address != | ||
2314 | expander_sas_address) | ||
2315 | continue; | ||
2316 | dsaswideprintk(ioc, | ||
2317 | dev_printk(KERN_DEBUG, &port->dev, | ||
2318 | MYIOC_s_FMT "delete port (%d)\n", ioc->name, | ||
2319 | port->port_identifier)); | ||
2320 | sas_port_delete(port); | ||
2321 | mptsas_port_delete(ioc, phy_info->port_details); | ||
2322 | } | 3517 | } |
2323 | next_port: | 3518 | } else |
3519 | mptsas_volume_delete(ioc, sas_info->fw.id); | ||
3520 | } | ||
3521 | mutex_lock(&ioc->sas_device_info_mutex); | ||
2324 | 3522 | ||
2325 | phy_info = port_info->phy_info; | 3523 | /* expanders */ |
2326 | for (i = 0; i < port_info->num_phys; i++, phy_info++) | 3524 | mutex_lock(&ioc->sas_topology_mutex); |
2327 | mptsas_port_delete(ioc, phy_info->port_details); | 3525 | redo_expander_scan: |
3526 | list_for_each_entry(port_info, &ioc->sas_topology, list) { | ||
2328 | 3527 | ||
2329 | list_del(&port_info->list); | 3528 | if (port_info->phy_info && |
2330 | kfree(port_info->phy_info); | 3529 | (!(port_info->phy_info[0].identify.device_info & |
2331 | kfree(port_info); | 3530 | MPI_SAS_DEVICE_INFO_SMP_TARGET))) |
3531 | continue; | ||
3532 | found_expander = 0; | ||
3533 | handle = 0xFFFF; | ||
3534 | while (!mptsas_sas_expander_pg0(ioc, &buffer, | ||
3535 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << | ||
3536 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) && | ||
3537 | !found_expander) { | ||
3538 | |||
3539 | handle = buffer.phy_info[0].handle; | ||
3540 | if (buffer.phy_info[0].identify.sas_address == | ||
3541 | port_info->phy_info[0].identify.sas_address) { | ||
3542 | found_expander = 1; | ||
3543 | } | ||
3544 | kfree(buffer.phy_info); | ||
3545 | } | ||
3546 | |||
3547 | if (!found_expander) { | ||
3548 | mptsas_expander_delete(ioc, port_info, 0); | ||
3549 | goto redo_expander_scan; | ||
2332 | } | 3550 | } |
2333 | /* | ||
2334 | * Free this memory allocated from inside | ||
2335 | * mptsas_sas_expander_pg0 | ||
2336 | */ | ||
2337 | kfree(buffer.phy_info); | ||
2338 | } | 3551 | } |
2339 | mutex_unlock(&ioc->sas_topology_mutex); | 3552 | mutex_lock(&ioc->sas_topology_mutex); |
3553 | } | ||
3554 | |||
3555 | /** | ||
3556 | * mptsas_probe_expanders - adding expanders | ||
3557 | * @ioc: Pointer to MPT_ADAPTER structure | ||
3558 | * | ||
3559 | **/ | ||
3560 | static void | ||
3561 | mptsas_probe_expanders(MPT_ADAPTER *ioc) | ||
3562 | { | ||
3563 | struct mptsas_portinfo buffer, *port_info; | ||
3564 | u32 handle; | ||
3565 | int i; | ||
3566 | |||
3567 | handle = 0xFFFF; | ||
3568 | while (!mptsas_sas_expander_pg0(ioc, &buffer, | ||
3569 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << | ||
3570 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) { | ||
3571 | |||
3572 | handle = buffer.phy_info[0].handle; | ||
3573 | port_info = mptsas_find_portinfo_by_sas_address(ioc, | ||
3574 | buffer.phy_info[0].identify.sas_address); | ||
3575 | |||
3576 | if (port_info) { | ||
3577 | /* refreshing handles */ | ||
3578 | for (i = 0; i < buffer.num_phys; i++) { | ||
3579 | port_info->phy_info[i].handle = handle; | ||
3580 | port_info->phy_info[i].identify.handle_parent = | ||
3581 | buffer.phy_info[0].identify.handle_parent; | ||
3582 | } | ||
3583 | mptsas_expander_refresh(ioc, port_info); | ||
3584 | kfree(buffer.phy_info); | ||
3585 | continue; | ||
3586 | } | ||
3587 | |||
3588 | port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); | ||
3589 | if (!port_info) { | ||
3590 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
3591 | "%s: exit at line=%d\n", ioc->name, | ||
3592 | __func__, __LINE__)); | ||
3593 | return; | ||
3594 | } | ||
3595 | port_info->num_phys = buffer.num_phys; | ||
3596 | port_info->phy_info = buffer.phy_info; | ||
3597 | for (i = 0; i < port_info->num_phys; i++) | ||
3598 | port_info->phy_info[i].portinfo = port_info; | ||
3599 | mutex_lock(&ioc->sas_topology_mutex); | ||
3600 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
3601 | mutex_unlock(&ioc->sas_topology_mutex); | ||
3602 | printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " | ||
3603 | "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, | ||
3604 | (unsigned long long)buffer.phy_info[0].identify.sas_address); | ||
3605 | mptsas_expander_refresh(ioc, port_info); | ||
3606 | } | ||
2340 | } | 3607 | } |
2341 | 3608 | ||
2342 | /* | 3609 | static void |
2343 | * Start of day discovery | 3610 | mptsas_probe_devices(MPT_ADAPTER *ioc) |
2344 | */ | 3611 | { |
3612 | u16 handle; | ||
3613 | struct mptsas_devinfo sas_device; | ||
3614 | struct mptsas_phyinfo *phy_info; | ||
3615 | |||
3616 | handle = 0xFFFF; | ||
3617 | while (!(mptsas_sas_device_pg0(ioc, &sas_device, | ||
3618 | MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) { | ||
3619 | |||
3620 | handle = sas_device.handle; | ||
3621 | |||
3622 | if ((sas_device.device_info & | ||
3623 | (MPI_SAS_DEVICE_INFO_SSP_TARGET | | ||
3624 | MPI_SAS_DEVICE_INFO_STP_TARGET | | ||
3625 | MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) | ||
3626 | continue; | ||
3627 | |||
3628 | phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); | ||
3629 | if (!phy_info) | ||
3630 | continue; | ||
3631 | |||
3632 | if (mptsas_get_rphy(phy_info)) | ||
3633 | continue; | ||
3634 | |||
3635 | mptsas_add_end_device(ioc, phy_info); | ||
3636 | } | ||
3637 | } | ||
3638 | |||
3639 | /** | ||
3640 | * mptsas_scan_sas_topology - | ||
3641 | * @ioc: Pointer to MPT_ADAPTER structure | ||
3642 | * @sas_address: | ||
3643 | * | ||
3644 | **/ | ||
2345 | static void | 3645 | static void |
2346 | mptsas_scan_sas_topology(MPT_ADAPTER *ioc) | 3646 | mptsas_scan_sas_topology(MPT_ADAPTER *ioc) |
2347 | { | 3647 | { |
2348 | u32 handle = 0xFFFF; | 3648 | struct scsi_device *sdev; |
2349 | int i; | 3649 | int i; |
2350 | 3650 | ||
2351 | mutex_lock(&ioc->sas_discovery_mutex); | ||
2352 | mptsas_probe_hba_phys(ioc); | 3651 | mptsas_probe_hba_phys(ioc); |
2353 | while (!mptsas_probe_expander_phys(ioc, &handle)) | 3652 | mptsas_probe_expanders(ioc); |
2354 | ; | 3653 | mptsas_probe_devices(ioc); |
3654 | |||
2355 | /* | 3655 | /* |
2356 | Reporting RAID volumes. | 3656 | Reporting RAID volumes. |
2357 | */ | 3657 | */ |
2358 | if (!ioc->ir_firmware) | 3658 | if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 || |
2359 | goto out; | 3659 | !ioc->raid_data.pIocPg2->NumActiveVolumes) |
2360 | if (!ioc->raid_data.pIocPg2) | 3660 | return; |
2361 | goto out; | ||
2362 | if (!ioc->raid_data.pIocPg2->NumActiveVolumes) | ||
2363 | goto out; | ||
2364 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { | 3661 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { |
3662 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, | ||
3663 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); | ||
3664 | if (sdev) { | ||
3665 | scsi_device_put(sdev); | ||
3666 | continue; | ||
3667 | } | ||
3668 | printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " | ||
3669 | "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, | ||
3670 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID); | ||
2365 | scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, | 3671 | scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, |
2366 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); | 3672 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); |
2367 | } | 3673 | } |
2368 | out: | ||
2369 | mutex_unlock(&ioc->sas_discovery_mutex); | ||
2370 | } | 3674 | } |
2371 | 3675 | ||
2372 | /* | 3676 | |
2373 | * Work queue thread to handle Runtime discovery | ||
2374 | * Mere purpose is the hot add/delete of expanders | ||
2375 | *(Mutex UNLOCKED) | ||
2376 | */ | ||
2377 | static void | 3677 | static void |
2378 | __mptsas_discovery_work(MPT_ADAPTER *ioc) | 3678 | mptsas_handle_queue_full_event(struct fw_event_work *fw_event) |
2379 | { | 3679 | { |
2380 | u32 handle = 0xFFFF; | 3680 | MPT_ADAPTER *ioc; |
3681 | EventDataQueueFull_t *qfull_data; | ||
3682 | struct mptsas_device_info *sas_info; | ||
3683 | struct scsi_device *sdev; | ||
3684 | int depth; | ||
3685 | int id = -1; | ||
3686 | int channel = -1; | ||
3687 | int fw_id, fw_channel; | ||
3688 | u16 current_depth; | ||
3689 | |||
3690 | |||
3691 | ioc = fw_event->ioc; | ||
3692 | qfull_data = (EventDataQueueFull_t *)fw_event->event_data; | ||
3693 | fw_id = qfull_data->TargetID; | ||
3694 | fw_channel = qfull_data->Bus; | ||
3695 | current_depth = le16_to_cpu(qfull_data->CurrentDepth); | ||
3696 | |||
3697 | /* if hidden raid component, look for the volume id */ | ||
3698 | mutex_lock(&ioc->sas_device_info_mutex); | ||
3699 | if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) { | ||
3700 | list_for_each_entry(sas_info, &ioc->sas_device_info_list, | ||
3701 | list) { | ||
3702 | if (sas_info->is_cached || | ||
3703 | sas_info->is_logical_volume) | ||
3704 | continue; | ||
3705 | if (sas_info->is_hidden_raid_component && | ||
3706 | (sas_info->fw.channel == fw_channel && | ||
3707 | sas_info->fw.id == fw_id)) { | ||
3708 | id = sas_info->volume_id; | ||
3709 | channel = MPTSAS_RAID_CHANNEL; | ||
3710 | goto out; | ||
3711 | } | ||
3712 | } | ||
3713 | } else { | ||
3714 | list_for_each_entry(sas_info, &ioc->sas_device_info_list, | ||
3715 | list) { | ||
3716 | if (sas_info->is_cached || | ||
3717 | sas_info->is_hidden_raid_component || | ||
3718 | sas_info->is_logical_volume) | ||
3719 | continue; | ||
3720 | if (sas_info->fw.channel == fw_channel && | ||
3721 | sas_info->fw.id == fw_id) { | ||
3722 | id = sas_info->os.id; | ||
3723 | channel = sas_info->os.channel; | ||
3724 | goto out; | ||
3725 | } | ||
3726 | } | ||
2381 | 3727 | ||
2382 | ioc->sas_discovery_runtime=1; | 3728 | } |
2383 | mptsas_delete_expander_phys(ioc); | ||
2384 | mptsas_probe_hba_phys(ioc); | ||
2385 | while (!mptsas_probe_expander_phys(ioc, &handle)) | ||
2386 | ; | ||
2387 | ioc->sas_discovery_runtime=0; | ||
2388 | } | ||
2389 | 3729 | ||
2390 | /* | 3730 | out: |
2391 | * Work queue thread to handle Runtime discovery | 3731 | mutex_unlock(&ioc->sas_device_info_mutex); |
2392 | * Mere purpose is the hot add/delete of expanders | 3732 | |
2393 | *(Mutex LOCKED) | 3733 | if (id != -1) { |
2394 | */ | 3734 | shost_for_each_device(sdev, ioc->sh) { |
2395 | static void | 3735 | if (sdev->id == id && sdev->channel == channel) { |
2396 | mptsas_discovery_work(struct work_struct *work) | 3736 | if (current_depth > sdev->queue_depth) { |
2397 | { | 3737 | sdev_printk(KERN_INFO, sdev, |
2398 | struct mptsas_discovery_event *ev = | 3738 | "strange observation, the queue " |
2399 | container_of(work, struct mptsas_discovery_event, work); | 3739 | "depth is (%d) meanwhile fw queue " |
2400 | MPT_ADAPTER *ioc = ev->ioc; | 3740 | "depth (%d)\n", sdev->queue_depth, |
3741 | current_depth); | ||
3742 | continue; | ||
3743 | } | ||
3744 | depth = scsi_track_queue_full(sdev, | ||
3745 | current_depth - 1); | ||
3746 | if (depth > 0) | ||
3747 | sdev_printk(KERN_INFO, sdev, | ||
3748 | "Queue depth reduced to (%d)\n", | ||
3749 | depth); | ||
3750 | else if (depth < 0) | ||
3751 | sdev_printk(KERN_INFO, sdev, | ||
3752 | "Tagged Command Queueing is being " | ||
3753 | "disabled\n"); | ||
3754 | else if (depth == 0) | ||
3755 | sdev_printk(KERN_INFO, sdev, | ||
3756 | "Queue depth not changed yet\n"); | ||
3757 | } | ||
3758 | } | ||
3759 | } | ||
2401 | 3760 | ||
2402 | mutex_lock(&ioc->sas_discovery_mutex); | 3761 | mptsas_free_fw_event(ioc, fw_event); |
2403 | __mptsas_discovery_work(ioc); | ||
2404 | mutex_unlock(&ioc->sas_discovery_mutex); | ||
2405 | kfree(ev); | ||
2406 | } | 3762 | } |
2407 | 3763 | ||
3764 | |||
2408 | static struct mptsas_phyinfo * | 3765 | static struct mptsas_phyinfo * |
2409 | mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) | 3766 | mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) |
2410 | { | 3767 | { |
@@ -2429,69 +3786,80 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) | |||
2429 | return phy_info; | 3786 | return phy_info; |
2430 | } | 3787 | } |
2431 | 3788 | ||
3789 | /** | ||
3790 | * mptsas_find_phyinfo_by_phys_disk_num - | ||
3791 | * @ioc: Pointer to MPT_ADAPTER structure | ||
3792 | * @phys_disk_num: | ||
3793 | * @channel: | ||
3794 | * @id: | ||
3795 | * | ||
3796 | **/ | ||
2432 | static struct mptsas_phyinfo * | 3797 | static struct mptsas_phyinfo * |
2433 | mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id) | 3798 | mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, |
3799 | u8 channel, u8 id) | ||
2434 | { | 3800 | { |
2435 | struct mptsas_portinfo *port_info; | ||
2436 | struct mptsas_phyinfo *phy_info = NULL; | 3801 | struct mptsas_phyinfo *phy_info = NULL; |
3802 | struct mptsas_portinfo *port_info; | ||
3803 | RaidPhysDiskPage1_t *phys_disk = NULL; | ||
3804 | int num_paths; | ||
3805 | u64 sas_address = 0; | ||
2437 | int i; | 3806 | int i; |
2438 | 3807 | ||
2439 | mutex_lock(&ioc->sas_topology_mutex); | 3808 | phy_info = NULL; |
2440 | list_for_each_entry(port_info, &ioc->sas_topology, list) { | 3809 | if (!ioc->raid_data.pIocPg3) |
2441 | for (i = 0; i < port_info->num_phys; i++) { | 3810 | return NULL; |
2442 | if (!mptsas_is_end_device( | 3811 | /* dual port support */ |
2443 | &port_info->phy_info[i].attached)) | 3812 | num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num); |
2444 | continue; | 3813 | if (!num_paths) |
2445 | if (port_info->phy_info[i].attached.id != id) | 3814 | goto out; |
2446 | continue; | 3815 | phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + |
2447 | if (port_info->phy_info[i].attached.channel != channel) | 3816 | (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); |
2448 | continue; | 3817 | if (!phys_disk) |
2449 | phy_info = &port_info->phy_info[i]; | 3818 | goto out; |
2450 | break; | 3819 | mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk); |
3820 | for (i = 0; i < num_paths; i++) { | ||
3821 | if ((phys_disk->Path[i].Flags & 1) != 0) | ||
3822 | /* entry no longer valid */ | ||
3823 | continue; | ||
3824 | if ((id == phys_disk->Path[i].PhysDiskID) && | ||
3825 | (channel == phys_disk->Path[i].PhysDiskBus)) { | ||
3826 | memcpy(&sas_address, &phys_disk->Path[i].WWID, | ||
3827 | sizeof(u64)); | ||
3828 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, | ||
3829 | sas_address); | ||
3830 | goto out; | ||
2451 | } | 3831 | } |
2452 | } | 3832 | } |
2453 | mutex_unlock(&ioc->sas_topology_mutex); | ||
2454 | return phy_info; | ||
2455 | } | ||
2456 | 3833 | ||
2457 | static struct mptsas_phyinfo * | 3834 | out: |
2458 | mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id) | 3835 | kfree(phys_disk); |
2459 | { | 3836 | if (phy_info) |
2460 | struct mptsas_portinfo *port_info; | 3837 | return phy_info; |
2461 | struct mptsas_phyinfo *phy_info = NULL; | ||
2462 | int i; | ||
2463 | 3838 | ||
3839 | /* | ||
3840 | * Extra code to handle RAID0 case, where the sas_address is not updated | ||
3841 | * in phys_disk_page_1 when hotswapped | ||
3842 | */ | ||
2464 | mutex_lock(&ioc->sas_topology_mutex); | 3843 | mutex_lock(&ioc->sas_topology_mutex); |
2465 | list_for_each_entry(port_info, &ioc->sas_topology, list) { | 3844 | list_for_each_entry(port_info, &ioc->sas_topology, list) { |
2466 | for (i = 0; i < port_info->num_phys; i++) { | 3845 | for (i = 0; i < port_info->num_phys && !phy_info; i++) { |
2467 | if (!mptsas_is_end_device( | 3846 | if (!mptsas_is_end_device( |
2468 | &port_info->phy_info[i].attached)) | 3847 | &port_info->phy_info[i].attached)) |
2469 | continue; | 3848 | continue; |
2470 | if (port_info->phy_info[i].attached.phys_disk_num == ~0) | 3849 | if (port_info->phy_info[i].attached.phys_disk_num == ~0) |
2471 | continue; | 3850 | continue; |
2472 | if (port_info->phy_info[i].attached.phys_disk_num != id) | 3851 | if ((port_info->phy_info[i].attached.phys_disk_num == |
2473 | continue; | 3852 | phys_disk_num) && |
2474 | if (port_info->phy_info[i].attached.channel != channel) | 3853 | (port_info->phy_info[i].attached.id == id) && |
2475 | continue; | 3854 | (port_info->phy_info[i].attached.channel == |
2476 | phy_info = &port_info->phy_info[i]; | 3855 | channel)) |
2477 | break; | 3856 | phy_info = &port_info->phy_info[i]; |
2478 | } | 3857 | } |
2479 | } | 3858 | } |
2480 | mutex_unlock(&ioc->sas_topology_mutex); | 3859 | mutex_unlock(&ioc->sas_topology_mutex); |
2481 | return phy_info; | 3860 | return phy_info; |
2482 | } | 3861 | } |
2483 | 3862 | ||
2484 | /* | ||
2485 | * Work queue thread to clear the persitency table | ||
2486 | */ | ||
2487 | static void | ||
2488 | mptsas_persist_clear_table(struct work_struct *work) | ||
2489 | { | ||
2490 | MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task); | ||
2491 | |||
2492 | mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); | ||
2493 | } | ||
2494 | |||
2495 | static void | 3863 | static void |
2496 | mptsas_reprobe_lun(struct scsi_device *sdev, void *data) | 3864 | mptsas_reprobe_lun(struct scsi_device *sdev, void *data) |
2497 | { | 3865 | { |
@@ -2517,7 +3885,8 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
2517 | pRaidVolumePage0_t buffer = NULL; | 3885 | pRaidVolumePage0_t buffer = NULL; |
2518 | RaidPhysDiskPage0_t phys_disk; | 3886 | RaidPhysDiskPage0_t phys_disk; |
2519 | int i; | 3887 | int i; |
2520 | struct mptsas_hotplug_event *ev; | 3888 | struct mptsas_phyinfo *phy_info; |
3889 | struct mptsas_devinfo sas_device; | ||
2521 | 3890 | ||
2522 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); | 3891 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); |
2523 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); | 3892 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); |
@@ -2557,20 +3926,16 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
2557 | buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) | 3926 | buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) |
2558 | continue; | 3927 | continue; |
2559 | 3928 | ||
2560 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 3929 | if (mptsas_sas_device_pg0(ioc, &sas_device, |
2561 | if (!ev) { | 3930 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
2562 | printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name); | 3931 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
2563 | goto out; | 3932 | (phys_disk.PhysDiskBus << 8) + |
2564 | } | 3933 | phys_disk.PhysDiskID)) |
3934 | continue; | ||
2565 | 3935 | ||
2566 | INIT_WORK(&ev->work, mptsas_hotplug_work); | 3936 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
2567 | ev->ioc = ioc; | 3937 | sas_device.sas_address); |
2568 | ev->id = phys_disk.PhysDiskID; | 3938 | mptsas_add_end_device(ioc, phy_info); |
2569 | ev->channel = phys_disk.PhysDiskBus; | ||
2570 | ev->phys_disk_num_valid = 1; | ||
2571 | ev->phys_disk_num = phys_disk.PhysDiskNum; | ||
2572 | ev->event_type = MPTSAS_ADD_DEVICE; | ||
2573 | schedule_work(&ev->work); | ||
2574 | } | 3939 | } |
2575 | 3940 | ||
2576 | out: | 3941 | out: |
@@ -2582,417 +3947,386 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
2582 | * Work queue thread to handle SAS hotplug events | 3947 | * Work queue thread to handle SAS hotplug events |
2583 | */ | 3948 | */ |
2584 | static void | 3949 | static void |
2585 | mptsas_hotplug_work(struct work_struct *work) | 3950 | mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, |
3951 | struct mptsas_hotplug_event *hot_plug_info) | ||
2586 | { | 3952 | { |
2587 | struct mptsas_hotplug_event *ev = | ||
2588 | container_of(work, struct mptsas_hotplug_event, work); | ||
2589 | |||
2590 | MPT_ADAPTER *ioc = ev->ioc; | ||
2591 | struct mptsas_phyinfo *phy_info; | 3953 | struct mptsas_phyinfo *phy_info; |
2592 | struct sas_rphy *rphy; | ||
2593 | struct sas_port *port; | ||
2594 | struct scsi_device *sdev; | ||
2595 | struct scsi_target * starget; | 3954 | struct scsi_target * starget; |
2596 | struct sas_identify identify; | ||
2597 | char *ds = NULL; | ||
2598 | struct mptsas_devinfo sas_device; | 3955 | struct mptsas_devinfo sas_device; |
2599 | VirtTarget *vtarget; | 3956 | VirtTarget *vtarget; |
2600 | VirtDevice *vdevice; | 3957 | int i; |
2601 | 3958 | ||
2602 | mutex_lock(&ioc->sas_discovery_mutex); | 3959 | switch (hot_plug_info->event_type) { |
2603 | switch (ev->event_type) { | ||
2604 | case MPTSAS_DEL_DEVICE: | ||
2605 | 3960 | ||
2606 | phy_info = NULL; | 3961 | case MPTSAS_ADD_PHYSDISK: |
2607 | if (ev->phys_disk_num_valid) { | 3962 | |
2608 | if (ev->hidden_raid_component){ | 3963 | if (!ioc->raid_data.pIocPg2) |
2609 | if (mptsas_sas_device_pg0(ioc, &sas_device, | 3964 | break; |
2610 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | 3965 | |
2611 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 3966 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { |
2612 | (ev->channel << 8) + ev->id)) { | 3967 | if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == |
2613 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 3968 | hot_plug_info->id) { |
2614 | "%s: exit at line=%d\n", ioc->name, | 3969 | printk(MYIOC_s_WARN_FMT "firmware bug: unable " |
2615 | __func__, __LINE__)); | 3970 | "to add hidden disk - target_id matchs " |
2616 | break; | 3971 | "volume_id\n", ioc->name); |
2617 | } | 3972 | mptsas_free_fw_event(ioc, fw_event); |
2618 | phy_info = mptsas_find_phyinfo_by_sas_address( | 3973 | return; |
2619 | ioc, sas_device.sas_address); | 3974 | } |
2620 | }else | ||
2621 | phy_info = mptsas_find_phyinfo_by_phys_disk_num( | ||
2622 | ioc, ev->channel, ev->phys_disk_num); | ||
2623 | } | 3975 | } |
3976 | mpt_findImVolumes(ioc); | ||
2624 | 3977 | ||
3978 | case MPTSAS_ADD_DEVICE: | ||
3979 | memset(&sas_device, 0, sizeof(struct mptsas_devinfo)); | ||
3980 | mptsas_sas_device_pg0(ioc, &sas_device, | ||
3981 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | ||
3982 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | ||
3983 | (hot_plug_info->channel << 8) + | ||
3984 | hot_plug_info->id); | ||
3985 | |||
3986 | if (!sas_device.handle) | ||
3987 | return; | ||
3988 | |||
3989 | phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); | ||
2625 | if (!phy_info) | 3990 | if (!phy_info) |
2626 | phy_info = mptsas_find_phyinfo_by_target(ioc, | 3991 | break; |
2627 | ev->channel, ev->id); | ||
2628 | 3992 | ||
2629 | /* | 3993 | if (mptsas_get_rphy(phy_info)) |
2630 | * Sanity checks, for non-existing phys and remote rphys. | 3994 | break; |
2631 | */ | 3995 | |
2632 | if (!phy_info){ | 3996 | mptsas_add_end_device(ioc, phy_info); |
3997 | break; | ||
3998 | |||
3999 | case MPTSAS_DEL_DEVICE: | ||
4000 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, | ||
4001 | hot_plug_info->sas_address); | ||
4002 | mptsas_del_end_device(ioc, phy_info); | ||
4003 | break; | ||
4004 | |||
4005 | case MPTSAS_DEL_PHYSDISK: | ||
4006 | |||
4007 | mpt_findImVolumes(ioc); | ||
4008 | |||
4009 | phy_info = mptsas_find_phyinfo_by_phys_disk_num( | ||
4010 | ioc, hot_plug_info->phys_disk_num, | ||
4011 | hot_plug_info->channel, | ||
4012 | hot_plug_info->id); | ||
4013 | mptsas_del_end_device(ioc, phy_info); | ||
4014 | break; | ||
4015 | |||
4016 | case MPTSAS_ADD_PHYSDISK_REPROBE: | ||
4017 | |||
4018 | if (mptsas_sas_device_pg0(ioc, &sas_device, | ||
4019 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | ||
4020 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | ||
4021 | (hot_plug_info->channel << 8) + hot_plug_info->id)) { | ||
2633 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 4022 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2634 | "%s: exit at line=%d\n", ioc->name, | 4023 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2635 | __func__, __LINE__)); | 4024 | __func__, hot_plug_info->id, __LINE__)); |
2636 | break; | 4025 | break; |
2637 | } | 4026 | } |
2638 | if (!phy_info->port_details) { | 4027 | |
4028 | phy_info = mptsas_find_phyinfo_by_sas_address( | ||
4029 | ioc, sas_device.sas_address); | ||
4030 | |||
4031 | if (!phy_info) { | ||
2639 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 4032 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2640 | "%s: exit at line=%d\n", ioc->name, | 4033 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2641 | __func__, __LINE__)); | 4034 | __func__, hot_plug_info->id, __LINE__)); |
2642 | break; | 4035 | break; |
2643 | } | 4036 | } |
2644 | rphy = mptsas_get_rphy(phy_info); | 4037 | |
2645 | if (!rphy) { | 4038 | starget = mptsas_get_starget(phy_info); |
4039 | if (!starget) { | ||
2646 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 4040 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2647 | "%s: exit at line=%d\n", ioc->name, | 4041 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2648 | __func__, __LINE__)); | 4042 | __func__, hot_plug_info->id, __LINE__)); |
2649 | break; | 4043 | break; |
2650 | } | 4044 | } |
2651 | 4045 | ||
2652 | port = mptsas_get_port(phy_info); | 4046 | vtarget = starget->hostdata; |
2653 | if (!port) { | 4047 | if (!vtarget) { |
2654 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 4048 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2655 | "%s: exit at line=%d\n", ioc->name, | 4049 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2656 | __func__, __LINE__)); | 4050 | __func__, hot_plug_info->id, __LINE__)); |
2657 | break; | 4051 | break; |
2658 | } | 4052 | } |
2659 | 4053 | ||
2660 | starget = mptsas_get_starget(phy_info); | 4054 | mpt_findImVolumes(ioc); |
2661 | if (starget) { | ||
2662 | vtarget = starget->hostdata; | ||
2663 | 4055 | ||
2664 | if (!vtarget) { | 4056 | starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: " |
2665 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 4057 | "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", |
2666 | "%s: exit at line=%d\n", ioc->name, | 4058 | ioc->name, hot_plug_info->channel, hot_plug_info->id, |
2667 | __func__, __LINE__)); | 4059 | hot_plug_info->phys_disk_num, (unsigned long long) |
2668 | break; | 4060 | sas_device.sas_address); |
2669 | } | ||
2670 | 4061 | ||
2671 | /* | 4062 | vtarget->id = hot_plug_info->phys_disk_num; |
2672 | * Handling RAID components | 4063 | vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; |
2673 | */ | 4064 | phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num; |
2674 | if (ev->phys_disk_num_valid && | 4065 | mptsas_reprobe_target(starget, 1); |
2675 | ev->hidden_raid_component) { | ||
2676 | printk(MYIOC_s_INFO_FMT | ||
2677 | "RAID Hidding: channel=%d, id=%d, " | ||
2678 | "physdsk %d \n", ioc->name, ev->channel, | ||
2679 | ev->id, ev->phys_disk_num); | ||
2680 | vtarget->id = ev->phys_disk_num; | ||
2681 | vtarget->tflags |= | ||
2682 | MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
2683 | mptsas_reprobe_target(starget, 1); | ||
2684 | phy_info->attached.phys_disk_num = | ||
2685 | ev->phys_disk_num; | ||
2686 | break; | ||
2687 | } | ||
2688 | } | ||
2689 | |||
2690 | if (phy_info->attached.device_info & | ||
2691 | MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
2692 | ds = "ssp"; | ||
2693 | if (phy_info->attached.device_info & | ||
2694 | MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
2695 | ds = "stp"; | ||
2696 | if (phy_info->attached.device_info & | ||
2697 | MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
2698 | ds = "sata"; | ||
2699 | |||
2700 | printk(MYIOC_s_INFO_FMT | ||
2701 | "removing %s device, channel %d, id %d, phy %d\n", | ||
2702 | ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); | ||
2703 | dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT | ||
2704 | "delete port (%d)\n", ioc->name, port->port_identifier); | ||
2705 | sas_port_delete(port); | ||
2706 | mptsas_port_delete(ioc, phy_info->port_details); | ||
2707 | break; | 4066 | break; |
2708 | case MPTSAS_ADD_DEVICE: | ||
2709 | 4067 | ||
2710 | if (ev->phys_disk_num_valid) | 4068 | case MPTSAS_DEL_PHYSDISK_REPROBE: |
2711 | mpt_findImVolumes(ioc); | ||
2712 | 4069 | ||
2713 | /* | ||
2714 | * Refresh sas device pg0 data | ||
2715 | */ | ||
2716 | if (mptsas_sas_device_pg0(ioc, &sas_device, | 4070 | if (mptsas_sas_device_pg0(ioc, &sas_device, |
2717 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | 4071 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
2718 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 4072 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
2719 | (ev->channel << 8) + ev->id)) { | 4073 | (hot_plug_info->channel << 8) + hot_plug_info->id)) { |
2720 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 4074 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2721 | "%s: exit at line=%d\n", ioc->name, | 4075 | "%s: fw_id=%d exit at line=%d\n", |
2722 | __func__, __LINE__)); | 4076 | ioc->name, __func__, |
4077 | hot_plug_info->id, __LINE__)); | ||
2723 | break; | 4078 | break; |
2724 | } | 4079 | } |
2725 | 4080 | ||
2726 | __mptsas_discovery_work(ioc); | ||
2727 | |||
2728 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, | 4081 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
2729 | sas_device.sas_address); | 4082 | sas_device.sas_address); |
2730 | 4083 | if (!phy_info) { | |
2731 | if (!phy_info || !phy_info->port_details) { | ||
2732 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 4084 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2733 | "%s: exit at line=%d\n", ioc->name, | 4085 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2734 | __func__, __LINE__)); | 4086 | __func__, hot_plug_info->id, __LINE__)); |
2735 | break; | 4087 | break; |
2736 | } | 4088 | } |
2737 | 4089 | ||
2738 | starget = mptsas_get_starget(phy_info); | 4090 | starget = mptsas_get_starget(phy_info); |
2739 | if (starget && (!ev->hidden_raid_component)){ | 4091 | if (!starget) { |
2740 | 4092 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | |
2741 | vtarget = starget->hostdata; | 4093 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2742 | 4094 | __func__, hot_plug_info->id, __LINE__)); | |
2743 | if (!vtarget) { | ||
2744 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
2745 | "%s: exit at line=%d\n", ioc->name, | ||
2746 | __func__, __LINE__)); | ||
2747 | break; | ||
2748 | } | ||
2749 | /* | ||
2750 | * Handling RAID components | ||
2751 | */ | ||
2752 | if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { | ||
2753 | printk(MYIOC_s_INFO_FMT | ||
2754 | "RAID Exposing: channel=%d, id=%d, " | ||
2755 | "physdsk %d \n", ioc->name, ev->channel, | ||
2756 | ev->id, ev->phys_disk_num); | ||
2757 | vtarget->tflags &= | ||
2758 | ~MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
2759 | vtarget->id = ev->id; | ||
2760 | mptsas_reprobe_target(starget, 0); | ||
2761 | phy_info->attached.phys_disk_num = ~0; | ||
2762 | } | ||
2763 | break; | 4095 | break; |
2764 | } | 4096 | } |
2765 | 4097 | ||
2766 | if (mptsas_get_rphy(phy_info)) { | 4098 | vtarget = starget->hostdata; |
4099 | if (!vtarget) { | ||
2767 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 4100 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2768 | "%s: exit at line=%d\n", ioc->name, | 4101 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2769 | __func__, __LINE__)); | 4102 | __func__, hot_plug_info->id, __LINE__)); |
2770 | if (ev->channel) printk("%d\n", __LINE__); | ||
2771 | break; | 4103 | break; |
2772 | } | 4104 | } |
2773 | 4105 | ||
2774 | port = mptsas_get_port(phy_info); | 4106 | if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) { |
2775 | if (!port) { | ||
2776 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 4107 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
2777 | "%s: exit at line=%d\n", ioc->name, | 4108 | "%s: fw_id=%d exit at line=%d\n", ioc->name, |
2778 | __func__, __LINE__)); | 4109 | __func__, hot_plug_info->id, __LINE__)); |
2779 | break; | 4110 | break; |
2780 | } | 4111 | } |
2781 | memcpy(&phy_info->attached, &sas_device, | ||
2782 | sizeof(struct mptsas_devinfo)); | ||
2783 | |||
2784 | if (phy_info->attached.device_info & | ||
2785 | MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
2786 | ds = "ssp"; | ||
2787 | if (phy_info->attached.device_info & | ||
2788 | MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
2789 | ds = "stp"; | ||
2790 | if (phy_info->attached.device_info & | ||
2791 | MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
2792 | ds = "sata"; | ||
2793 | |||
2794 | printk(MYIOC_s_INFO_FMT | ||
2795 | "attaching %s device, channel %d, id %d, phy %d\n", | ||
2796 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | ||
2797 | 4112 | ||
2798 | mptsas_parse_device_info(&identify, &phy_info->attached); | 4113 | mpt_findImVolumes(ioc); |
2799 | rphy = sas_end_device_alloc(port); | ||
2800 | if (!rphy) { | ||
2801 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
2802 | "%s: exit at line=%d\n", ioc->name, | ||
2803 | __func__, __LINE__)); | ||
2804 | break; /* non-fatal: an rphy can be added later */ | ||
2805 | } | ||
2806 | 4114 | ||
2807 | rphy->identify = identify; | 4115 | starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:" |
2808 | if (sas_rphy_add(rphy)) { | 4116 | " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", |
2809 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 4117 | ioc->name, hot_plug_info->channel, hot_plug_info->id, |
2810 | "%s: exit at line=%d\n", ioc->name, | 4118 | hot_plug_info->phys_disk_num, (unsigned long long) |
2811 | __func__, __LINE__)); | 4119 | sas_device.sas_address); |
2812 | sas_rphy_free(rphy); | 4120 | |
2813 | break; | 4121 | vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; |
2814 | } | 4122 | vtarget->id = hot_plug_info->id; |
2815 | mptsas_set_rphy(ioc, phy_info, rphy); | 4123 | phy_info->attached.phys_disk_num = ~0; |
4124 | mptsas_reprobe_target(starget, 0); | ||
4125 | mptsas_add_device_component_by_fw(ioc, | ||
4126 | hot_plug_info->channel, hot_plug_info->id); | ||
2816 | break; | 4127 | break; |
4128 | |||
2817 | case MPTSAS_ADD_RAID: | 4129 | case MPTSAS_ADD_RAID: |
2818 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, | 4130 | |
2819 | ev->id, 0); | ||
2820 | if (sdev) { | ||
2821 | scsi_device_put(sdev); | ||
2822 | break; | ||
2823 | } | ||
2824 | printk(MYIOC_s_INFO_FMT | ||
2825 | "attaching raid volume, channel %d, id %d\n", | ||
2826 | ioc->name, MPTSAS_RAID_CHANNEL, ev->id); | ||
2827 | scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0); | ||
2828 | mpt_findImVolumes(ioc); | 4131 | mpt_findImVolumes(ioc); |
4132 | printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " | ||
4133 | "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, | ||
4134 | hot_plug_info->id); | ||
4135 | scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, | ||
4136 | hot_plug_info->id, 0); | ||
2829 | break; | 4137 | break; |
4138 | |||
2830 | case MPTSAS_DEL_RAID: | 4139 | case MPTSAS_DEL_RAID: |
2831 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, | 4140 | |
2832 | ev->id, 0); | ||
2833 | if (!sdev) | ||
2834 | break; | ||
2835 | printk(MYIOC_s_INFO_FMT | ||
2836 | "removing raid volume, channel %d, id %d\n", | ||
2837 | ioc->name, MPTSAS_RAID_CHANNEL, ev->id); | ||
2838 | vdevice = sdev->hostdata; | ||
2839 | scsi_remove_device(sdev); | ||
2840 | scsi_device_put(sdev); | ||
2841 | mpt_findImVolumes(ioc); | 4141 | mpt_findImVolumes(ioc); |
4142 | printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " | ||
4143 | "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, | ||
4144 | hot_plug_info->id); | ||
4145 | scsi_remove_device(hot_plug_info->sdev); | ||
4146 | scsi_device_put(hot_plug_info->sdev); | ||
2842 | break; | 4147 | break; |
4148 | |||
2843 | case MPTSAS_ADD_INACTIVE_VOLUME: | 4149 | case MPTSAS_ADD_INACTIVE_VOLUME: |
4150 | |||
4151 | mpt_findImVolumes(ioc); | ||
2844 | mptsas_adding_inactive_raid_components(ioc, | 4152 | mptsas_adding_inactive_raid_components(ioc, |
2845 | ev->channel, ev->id); | 4153 | hot_plug_info->channel, hot_plug_info->id); |
2846 | break; | 4154 | break; |
2847 | case MPTSAS_IGNORE_EVENT: | 4155 | |
2848 | default: | 4156 | default: |
2849 | break; | 4157 | break; |
2850 | } | 4158 | } |
2851 | 4159 | ||
2852 | mutex_unlock(&ioc->sas_discovery_mutex); | 4160 | mptsas_free_fw_event(ioc, fw_event); |
2853 | kfree(ev); | ||
2854 | } | 4161 | } |
2855 | 4162 | ||
2856 | static void | 4163 | static void |
2857 | mptsas_send_sas_event(MPT_ADAPTER *ioc, | 4164 | mptsas_send_sas_event(struct fw_event_work *fw_event) |
2858 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) | ||
2859 | { | 4165 | { |
2860 | struct mptsas_hotplug_event *ev; | 4166 | MPT_ADAPTER *ioc; |
2861 | u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo); | 4167 | struct mptsas_hotplug_event hot_plug_info; |
2862 | __le64 sas_address; | 4168 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; |
4169 | u32 device_info; | ||
4170 | u64 sas_address; | ||
4171 | |||
4172 | ioc = fw_event->ioc; | ||
4173 | sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) | ||
4174 | fw_event->event_data; | ||
4175 | device_info = le32_to_cpu(sas_event_data->DeviceInfo); | ||
2863 | 4176 | ||
2864 | if ((device_info & | 4177 | if ((device_info & |
2865 | (MPI_SAS_DEVICE_INFO_SSP_TARGET | | 4178 | (MPI_SAS_DEVICE_INFO_SSP_TARGET | |
2866 | MPI_SAS_DEVICE_INFO_STP_TARGET | | 4179 | MPI_SAS_DEVICE_INFO_STP_TARGET | |
2867 | MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) | 4180 | MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) { |
4181 | mptsas_free_fw_event(ioc, fw_event); | ||
4182 | return; | ||
4183 | } | ||
4184 | |||
4185 | if (sas_event_data->ReasonCode == | ||
4186 | MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) { | ||
4187 | mptbase_sas_persist_operation(ioc, | ||
4188 | MPI_SAS_OP_CLEAR_NOT_PRESENT); | ||
4189 | mptsas_free_fw_event(ioc, fw_event); | ||
2868 | return; | 4190 | return; |
4191 | } | ||
2869 | 4192 | ||
2870 | switch (sas_event_data->ReasonCode) { | 4193 | switch (sas_event_data->ReasonCode) { |
2871 | case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: | 4194 | case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: |
2872 | |||
2873 | mptsas_target_reset_queue(ioc, sas_event_data); | ||
2874 | break; | ||
2875 | |||
2876 | case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: | 4195 | case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: |
2877 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 4196 | memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); |
2878 | if (!ev) { | 4197 | hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle); |
2879 | printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); | 4198 | hot_plug_info.channel = sas_event_data->Bus; |
2880 | break; | 4199 | hot_plug_info.id = sas_event_data->TargetID; |
2881 | } | 4200 | hot_plug_info.phy_id = sas_event_data->PhyNum; |
2882 | |||
2883 | INIT_WORK(&ev->work, mptsas_hotplug_work); | ||
2884 | ev->ioc = ioc; | ||
2885 | ev->handle = le16_to_cpu(sas_event_data->DevHandle); | ||
2886 | ev->parent_handle = | ||
2887 | le16_to_cpu(sas_event_data->ParentDevHandle); | ||
2888 | ev->channel = sas_event_data->Bus; | ||
2889 | ev->id = sas_event_data->TargetID; | ||
2890 | ev->phy_id = sas_event_data->PhyNum; | ||
2891 | memcpy(&sas_address, &sas_event_data->SASAddress, | 4201 | memcpy(&sas_address, &sas_event_data->SASAddress, |
2892 | sizeof(__le64)); | 4202 | sizeof(u64)); |
2893 | ev->sas_address = le64_to_cpu(sas_address); | 4203 | hot_plug_info.sas_address = le64_to_cpu(sas_address); |
2894 | ev->device_info = device_info; | 4204 | hot_plug_info.device_info = device_info; |
2895 | |||
2896 | if (sas_event_data->ReasonCode & | 4205 | if (sas_event_data->ReasonCode & |
2897 | MPI_EVENT_SAS_DEV_STAT_RC_ADDED) | 4206 | MPI_EVENT_SAS_DEV_STAT_RC_ADDED) |
2898 | ev->event_type = MPTSAS_ADD_DEVICE; | 4207 | hot_plug_info.event_type = MPTSAS_ADD_DEVICE; |
2899 | else | 4208 | else |
2900 | ev->event_type = MPTSAS_DEL_DEVICE; | 4209 | hot_plug_info.event_type = MPTSAS_DEL_DEVICE; |
2901 | schedule_work(&ev->work); | 4210 | mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); |
2902 | break; | 4211 | break; |
4212 | |||
2903 | case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: | 4213 | case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: |
2904 | /* | 4214 | mptbase_sas_persist_operation(ioc, |
2905 | * Persistent table is full. | 4215 | MPI_SAS_OP_CLEAR_NOT_PRESENT); |
2906 | */ | 4216 | mptsas_free_fw_event(ioc, fw_event); |
2907 | INIT_WORK(&ioc->sas_persist_task, | ||
2908 | mptsas_persist_clear_table); | ||
2909 | schedule_work(&ioc->sas_persist_task); | ||
2910 | break; | 4217 | break; |
2911 | /* | 4218 | |
2912 | * TODO, handle other events | ||
2913 | */ | ||
2914 | case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: | 4219 | case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: |
2915 | case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: | 4220 | /* TODO */ |
2916 | case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: | 4221 | case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: |
2917 | case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: | 4222 | /* TODO */ |
2918 | case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: | ||
2919 | case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: | ||
2920 | case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: | ||
2921 | default: | 4223 | default: |
4224 | mptsas_free_fw_event(ioc, fw_event); | ||
2922 | break; | 4225 | break; |
2923 | } | 4226 | } |
2924 | } | 4227 | } |
4228 | |||
2925 | static void | 4229 | static void |
2926 | mptsas_send_raid_event(MPT_ADAPTER *ioc, | 4230 | mptsas_send_raid_event(struct fw_event_work *fw_event) |
2927 | EVENT_DATA_RAID *raid_event_data) | ||
2928 | { | 4231 | { |
2929 | struct mptsas_hotplug_event *ev; | 4232 | MPT_ADAPTER *ioc; |
2930 | int status = le32_to_cpu(raid_event_data->SettingsStatus); | 4233 | EVENT_DATA_RAID *raid_event_data; |
2931 | int state = (status >> 8) & 0xff; | 4234 | struct mptsas_hotplug_event hot_plug_info; |
2932 | 4235 | int status; | |
2933 | if (ioc->bus_type != SAS) | 4236 | int state; |
2934 | return; | 4237 | struct scsi_device *sdev = NULL; |
2935 | 4238 | VirtDevice *vdevice = NULL; | |
2936 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 4239 | RaidPhysDiskPage0_t phys_disk; |
2937 | if (!ev) { | 4240 | |
2938 | printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); | 4241 | ioc = fw_event->ioc; |
2939 | return; | 4242 | raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data; |
4243 | status = le32_to_cpu(raid_event_data->SettingsStatus); | ||
4244 | state = (status >> 8) & 0xff; | ||
4245 | |||
4246 | memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); | ||
4247 | hot_plug_info.id = raid_event_data->VolumeID; | ||
4248 | hot_plug_info.channel = raid_event_data->VolumeBus; | ||
4249 | hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum; | ||
4250 | |||
4251 | if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED || | ||
4252 | raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED || | ||
4253 | raid_event_data->ReasonCode == | ||
4254 | MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) { | ||
4255 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, | ||
4256 | hot_plug_info.id, 0); | ||
4257 | hot_plug_info.sdev = sdev; | ||
4258 | if (sdev) | ||
4259 | vdevice = sdev->hostdata; | ||
2940 | } | 4260 | } |
2941 | 4261 | ||
2942 | INIT_WORK(&ev->work, mptsas_hotplug_work); | 4262 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " |
2943 | ev->ioc = ioc; | 4263 | "ReasonCode=%02x\n", ioc->name, __func__, |
2944 | ev->id = raid_event_data->VolumeID; | 4264 | raid_event_data->ReasonCode)); |
2945 | ev->channel = raid_event_data->VolumeBus; | ||
2946 | ev->event_type = MPTSAS_IGNORE_EVENT; | ||
2947 | 4265 | ||
2948 | switch (raid_event_data->ReasonCode) { | 4266 | switch (raid_event_data->ReasonCode) { |
2949 | case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: | 4267 | case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: |
2950 | ev->phys_disk_num_valid = 1; | 4268 | hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE; |
2951 | ev->phys_disk_num = raid_event_data->PhysDiskNum; | ||
2952 | ev->event_type = MPTSAS_ADD_DEVICE; | ||
2953 | break; | 4269 | break; |
2954 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: | 4270 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: |
2955 | ev->phys_disk_num_valid = 1; | 4271 | hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE; |
2956 | ev->phys_disk_num = raid_event_data->PhysDiskNum; | ||
2957 | ev->hidden_raid_component = 1; | ||
2958 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
2959 | break; | 4272 | break; |
2960 | case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: | 4273 | case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: |
2961 | switch (state) { | 4274 | switch (state) { |
2962 | case MPI_PD_STATE_ONLINE: | 4275 | case MPI_PD_STATE_ONLINE: |
2963 | case MPI_PD_STATE_NOT_COMPATIBLE: | 4276 | case MPI_PD_STATE_NOT_COMPATIBLE: |
2964 | ev->phys_disk_num_valid = 1; | 4277 | mpt_raid_phys_disk_pg0(ioc, |
2965 | ev->phys_disk_num = raid_event_data->PhysDiskNum; | 4278 | raid_event_data->PhysDiskNum, &phys_disk); |
2966 | ev->hidden_raid_component = 1; | 4279 | hot_plug_info.id = phys_disk.PhysDiskID; |
2967 | ev->event_type = MPTSAS_ADD_DEVICE; | 4280 | hot_plug_info.channel = phys_disk.PhysDiskBus; |
4281 | hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; | ||
2968 | break; | 4282 | break; |
4283 | case MPI_PD_STATE_FAILED: | ||
2969 | case MPI_PD_STATE_MISSING: | 4284 | case MPI_PD_STATE_MISSING: |
2970 | case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: | 4285 | case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: |
2971 | case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: | 4286 | case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: |
2972 | case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: | 4287 | case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: |
2973 | ev->phys_disk_num_valid = 1; | 4288 | hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; |
2974 | ev->phys_disk_num = raid_event_data->PhysDiskNum; | ||
2975 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
2976 | break; | 4289 | break; |
2977 | default: | 4290 | default: |
2978 | break; | 4291 | break; |
2979 | } | 4292 | } |
2980 | break; | 4293 | break; |
2981 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: | 4294 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: |
2982 | ev->event_type = MPTSAS_DEL_RAID; | 4295 | if (!sdev) |
4296 | break; | ||
4297 | vdevice->vtarget->deleted = 1; /* block IO */ | ||
4298 | hot_plug_info.event_type = MPTSAS_DEL_RAID; | ||
2983 | break; | 4299 | break; |
2984 | case MPI_EVENT_RAID_RC_VOLUME_CREATED: | 4300 | case MPI_EVENT_RAID_RC_VOLUME_CREATED: |
2985 | ev->event_type = MPTSAS_ADD_RAID; | 4301 | if (sdev) { |
4302 | scsi_device_put(sdev); | ||
4303 | break; | ||
4304 | } | ||
4305 | hot_plug_info.event_type = MPTSAS_ADD_RAID; | ||
2986 | break; | 4306 | break; |
2987 | case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: | 4307 | case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: |
4308 | if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) { | ||
4309 | if (!sdev) | ||
4310 | break; | ||
4311 | vdevice->vtarget->deleted = 1; /* block IO */ | ||
4312 | hot_plug_info.event_type = MPTSAS_DEL_RAID; | ||
4313 | break; | ||
4314 | } | ||
2988 | switch (state) { | 4315 | switch (state) { |
2989 | case MPI_RAIDVOL0_STATUS_STATE_FAILED: | 4316 | case MPI_RAIDVOL0_STATUS_STATE_FAILED: |
2990 | case MPI_RAIDVOL0_STATUS_STATE_MISSING: | 4317 | case MPI_RAIDVOL0_STATUS_STATE_MISSING: |
2991 | ev->event_type = MPTSAS_DEL_RAID; | 4318 | if (!sdev) |
4319 | break; | ||
4320 | vdevice->vtarget->deleted = 1; /* block IO */ | ||
4321 | hot_plug_info.event_type = MPTSAS_DEL_RAID; | ||
2992 | break; | 4322 | break; |
2993 | case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: | 4323 | case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: |
2994 | case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: | 4324 | case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: |
2995 | ev->event_type = MPTSAS_ADD_RAID; | 4325 | if (sdev) { |
4326 | scsi_device_put(sdev); | ||
4327 | break; | ||
4328 | } | ||
4329 | hot_plug_info.event_type = MPTSAS_ADD_RAID; | ||
2996 | break; | 4330 | break; |
2997 | default: | 4331 | default: |
2998 | break; | 4332 | break; |
@@ -3001,32 +4335,188 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc, | |||
3001 | default: | 4335 | default: |
3002 | break; | 4336 | break; |
3003 | } | 4337 | } |
3004 | schedule_work(&ev->work); | 4338 | |
4339 | if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT) | ||
4340 | mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); | ||
4341 | else | ||
4342 | mptsas_free_fw_event(ioc, fw_event); | ||
3005 | } | 4343 | } |
3006 | 4344 | ||
3007 | static void | 4345 | /** |
3008 | mptsas_send_discovery_event(MPT_ADAPTER *ioc, | 4346 | * mptsas_issue_tm - send mptsas internal tm request |
3009 | EVENT_DATA_SAS_DISCOVERY *discovery_data) | 4347 | * @ioc: Pointer to MPT_ADAPTER structure |
4348 | * @type: Task Management type | ||
4349 | * @channel: channel number for task management | ||
4350 | * @id: Logical Target ID for reset (if appropriate) | ||
4351 | * @lun: Logical unit for reset (if appropriate) | ||
4352 | * @task_context: Context for the task to be aborted | ||
4353 | * @timeout: timeout for task management control | ||
4354 | * | ||
4355 | * return 0 on success and -1 on failure: | ||
4356 | * | ||
4357 | */ | ||
4358 | static int | ||
4359 | mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, | ||
4360 | int task_context, ulong timeout, u8 *issue_reset) | ||
3010 | { | 4361 | { |
3011 | struct mptsas_discovery_event *ev; | 4362 | MPT_FRAME_HDR *mf; |
4363 | SCSITaskMgmt_t *pScsiTm; | ||
4364 | int retval; | ||
4365 | unsigned long timeleft; | ||
4366 | |||
4367 | *issue_reset = 0; | ||
4368 | mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); | ||
4369 | if (mf == NULL) { | ||
4370 | retval = -1; /* return failure */ | ||
4371 | dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no " | ||
4372 | "msg frames!!\n", ioc->name)); | ||
4373 | goto out; | ||
4374 | } | ||
3012 | 4375 | ||
3013 | /* | 4376 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, " |
3014 | * DiscoveryStatus | 4377 | "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, " |
3015 | * | 4378 | "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf, |
3016 | * This flag will be non-zero when firmware | 4379 | type, timeout, channel, id, (unsigned long long)lun, |
3017 | * kicks off discovery, and return to zero | 4380 | task_context)); |
3018 | * once its completed. | 4381 | |
3019 | */ | 4382 | pScsiTm = (SCSITaskMgmt_t *) mf; |
3020 | if (discovery_data->DiscoveryStatus) | 4383 | memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); |
3021 | return; | 4384 | pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; |
4385 | pScsiTm->TaskType = type; | ||
4386 | pScsiTm->MsgFlags = 0; | ||
4387 | pScsiTm->TargetID = id; | ||
4388 | pScsiTm->Bus = channel; | ||
4389 | pScsiTm->ChainOffset = 0; | ||
4390 | pScsiTm->Reserved = 0; | ||
4391 | pScsiTm->Reserved1 = 0; | ||
4392 | pScsiTm->TaskMsgContext = task_context; | ||
4393 | int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); | ||
4394 | |||
4395 | INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) | ||
4396 | CLEAR_MGMT_STATUS(ioc->internal_cmds.status) | ||
4397 | retval = 0; | ||
4398 | mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); | ||
4399 | |||
4400 | /* Now wait for the command to complete */ | ||
4401 | timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, | ||
4402 | timeout*HZ); | ||
4403 | if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { | ||
4404 | retval = -1; /* return failure */ | ||
4405 | dtmprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
4406 | "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf)); | ||
4407 | mpt_free_msg_frame(ioc, mf); | ||
4408 | if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) | ||
4409 | goto out; | ||
4410 | *issue_reset = 1; | ||
4411 | goto out; | ||
4412 | } | ||
3022 | 4413 | ||
3023 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 4414 | if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { |
3024 | if (!ev) | 4415 | retval = -1; /* return failure */ |
4416 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
4417 | "TaskMgmt request: failed with no reply\n", ioc->name)); | ||
4418 | goto out; | ||
4419 | } | ||
4420 | |||
4421 | out: | ||
4422 | CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) | ||
4423 | return retval; | ||
4424 | } | ||
4425 | |||
4426 | /** | ||
4427 | * mptsas_broadcast_primative_work - Handle broadcast primitives | ||
4428 | * @work: work queue payload containing info describing the event | ||
4429 | * | ||
4430 | * this will be handled in workqueue context. | ||
4431 | */ | ||
4432 | static void | ||
4433 | mptsas_broadcast_primative_work(struct fw_event_work *fw_event) | ||
4434 | { | ||
4435 | MPT_ADAPTER *ioc = fw_event->ioc; | ||
4436 | MPT_FRAME_HDR *mf; | ||
4437 | VirtDevice *vdevice; | ||
4438 | int ii; | ||
4439 | struct scsi_cmnd *sc; | ||
4440 | SCSITaskMgmtReply_t *pScsiTmReply; | ||
4441 | u8 issue_reset; | ||
4442 | int task_context; | ||
4443 | u8 channel, id; | ||
4444 | int lun; | ||
4445 | u32 termination_count; | ||
4446 | u32 query_count; | ||
4447 | |||
4448 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
4449 | "%s - enter\n", ioc->name, __func__)); | ||
4450 | |||
4451 | mutex_lock(&ioc->taskmgmt_cmds.mutex); | ||
4452 | if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { | ||
4453 | mutex_unlock(&ioc->taskmgmt_cmds.mutex); | ||
4454 | mptsas_requeue_fw_event(ioc, fw_event, 1000); | ||
3025 | return; | 4455 | return; |
3026 | INIT_WORK(&ev->work, mptsas_discovery_work); | 4456 | } |
3027 | ev->ioc = ioc; | 4457 | |
3028 | schedule_work(&ev->work); | 4458 | issue_reset = 0; |
3029 | }; | 4459 | termination_count = 0; |
4460 | query_count = 0; | ||
4461 | mpt_findImVolumes(ioc); | ||
4462 | pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; | ||
4463 | |||
4464 | for (ii = 0; ii < ioc->req_depth; ii++) { | ||
4465 | if (ioc->fw_events_off) | ||
4466 | goto out; | ||
4467 | sc = mptscsih_get_scsi_lookup(ioc, ii); | ||
4468 | if (!sc) | ||
4469 | continue; | ||
4470 | mf = MPT_INDEX_2_MFPTR(ioc, ii); | ||
4471 | if (!mf) | ||
4472 | continue; | ||
4473 | task_context = mf->u.frame.hwhdr.msgctxu.MsgContext; | ||
4474 | vdevice = sc->device->hostdata; | ||
4475 | if (!vdevice || !vdevice->vtarget) | ||
4476 | continue; | ||
4477 | if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) | ||
4478 | continue; /* skip hidden raid components */ | ||
4479 | if (vdevice->vtarget->raidVolume) | ||
4480 | continue; /* skip hidden raid components */ | ||
4481 | channel = vdevice->vtarget->channel; | ||
4482 | id = vdevice->vtarget->id; | ||
4483 | lun = vdevice->lun; | ||
4484 | if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK, | ||
4485 | channel, id, (u64)lun, task_context, 30, &issue_reset)) | ||
4486 | goto out; | ||
4487 | query_count++; | ||
4488 | termination_count += | ||
4489 | le32_to_cpu(pScsiTmReply->TerminationCount); | ||
4490 | if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) && | ||
4491 | (pScsiTmReply->ResponseCode == | ||
4492 | MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED || | ||
4493 | pScsiTmReply->ResponseCode == | ||
4494 | MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) | ||
4495 | continue; | ||
4496 | if (mptsas_issue_tm(ioc, | ||
4497 | MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, | ||
4498 | channel, id, (u64)lun, 0, 30, &issue_reset)) | ||
4499 | goto out; | ||
4500 | termination_count += | ||
4501 | le32_to_cpu(pScsiTmReply->TerminationCount); | ||
4502 | } | ||
4503 | |||
4504 | out: | ||
4505 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
4506 | "%s - exit, query_count = %d termination_count = %d\n", | ||
4507 | ioc->name, __func__, query_count, termination_count)); | ||
4508 | |||
4509 | ioc->broadcast_aen_busy = 0; | ||
4510 | mpt_clear_taskmgmt_in_progress_flag(ioc); | ||
4511 | mutex_unlock(&ioc->taskmgmt_cmds.mutex); | ||
4512 | |||
4513 | if (issue_reset) { | ||
4514 | printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", | ||
4515 | ioc->name, __func__); | ||
4516 | mpt_HardResetHandler(ioc, CAN_SLEEP); | ||
4517 | } | ||
4518 | mptsas_free_fw_event(ioc, fw_event); | ||
4519 | } | ||
3030 | 4520 | ||
3031 | /* | 4521 | /* |
3032 | * mptsas_send_ir2_event - handle exposing hidden disk when | 4522 | * mptsas_send_ir2_event - handle exposing hidden disk when |
@@ -3037,76 +4527,159 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc, | |||
3037 | * | 4527 | * |
3038 | */ | 4528 | */ |
3039 | static void | 4529 | static void |
3040 | mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data) | 4530 | mptsas_send_ir2_event(struct fw_event_work *fw_event) |
3041 | { | 4531 | { |
3042 | struct mptsas_hotplug_event *ev; | 4532 | MPT_ADAPTER *ioc; |
3043 | 4533 | struct mptsas_hotplug_event hot_plug_info; | |
3044 | if (ir2_data->ReasonCode != | 4534 | MPI_EVENT_DATA_IR2 *ir2_data; |
3045 | MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED) | 4535 | u8 reasonCode; |
3046 | return; | 4536 | RaidPhysDiskPage0_t phys_disk; |
3047 | 4537 | ||
3048 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 4538 | ioc = fw_event->ioc; |
3049 | if (!ev) | 4539 | ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data; |
4540 | reasonCode = ir2_data->ReasonCode; | ||
4541 | |||
4542 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " | ||
4543 | "ReasonCode=%02x\n", ioc->name, __func__, reasonCode)); | ||
4544 | |||
4545 | memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); | ||
4546 | hot_plug_info.id = ir2_data->TargetID; | ||
4547 | hot_plug_info.channel = ir2_data->Bus; | ||
4548 | switch (reasonCode) { | ||
4549 | case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: | ||
4550 | hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME; | ||
4551 | break; | ||
4552 | case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: | ||
4553 | hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; | ||
4554 | hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; | ||
4555 | break; | ||
4556 | case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: | ||
4557 | hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; | ||
4558 | mpt_raid_phys_disk_pg0(ioc, | ||
4559 | ir2_data->PhysDiskNum, &phys_disk); | ||
4560 | hot_plug_info.id = phys_disk.PhysDiskID; | ||
4561 | hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; | ||
4562 | break; | ||
4563 | default: | ||
4564 | mptsas_free_fw_event(ioc, fw_event); | ||
3050 | return; | 4565 | return; |
3051 | 4566 | } | |
3052 | INIT_WORK(&ev->work, mptsas_hotplug_work); | 4567 | mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); |
3053 | ev->ioc = ioc; | 4568 | } |
3054 | ev->id = ir2_data->TargetID; | ||
3055 | ev->channel = ir2_data->Bus; | ||
3056 | ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME; | ||
3057 | |||
3058 | schedule_work(&ev->work); | ||
3059 | }; | ||
3060 | 4569 | ||
3061 | static int | 4570 | static int |
3062 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | 4571 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) |
3063 | { | 4572 | { |
3064 | int rc=1; | 4573 | u32 event = le32_to_cpu(reply->Event); |
3065 | u8 event = le32_to_cpu(reply->Event) & 0xFF; | 4574 | int sz, event_data_sz; |
4575 | struct fw_event_work *fw_event; | ||
4576 | unsigned long delay; | ||
3066 | 4577 | ||
3067 | if (!ioc->sh) | 4578 | /* events turned off due to host reset or driver unloading */ |
3068 | goto out; | 4579 | if (ioc->fw_events_off) |
3069 | 4580 | return 0; | |
3070 | /* | ||
3071 | * sas_discovery_ignore_events | ||
3072 | * | ||
3073 | * This flag is to prevent anymore processing of | ||
3074 | * sas events once mptsas_remove function is called. | ||
3075 | */ | ||
3076 | if (ioc->sas_discovery_ignore_events) { | ||
3077 | rc = mptscsih_event_process(ioc, reply); | ||
3078 | goto out; | ||
3079 | } | ||
3080 | 4581 | ||
4582 | delay = msecs_to_jiffies(1); | ||
3081 | switch (event) { | 4583 | switch (event) { |
4584 | case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: | ||
4585 | { | ||
4586 | EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data = | ||
4587 | (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data; | ||
4588 | if (broadcast_event_data->Primitive != | ||
4589 | MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) | ||
4590 | return 0; | ||
4591 | if (ioc->broadcast_aen_busy) | ||
4592 | return 0; | ||
4593 | ioc->broadcast_aen_busy = 1; | ||
4594 | break; | ||
4595 | } | ||
3082 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | 4596 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: |
3083 | mptsas_send_sas_event(ioc, | 4597 | { |
3084 | (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); | 4598 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = |
4599 | (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data; | ||
4600 | |||
4601 | if (sas_event_data->ReasonCode == | ||
4602 | MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) { | ||
4603 | mptsas_target_reset_queue(ioc, sas_event_data); | ||
4604 | return 0; | ||
4605 | } | ||
3085 | break; | 4606 | break; |
3086 | case MPI_EVENT_INTEGRATED_RAID: | 4607 | } |
3087 | mptsas_send_raid_event(ioc, | 4608 | case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: |
3088 | (EVENT_DATA_RAID *)reply->Data); | 4609 | { |
4610 | MpiEventDataSasExpanderStatusChange_t *expander_data = | ||
4611 | (MpiEventDataSasExpanderStatusChange_t *)reply->Data; | ||
4612 | |||
4613 | if (ioc->old_sas_discovery_protocal) | ||
4614 | return 0; | ||
4615 | |||
4616 | if (expander_data->ReasonCode == | ||
4617 | MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING && | ||
4618 | ioc->device_missing_delay) | ||
4619 | delay = HZ * ioc->device_missing_delay; | ||
3089 | break; | 4620 | break; |
4621 | } | ||
4622 | case MPI_EVENT_SAS_DISCOVERY: | ||
4623 | { | ||
4624 | u32 discovery_status; | ||
4625 | EventDataSasDiscovery_t *discovery_data = | ||
4626 | (EventDataSasDiscovery_t *)reply->Data; | ||
4627 | |||
4628 | discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus); | ||
4629 | ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0; | ||
4630 | if (ioc->old_sas_discovery_protocal && !discovery_status) | ||
4631 | mptsas_queue_rescan(ioc); | ||
4632 | return 0; | ||
4633 | } | ||
4634 | case MPI_EVENT_INTEGRATED_RAID: | ||
3090 | case MPI_EVENT_PERSISTENT_TABLE_FULL: | 4635 | case MPI_EVENT_PERSISTENT_TABLE_FULL: |
3091 | INIT_WORK(&ioc->sas_persist_task, | ||
3092 | mptsas_persist_clear_table); | ||
3093 | schedule_work(&ioc->sas_persist_task); | ||
3094 | break; | ||
3095 | case MPI_EVENT_SAS_DISCOVERY: | ||
3096 | mptsas_send_discovery_event(ioc, | ||
3097 | (EVENT_DATA_SAS_DISCOVERY *)reply->Data); | ||
3098 | break; | ||
3099 | case MPI_EVENT_IR2: | 4636 | case MPI_EVENT_IR2: |
3100 | mptsas_send_ir2_event(ioc, | 4637 | case MPI_EVENT_SAS_PHY_LINK_STATUS: |
3101 | (PTR_MPI_EVENT_DATA_IR2)reply->Data); | 4638 | case MPI_EVENT_QUEUE_FULL: |
3102 | break; | 4639 | break; |
3103 | default: | 4640 | default: |
3104 | rc = mptscsih_event_process(ioc, reply); | 4641 | return 0; |
3105 | break; | ||
3106 | } | 4642 | } |
3107 | out: | ||
3108 | 4643 | ||
3109 | return rc; | 4644 | event_data_sz = ((reply->MsgLength * 4) - |
4645 | offsetof(EventNotificationReply_t, Data)); | ||
4646 | sz = offsetof(struct fw_event_work, event_data) + event_data_sz; | ||
4647 | fw_event = kzalloc(sz, GFP_ATOMIC); | ||
4648 | if (!fw_event) { | ||
4649 | printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name, | ||
4650 | __func__, __LINE__); | ||
4651 | return 0; | ||
4652 | } | ||
4653 | memcpy(fw_event->event_data, reply->Data, event_data_sz); | ||
4654 | fw_event->event = event; | ||
4655 | fw_event->ioc = ioc; | ||
4656 | mptsas_add_fw_event(ioc, fw_event, delay); | ||
4657 | return 0; | ||
4658 | } | ||
4659 | |||
4660 | /* Delete a volume when no longer listed in ioc pg2 | ||
4661 | */ | ||
4662 | static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id) | ||
4663 | { | ||
4664 | struct scsi_device *sdev; | ||
4665 | int i; | ||
4666 | |||
4667 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0); | ||
4668 | if (!sdev) | ||
4669 | return; | ||
4670 | if (!ioc->raid_data.pIocPg2) | ||
4671 | goto out; | ||
4672 | if (!ioc->raid_data.pIocPg2->NumActiveVolumes) | ||
4673 | goto out; | ||
4674 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) | ||
4675 | if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) | ||
4676 | goto release_sdev; | ||
4677 | out: | ||
4678 | printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " | ||
4679 | "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id); | ||
4680 | scsi_remove_device(sdev); | ||
4681 | release_sdev: | ||
4682 | scsi_device_put(sdev); | ||
3110 | } | 4683 | } |
3111 | 4684 | ||
3112 | static int | 4685 | static int |
@@ -3128,6 +4701,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3128 | return r; | 4701 | return r; |
3129 | 4702 | ||
3130 | ioc = pci_get_drvdata(pdev); | 4703 | ioc = pci_get_drvdata(pdev); |
4704 | mptsas_fw_event_off(ioc); | ||
3131 | ioc->DoneCtx = mptsasDoneCtx; | 4705 | ioc->DoneCtx = mptsasDoneCtx; |
3132 | ioc->TaskCtx = mptsasTaskCtx; | 4706 | ioc->TaskCtx = mptsasTaskCtx; |
3133 | ioc->InternalCtx = mptsasInternalCtx; | 4707 | ioc->InternalCtx = mptsasInternalCtx; |
@@ -3211,17 +4785,15 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3211 | * A slightly different algorithm is required for | 4785 | * A slightly different algorithm is required for |
3212 | * 64bit SGEs. | 4786 | * 64bit SGEs. |
3213 | */ | 4787 | */ |
3214 | scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); | 4788 | scale = ioc->req_sz/ioc->SGE_size; |
3215 | if (sizeof(dma_addr_t) == sizeof(u64)) { | 4789 | if (ioc->sg_addr_size == sizeof(u64)) { |
3216 | numSGE = (scale - 1) * | 4790 | numSGE = (scale - 1) * |
3217 | (ioc->facts.MaxChainDepth-1) + scale + | 4791 | (ioc->facts.MaxChainDepth-1) + scale + |
3218 | (ioc->req_sz - 60) / (sizeof(dma_addr_t) + | 4792 | (ioc->req_sz - 60) / ioc->SGE_size; |
3219 | sizeof(u32)); | ||
3220 | } else { | 4793 | } else { |
3221 | numSGE = 1 + (scale - 1) * | 4794 | numSGE = 1 + (scale - 1) * |
3222 | (ioc->facts.MaxChainDepth-1) + scale + | 4795 | (ioc->facts.MaxChainDepth-1) + scale + |
3223 | (ioc->req_sz - 64) / (sizeof(dma_addr_t) + | 4796 | (ioc->req_sz - 64) / ioc->SGE_size; |
3224 | sizeof(u32)); | ||
3225 | } | 4797 | } |
3226 | 4798 | ||
3227 | if (numSGE < sh->sg_tablesize) { | 4799 | if (numSGE < sh->sg_tablesize) { |
@@ -3251,9 +4823,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3251 | 4823 | ||
3252 | /* Clear the TM flags | 4824 | /* Clear the TM flags |
3253 | */ | 4825 | */ |
3254 | hd->tmPending = 0; | ||
3255 | hd->tmState = TM_STATE_NONE; | ||
3256 | hd->resetPending = 0; | ||
3257 | hd->abortSCpnt = NULL; | 4826 | hd->abortSCpnt = NULL; |
3258 | 4827 | ||
3259 | /* Clear the pointer used to store | 4828 | /* Clear the pointer used to store |
@@ -3273,10 +4842,11 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3273 | 4842 | ||
3274 | ioc->sas_data.ptClear = mpt_pt_clear; | 4843 | ioc->sas_data.ptClear = mpt_pt_clear; |
3275 | 4844 | ||
3276 | init_waitqueue_head(&hd->scandv_waitq); | ||
3277 | hd->scandv_wait_done = 0; | ||
3278 | hd->last_queue_full = 0; | 4845 | hd->last_queue_full = 0; |
3279 | INIT_LIST_HEAD(&hd->target_reset_list); | 4846 | INIT_LIST_HEAD(&hd->target_reset_list); |
4847 | INIT_LIST_HEAD(&ioc->sas_device_info_list); | ||
4848 | mutex_init(&ioc->sas_device_info_mutex); | ||
4849 | |||
3280 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); | 4850 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); |
3281 | 4851 | ||
3282 | if (ioc->sas_data.ptClear==1) { | 4852 | if (ioc->sas_data.ptClear==1) { |
@@ -3291,8 +4861,11 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3291 | goto out_mptsas_probe; | 4861 | goto out_mptsas_probe; |
3292 | } | 4862 | } |
3293 | 4863 | ||
4864 | /* older firmware doesn't support expander events */ | ||
4865 | if ((ioc->facts.HeaderVersion >> 8) < 0xE) | ||
4866 | ioc->old_sas_discovery_protocal = 1; | ||
3294 | mptsas_scan_sas_topology(ioc); | 4867 | mptsas_scan_sas_topology(ioc); |
3295 | 4868 | mptsas_fw_event_on(ioc); | |
3296 | return 0; | 4869 | return 0; |
3297 | 4870 | ||
3298 | out_mptsas_probe: | 4871 | out_mptsas_probe: |
@@ -3301,12 +4874,25 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3301 | return error; | 4874 | return error; |
3302 | } | 4875 | } |
3303 | 4876 | ||
4877 | void | ||
4878 | mptsas_shutdown(struct pci_dev *pdev) | ||
4879 | { | ||
4880 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | ||
4881 | |||
4882 | mptsas_fw_event_off(ioc); | ||
4883 | mptsas_cleanup_fw_event_q(ioc); | ||
4884 | } | ||
4885 | |||
3304 | static void __devexit mptsas_remove(struct pci_dev *pdev) | 4886 | static void __devexit mptsas_remove(struct pci_dev *pdev) |
3305 | { | 4887 | { |
3306 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | 4888 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
3307 | struct mptsas_portinfo *p, *n; | 4889 | struct mptsas_portinfo *p, *n; |
3308 | int i; | 4890 | int i; |
3309 | 4891 | ||
4892 | mptsas_shutdown(pdev); | ||
4893 | |||
4894 | mptsas_del_device_components(ioc); | ||
4895 | |||
3310 | ioc->sas_discovery_ignore_events = 1; | 4896 | ioc->sas_discovery_ignore_events = 1; |
3311 | sas_remove_host(ioc->sh); | 4897 | sas_remove_host(ioc->sh); |
3312 | 4898 | ||
@@ -3315,11 +4901,12 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) | |||
3315 | list_del(&p->list); | 4901 | list_del(&p->list); |
3316 | for (i = 0 ; i < p->num_phys ; i++) | 4902 | for (i = 0 ; i < p->num_phys ; i++) |
3317 | mptsas_port_delete(ioc, p->phy_info[i].port_details); | 4903 | mptsas_port_delete(ioc, p->phy_info[i].port_details); |
4904 | |||
3318 | kfree(p->phy_info); | 4905 | kfree(p->phy_info); |
3319 | kfree(p); | 4906 | kfree(p); |
3320 | } | 4907 | } |
3321 | mutex_unlock(&ioc->sas_topology_mutex); | 4908 | mutex_unlock(&ioc->sas_topology_mutex); |
3322 | 4909 | ioc->hba_port_info = NULL; | |
3323 | mptscsih_remove(pdev); | 4910 | mptscsih_remove(pdev); |
3324 | } | 4911 | } |
3325 | 4912 | ||
@@ -3344,7 +4931,7 @@ static struct pci_driver mptsas_driver = { | |||
3344 | .id_table = mptsas_pci_table, | 4931 | .id_table = mptsas_pci_table, |
3345 | .probe = mptsas_probe, | 4932 | .probe = mptsas_probe, |
3346 | .remove = __devexit_p(mptsas_remove), | 4933 | .remove = __devexit_p(mptsas_remove), |
3347 | .shutdown = mptscsih_shutdown, | 4934 | .shutdown = mptsas_shutdown, |
3348 | #ifdef CONFIG_PM | 4935 | #ifdef CONFIG_PM |
3349 | .suspend = mptscsih_suspend, | 4936 | .suspend = mptscsih_suspend, |
3350 | .resume = mptscsih_resume, | 4937 | .resume = mptscsih_resume, |
@@ -3364,10 +4951,12 @@ mptsas_init(void) | |||
3364 | return -ENODEV; | 4951 | return -ENODEV; |
3365 | 4952 | ||
3366 | mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER); | 4953 | mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER); |
3367 | mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER); | 4954 | mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER); |
3368 | mptsasInternalCtx = | 4955 | mptsasInternalCtx = |
3369 | mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); | 4956 | mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); |
3370 | mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); | 4957 | mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); |
4958 | mptsasDeviceResetCtx = | ||
4959 | mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER); | ||
3371 | 4960 | ||
3372 | mpt_event_register(mptsasDoneCtx, mptsas_event_process); | 4961 | mpt_event_register(mptsasDoneCtx, mptsas_event_process); |
3373 | mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset); | 4962 | mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset); |
@@ -3392,6 +4981,7 @@ mptsas_exit(void) | |||
3392 | mpt_deregister(mptsasInternalCtx); | 4981 | mpt_deregister(mptsasInternalCtx); |
3393 | mpt_deregister(mptsasTaskCtx); | 4982 | mpt_deregister(mptsasTaskCtx); |
3394 | mpt_deregister(mptsasDoneCtx); | 4983 | mpt_deregister(mptsasDoneCtx); |
4984 | mpt_deregister(mptsasDeviceResetCtx); | ||
3395 | } | 4985 | } |
3396 | 4986 | ||
3397 | module_init(mptsas_init); | 4987 | module_init(mptsas_init); |