diff options
Diffstat (limited to 'drivers/scsi/mpt2sas')
-rw-r--r-- | drivers/scsi/mpt2sas/Kconfig | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2.h | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_history.txt | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_init.h | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_tool.h | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 90 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 36 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_config.c | 8 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 46 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.h | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_debug.h | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 1055 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_transport.c | 89 |
15 files changed, 852 insertions, 490 deletions
diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig index ba8e128de238..bbb7e4bf30a3 100644 --- a/drivers/scsi/mpt2sas/Kconfig +++ b/drivers/scsi/mpt2sas/Kconfig | |||
@@ -2,7 +2,7 @@ | |||
2 | # Kernel configuration file for the MPT2SAS | 2 | # Kernel configuration file for the MPT2SAS |
3 | # | 3 | # |
4 | # This code is based on drivers/scsi/mpt2sas/Kconfig | 4 | # This code is based on drivers/scsi/mpt2sas/Kconfig |
5 | # Copyright (C) 2007-2009 LSI Corporation | 5 | # Copyright (C) 2007-2010 LSI Corporation |
6 | # (mailto:DL-MPTFusionLinux@lsi.com) | 6 | # (mailto:DL-MPTFusionLinux@lsi.com) |
7 | 7 | ||
8 | # This program is free software; you can redistribute it and/or | 8 | # This program is free software; you can redistribute it and/or |
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 9958d847a88d..dada0a13223f 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2009 LSI Corporation. | 2 | * Copyright (c) 2000-2010 LSI Corporation. |
3 | * | 3 | * |
4 | * | 4 | * |
5 | * Name: mpi2.h | 5 | * Name: mpi2.h |
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index cf0ac9f40c97..d4e9d6f8452e 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2009 LSI Corporation. | 2 | * Copyright (c) 2000-2010 LSI Corporation. |
3 | * | 3 | * |
4 | * | 4 | * |
5 | * Name: mpi2_cnfg.h | 5 | * Name: mpi2_cnfg.h |
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt index c4adf76b49d9..bd6c92b5fae5 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt +++ b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt | |||
@@ -2,7 +2,7 @@ | |||
2 | Fusion-MPT MPI 2.0 Header File Change History | 2 | Fusion-MPT MPI 2.0 Header File Change History |
3 | ============================== | 3 | ============================== |
4 | 4 | ||
5 | Copyright (c) 2000-2009 LSI Corporation. | 5 | Copyright (c) 2000-2010 LSI Corporation. |
6 | 6 | ||
7 | --------------------------------------- | 7 | --------------------------------------- |
8 | Header Set Release Version: 02.00.14 | 8 | Header Set Release Version: 02.00.14 |
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h index 6541945e97c3..220bf65a9216 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2009 LSI Corporation. | 2 | * Copyright (c) 2000-2010 LSI Corporation. |
3 | * | 3 | * |
4 | * | 4 | * |
5 | * Name: mpi2_init.h | 5 | * Name: mpi2_init.h |
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 754938422f6a..f18f114922ba 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2009 LSI Corporation. | 2 | * Copyright (c) 2000-2010 LSI Corporation. |
3 | * | 3 | * |
4 | * | 4 | * |
5 | * Name: mpi2_ioc.h | 5 | * Name: mpi2_ioc.h |
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h index 73fcdbf92632..686b09b81219 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2009 LSI Corporation. | 2 | * Copyright (c) 2000-2010 LSI Corporation. |
3 | * | 3 | * |
4 | * | 4 | * |
5 | * Name: mpi2_tool.h | 5 | * Name: mpi2_tool.h |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 88e6eebc3159..b830d61684dd 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * for access to MPT (Message Passing Technology) firmware. | 3 | * for access to MPT (Message Passing Technology) firmware. |
4 | * | 4 | * |
5 | * This code is based on drivers/scsi/mpt2sas/mpt2_base.c | 5 | * This code is based on drivers/scsi/mpt2sas/mpt2_base.c |
6 | * Copyright (C) 2007-2009 LSI Corporation | 6 | * Copyright (C) 2007-2010 LSI Corporation |
7 | * (mailto:DL-MPTFusionLinux@lsi.com) | 7 | * (mailto:DL-MPTFusionLinux@lsi.com) |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
@@ -58,6 +58,7 @@ | |||
58 | #include <linux/sort.h> | 58 | #include <linux/sort.h> |
59 | #include <linux/io.h> | 59 | #include <linux/io.h> |
60 | #include <linux/time.h> | 60 | #include <linux/time.h> |
61 | #include <linux/aer.h> | ||
61 | 62 | ||
62 | #include "mpt2sas_base.h" | 63 | #include "mpt2sas_base.h" |
63 | 64 | ||
@@ -285,6 +286,9 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, | |||
285 | request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION) | 286 | request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION) |
286 | return; | 287 | return; |
287 | 288 | ||
289 | if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) | ||
290 | return; | ||
291 | |||
288 | switch (ioc_status) { | 292 | switch (ioc_status) { |
289 | 293 | ||
290 | /**************************************************************************** | 294 | /**************************************************************************** |
@@ -517,8 +521,18 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, | |||
517 | desc = "IR Operation Status"; | 521 | desc = "IR Operation Status"; |
518 | break; | 522 | break; |
519 | case MPI2_EVENT_SAS_DISCOVERY: | 523 | case MPI2_EVENT_SAS_DISCOVERY: |
520 | desc = "Discovery"; | 524 | { |
521 | break; | 525 | Mpi2EventDataSasDiscovery_t *event_data = |
526 | (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData; | ||
527 | printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name, | ||
528 | (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? | ||
529 | "start" : "stop"); | ||
530 | if (event_data->DiscoveryStatus) | ||
531 | printk("discovery_status(0x%08x)", | ||
532 | le32_to_cpu(event_data->DiscoveryStatus)); | ||
533 | printk("\n"); | ||
534 | return; | ||
535 | } | ||
522 | case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: | 536 | case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: |
523 | desc = "SAS Broadcast Primitive"; | 537 | desc = "SAS Broadcast Primitive"; |
524 | break; | 538 | break; |
@@ -1243,6 +1257,9 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) | |||
1243 | goto out_fail; | 1257 | goto out_fail; |
1244 | } | 1258 | } |
1245 | 1259 | ||
1260 | /* AER (Advanced Error Reporting) hooks */ | ||
1261 | pci_enable_pcie_error_reporting(pdev); | ||
1262 | |||
1246 | pci_set_master(pdev); | 1263 | pci_set_master(pdev); |
1247 | 1264 | ||
1248 | if (_base_config_dma_addressing(ioc, pdev) != 0) { | 1265 | if (_base_config_dma_addressing(ioc, pdev) != 0) { |
@@ -1253,7 +1270,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) | |||
1253 | } | 1270 | } |
1254 | 1271 | ||
1255 | for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) { | 1272 | for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) { |
1256 | if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { | 1273 | if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { |
1257 | if (pio_sz) | 1274 | if (pio_sz) |
1258 | continue; | 1275 | continue; |
1259 | pio_chip = (u64)pci_resource_start(pdev, i); | 1276 | pio_chip = (u64)pci_resource_start(pdev, i); |
@@ -1261,15 +1278,18 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) | |||
1261 | } else { | 1278 | } else { |
1262 | if (memap_sz) | 1279 | if (memap_sz) |
1263 | continue; | 1280 | continue; |
1264 | ioc->chip_phys = pci_resource_start(pdev, i); | 1281 | /* verify memory resource is valid before using */ |
1265 | chip_phys = (u64)ioc->chip_phys; | 1282 | if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { |
1266 | memap_sz = pci_resource_len(pdev, i); | 1283 | ioc->chip_phys = pci_resource_start(pdev, i); |
1267 | ioc->chip = ioremap(ioc->chip_phys, memap_sz); | 1284 | chip_phys = (u64)ioc->chip_phys; |
1268 | if (ioc->chip == NULL) { | 1285 | memap_sz = pci_resource_len(pdev, i); |
1269 | printk(MPT2SAS_ERR_FMT "unable to map adapter " | 1286 | ioc->chip = ioremap(ioc->chip_phys, memap_sz); |
1270 | "memory!\n", ioc->name); | 1287 | if (ioc->chip == NULL) { |
1271 | r = -EINVAL; | 1288 | printk(MPT2SAS_ERR_FMT "unable to map " |
1272 | goto out_fail; | 1289 | "adapter memory!\n", ioc->name); |
1290 | r = -EINVAL; | ||
1291 | goto out_fail; | ||
1292 | } | ||
1273 | } | 1293 | } |
1274 | } | 1294 | } |
1275 | } | 1295 | } |
@@ -1295,6 +1315,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) | |||
1295 | ioc->chip_phys = 0; | 1315 | ioc->chip_phys = 0; |
1296 | ioc->pci_irq = -1; | 1316 | ioc->pci_irq = -1; |
1297 | pci_release_selected_regions(ioc->pdev, ioc->bars); | 1317 | pci_release_selected_regions(ioc->pdev, ioc->bars); |
1318 | pci_disable_pcie_error_reporting(pdev); | ||
1298 | pci_disable_device(pdev); | 1319 | pci_disable_device(pdev); |
1299 | return r; | 1320 | return r; |
1300 | } | 1321 | } |
@@ -1898,7 +1919,10 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) | |||
1898 | ioc->config_page, ioc->config_page_dma); | 1919 | ioc->config_page, ioc->config_page_dma); |
1899 | } | 1920 | } |
1900 | 1921 | ||
1901 | kfree(ioc->scsi_lookup); | 1922 | if (ioc->scsi_lookup) { |
1923 | free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages); | ||
1924 | ioc->scsi_lookup = NULL; | ||
1925 | } | ||
1902 | kfree(ioc->hpr_lookup); | 1926 | kfree(ioc->hpr_lookup); |
1903 | kfree(ioc->internal_lookup); | 1927 | kfree(ioc->internal_lookup); |
1904 | } | 1928 | } |
@@ -2110,11 +2134,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
2110 | ioc->name, (unsigned long long) ioc->request_dma)); | 2134 | ioc->name, (unsigned long long) ioc->request_dma)); |
2111 | total_sz += sz; | 2135 | total_sz += sz; |
2112 | 2136 | ||
2113 | ioc->scsi_lookup = kcalloc(ioc->scsiio_depth, | 2137 | sz = ioc->scsiio_depth * sizeof(struct request_tracker); |
2114 | sizeof(struct request_tracker), GFP_KERNEL); | 2138 | ioc->scsi_lookup_pages = get_order(sz); |
2139 | ioc->scsi_lookup = (struct request_tracker *)__get_free_pages( | ||
2140 | GFP_KERNEL, ioc->scsi_lookup_pages); | ||
2115 | if (!ioc->scsi_lookup) { | 2141 | if (!ioc->scsi_lookup) { |
2116 | printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n", | 2142 | printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, " |
2117 | ioc->name); | 2143 | "sz(%d)\n", ioc->name, (int)sz); |
2118 | goto out; | 2144 | goto out; |
2119 | } | 2145 | } |
2120 | 2146 | ||
@@ -3006,8 +3032,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
3006 | * since epoch ~ midnight January 1, 1970. | 3032 | * since epoch ~ midnight January 1, 1970. |
3007 | */ | 3033 | */ |
3008 | do_gettimeofday(¤t_time); | 3034 | do_gettimeofday(¤t_time); |
3009 | mpi_request.TimeStamp = (current_time.tv_sec * 1000) + | 3035 | mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 + |
3010 | (current_time.tv_usec >> 3); | 3036 | (current_time.tv_usec / 1000)); |
3011 | 3037 | ||
3012 | if (ioc->logging_level & MPT_DEBUG_INIT) { | 3038 | if (ioc->logging_level & MPT_DEBUG_INIT) { |
3013 | u32 *mfp; | 3039 | u32 *mfp; |
@@ -3179,7 +3205,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
3179 | mpi_request->VP_ID = 0; | 3205 | mpi_request->VP_ID = 0; |
3180 | for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) | 3206 | for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) |
3181 | mpi_request->EventMasks[i] = | 3207 | mpi_request->EventMasks[i] = |
3182 | le32_to_cpu(ioc->event_masks[i]); | 3208 | cpu_to_le32(ioc->event_masks[i]); |
3183 | mpt2sas_base_put_smid_default(ioc, smid); | 3209 | mpt2sas_base_put_smid_default(ioc, smid); |
3184 | init_completion(&ioc->base_cmds.done); | 3210 | init_completion(&ioc->base_cmds.done); |
3185 | timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); | 3211 | timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); |
@@ -3516,7 +3542,9 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) | |||
3516 | __func__)); | 3542 | __func__)); |
3517 | 3543 | ||
3518 | _base_mask_interrupts(ioc); | 3544 | _base_mask_interrupts(ioc); |
3545 | ioc->shost_recovery = 1; | ||
3519 | _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); | 3546 | _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); |
3547 | ioc->shost_recovery = 0; | ||
3520 | if (ioc->pci_irq) { | 3548 | if (ioc->pci_irq) { |
3521 | synchronize_irq(pdev->irq); | 3549 | synchronize_irq(pdev->irq); |
3522 | free_irq(ioc->pci_irq, ioc); | 3550 | free_irq(ioc->pci_irq, ioc); |
@@ -3527,6 +3555,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) | |||
3527 | ioc->pci_irq = -1; | 3555 | ioc->pci_irq = -1; |
3528 | ioc->chip_phys = 0; | 3556 | ioc->chip_phys = 0; |
3529 | pci_release_selected_regions(ioc->pdev, ioc->bars); | 3557 | pci_release_selected_regions(ioc->pdev, ioc->bars); |
3558 | pci_disable_pcie_error_reporting(pdev); | ||
3530 | pci_disable_device(pdev); | 3559 | pci_disable_device(pdev); |
3531 | return; | 3560 | return; |
3532 | } | 3561 | } |
@@ -3560,8 +3589,10 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) | |||
3560 | 3589 | ||
3561 | ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, | 3590 | ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, |
3562 | sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); | 3591 | sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); |
3563 | if (!ioc->pfacts) | 3592 | if (!ioc->pfacts) { |
3593 | r = -ENOMEM; | ||
3564 | goto out_free_resources; | 3594 | goto out_free_resources; |
3595 | } | ||
3565 | 3596 | ||
3566 | for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { | 3597 | for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { |
3567 | r = _base_get_port_facts(ioc, i, CAN_SLEEP); | 3598 | r = _base_get_port_facts(ioc, i, CAN_SLEEP); |
@@ -3607,6 +3638,15 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) | |||
3607 | ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; | 3638 | ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; |
3608 | mutex_init(&ioc->ctl_cmds.mutex); | 3639 | mutex_init(&ioc->ctl_cmds.mutex); |
3609 | 3640 | ||
3641 | if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || | ||
3642 | !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || | ||
3643 | !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) { | ||
3644 | r = -ENOMEM; | ||
3645 | goto out_free_resources; | ||
3646 | } | ||
3647 | |||
3648 | init_completion(&ioc->shost_recovery_done); | ||
3649 | |||
3610 | for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) | 3650 | for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) |
3611 | ioc->event_masks[i] = -1; | 3651 | ioc->event_masks[i] = -1; |
3612 | 3652 | ||
@@ -3639,6 +3679,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) | |||
3639 | pci_set_drvdata(ioc->pdev, NULL); | 3679 | pci_set_drvdata(ioc->pdev, NULL); |
3640 | kfree(ioc->tm_cmds.reply); | 3680 | kfree(ioc->tm_cmds.reply); |
3641 | kfree(ioc->transport_cmds.reply); | 3681 | kfree(ioc->transport_cmds.reply); |
3682 | kfree(ioc->scsih_cmds.reply); | ||
3642 | kfree(ioc->config_cmds.reply); | 3683 | kfree(ioc->config_cmds.reply); |
3643 | kfree(ioc->base_cmds.reply); | 3684 | kfree(ioc->base_cmds.reply); |
3644 | kfree(ioc->ctl_cmds.reply); | 3685 | kfree(ioc->ctl_cmds.reply); |
@@ -3646,6 +3687,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) | |||
3646 | ioc->ctl_cmds.reply = NULL; | 3687 | ioc->ctl_cmds.reply = NULL; |
3647 | ioc->base_cmds.reply = NULL; | 3688 | ioc->base_cmds.reply = NULL; |
3648 | ioc->tm_cmds.reply = NULL; | 3689 | ioc->tm_cmds.reply = NULL; |
3690 | ioc->scsih_cmds.reply = NULL; | ||
3649 | ioc->transport_cmds.reply = NULL; | 3691 | ioc->transport_cmds.reply = NULL; |
3650 | ioc->config_cmds.reply = NULL; | 3692 | ioc->config_cmds.reply = NULL; |
3651 | ioc->pfacts = NULL; | 3693 | ioc->pfacts = NULL; |
@@ -3675,6 +3717,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) | |||
3675 | kfree(ioc->base_cmds.reply); | 3717 | kfree(ioc->base_cmds.reply); |
3676 | kfree(ioc->tm_cmds.reply); | 3718 | kfree(ioc->tm_cmds.reply); |
3677 | kfree(ioc->transport_cmds.reply); | 3719 | kfree(ioc->transport_cmds.reply); |
3720 | kfree(ioc->scsih_cmds.reply); | ||
3678 | kfree(ioc->config_cmds.reply); | 3721 | kfree(ioc->config_cmds.reply); |
3679 | } | 3722 | } |
3680 | 3723 | ||
@@ -3811,9 +3854,8 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, | |||
3811 | 3854 | ||
3812 | spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); | 3855 | spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); |
3813 | ioc->shost_recovery = 0; | 3856 | ioc->shost_recovery = 0; |
3857 | complete(&ioc->shost_recovery_done); | ||
3814 | spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); | 3858 | spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); |
3815 | 3859 | ||
3816 | if (!r) | ||
3817 | _base_reset_handler(ioc, MPT2_IOC_RUNNING); | ||
3818 | return r; | 3860 | return r; |
3819 | } | 3861 | } |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index e18b0544c38f..b4afe431ac1e 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h | |||
@@ -3,7 +3,7 @@ | |||
3 | * for access to MPT (Message Passing Technology) firmware. | 3 | * for access to MPT (Message Passing Technology) firmware. |
4 | * | 4 | * |
5 | * This code is based on drivers/scsi/mpt2sas/mpt2_base.h | 5 | * This code is based on drivers/scsi/mpt2sas/mpt2_base.h |
6 | * Copyright (C) 2007-2009 LSI Corporation | 6 | * Copyright (C) 2007-2010 LSI Corporation |
7 | * (mailto:DL-MPTFusionLinux@lsi.com) | 7 | * (mailto:DL-MPTFusionLinux@lsi.com) |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
@@ -69,11 +69,11 @@ | |||
69 | #define MPT2SAS_DRIVER_NAME "mpt2sas" | 69 | #define MPT2SAS_DRIVER_NAME "mpt2sas" |
70 | #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>" | 70 | #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>" |
71 | #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" | 71 | #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" |
72 | #define MPT2SAS_DRIVER_VERSION "04.100.01.00" | 72 | #define MPT2SAS_DRIVER_VERSION "05.100.00.02" |
73 | #define MPT2SAS_MAJOR_VERSION 04 | 73 | #define MPT2SAS_MAJOR_VERSION 05 |
74 | #define MPT2SAS_MINOR_VERSION 100 | 74 | #define MPT2SAS_MINOR_VERSION 100 |
75 | #define MPT2SAS_BUILD_VERSION 01 | 75 | #define MPT2SAS_BUILD_VERSION 00 |
76 | #define MPT2SAS_RELEASE_VERSION 00 | 76 | #define MPT2SAS_RELEASE_VERSION 02 |
77 | 77 | ||
78 | /* | 78 | /* |
79 | * Set MPT2SAS_SG_DEPTH value based on user input. | 79 | * Set MPT2SAS_SG_DEPTH value based on user input. |
@@ -119,7 +119,6 @@ | |||
119 | #define MPT2_IOC_PRE_RESET 1 /* prior to host reset */ | 119 | #define MPT2_IOC_PRE_RESET 1 /* prior to host reset */ |
120 | #define MPT2_IOC_AFTER_RESET 2 /* just after host reset */ | 120 | #define MPT2_IOC_AFTER_RESET 2 /* just after host reset */ |
121 | #define MPT2_IOC_DONE_RESET 3 /* links re-initialized */ | 121 | #define MPT2_IOC_DONE_RESET 3 /* links re-initialized */ |
122 | #define MPT2_IOC_RUNNING 4 /* shost running */ | ||
123 | 122 | ||
124 | /* | 123 | /* |
125 | * logging format | 124 | * logging format |
@@ -260,16 +259,6 @@ struct _internal_cmd { | |||
260 | u16 smid; | 259 | u16 smid; |
261 | }; | 260 | }; |
262 | 261 | ||
263 | /* | ||
264 | * SAS Topology Structures | ||
265 | */ | ||
266 | |||
267 | #define MPTSAS_STATE_TR_SEND 0x0001 | ||
268 | #define MPTSAS_STATE_TR_COMPLETE 0x0002 | ||
269 | #define MPTSAS_STATE_CNTRL_SEND 0x0004 | ||
270 | #define MPTSAS_STATE_CNTRL_COMPLETE 0x0008 | ||
271 | |||
272 | #define MPT2SAS_REQ_SAS_CNTRL 0x0010 | ||
273 | 262 | ||
274 | /** | 263 | /** |
275 | * struct _sas_device - attached device information | 264 | * struct _sas_device - attached device information |
@@ -307,7 +296,6 @@ struct _sas_device { | |||
307 | u16 slot; | 296 | u16 slot; |
308 | u8 hidden_raid_component; | 297 | u8 hidden_raid_component; |
309 | u8 responding; | 298 | u8 responding; |
310 | u16 state; | ||
311 | }; | 299 | }; |
312 | 300 | ||
313 | /** | 301 | /** |
@@ -378,6 +366,7 @@ struct _sas_port { | |||
378 | * @phy_id: unique phy id | 366 | * @phy_id: unique phy id |
379 | * @handle: device handle for this phy | 367 | * @handle: device handle for this phy |
380 | * @attached_handle: device handle for attached device | 368 | * @attached_handle: device handle for attached device |
369 | * @phy_belongs_to_port: port has been created for this phy | ||
381 | */ | 370 | */ |
382 | struct _sas_phy { | 371 | struct _sas_phy { |
383 | struct list_head port_siblings; | 372 | struct list_head port_siblings; |
@@ -387,6 +376,7 @@ struct _sas_phy { | |||
387 | u8 phy_id; | 376 | u8 phy_id; |
388 | u16 handle; | 377 | u16 handle; |
389 | u16 attached_handle; | 378 | u16 attached_handle; |
379 | u8 phy_belongs_to_port; | ||
390 | }; | 380 | }; |
391 | 381 | ||
392 | /** | 382 | /** |
@@ -603,7 +593,6 @@ struct MPT2SAS_ADAPTER { | |||
603 | /* fw event handler */ | 593 | /* fw event handler */ |
604 | char firmware_event_name[20]; | 594 | char firmware_event_name[20]; |
605 | struct workqueue_struct *firmware_event_thread; | 595 | struct workqueue_struct *firmware_event_thread; |
606 | u8 fw_events_off; | ||
607 | spinlock_t fw_event_lock; | 596 | spinlock_t fw_event_lock; |
608 | struct list_head fw_event_list; | 597 | struct list_head fw_event_list; |
609 | 598 | ||
@@ -611,6 +600,7 @@ struct MPT2SAS_ADAPTER { | |||
611 | int aen_event_read_flag; | 600 | int aen_event_read_flag; |
612 | u8 broadcast_aen_busy; | 601 | u8 broadcast_aen_busy; |
613 | u8 shost_recovery; | 602 | u8 shost_recovery; |
603 | struct completion shost_recovery_done; | ||
614 | spinlock_t ioc_reset_in_progress_lock; | 604 | spinlock_t ioc_reset_in_progress_lock; |
615 | u8 ioc_link_reset_in_progress; | 605 | u8 ioc_link_reset_in_progress; |
616 | u8 ignore_loginfos; | 606 | u8 ignore_loginfos; |
@@ -688,7 +678,8 @@ struct MPT2SAS_ADAPTER { | |||
688 | dma_addr_t request_dma; | 678 | dma_addr_t request_dma; |
689 | u32 request_dma_sz; | 679 | u32 request_dma_sz; |
690 | struct request_tracker *scsi_lookup; | 680 | struct request_tracker *scsi_lookup; |
691 | spinlock_t scsi_lookup_lock; | 681 | ulong scsi_lookup_pages; |
682 | spinlock_t scsi_lookup_lock; | ||
692 | struct list_head free_list; | 683 | struct list_head free_list; |
693 | int pending_io_count; | 684 | int pending_io_count; |
694 | wait_queue_head_t reset_wq; | 685 | wait_queue_head_t reset_wq; |
@@ -700,7 +691,7 @@ struct MPT2SAS_ADAPTER { | |||
700 | u16 max_sges_in_chain_message; | 691 | u16 max_sges_in_chain_message; |
701 | u16 chains_needed_per_io; | 692 | u16 chains_needed_per_io; |
702 | u16 chain_offset_value_for_main_message; | 693 | u16 chain_offset_value_for_main_message; |
703 | u16 chain_depth; | 694 | u32 chain_depth; |
704 | 695 | ||
705 | /* hi-priority queue */ | 696 | /* hi-priority queue */ |
706 | u16 hi_priority_smid; | 697 | u16 hi_priority_smid; |
@@ -814,8 +805,9 @@ void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc); | |||
814 | /* scsih shared API */ | 805 | /* scsih shared API */ |
815 | u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, | 806 | u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, |
816 | u32 reply); | 807 | u32 reply); |
817 | void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, | 808 | int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, |
818 | u8 type, u16 smid_task, ulong timeout); | 809 | uint channel, uint id, uint lun, u8 type, u16 smid_task, |
810 | ulong timeout, struct scsi_cmnd *scmd); | ||
819 | void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); | 811 | void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); |
820 | void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); | 812 | void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); |
821 | struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, | 813 | struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index cf44b355bc97..e762dd3e2fcb 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * This module provides common API for accessing firmware configuration pages | 2 | * This module provides common API for accessing firmware configuration pages |
3 | * | 3 | * |
4 | * This code is based on drivers/scsi/mpt2sas/mpt2_base.c | 4 | * This code is based on drivers/scsi/mpt2sas/mpt2_base.c |
5 | * Copyright (C) 2007-2009 LSI Corporation | 5 | * Copyright (C) 2007-2010 LSI Corporation |
6 | * (mailto:DL-MPTFusionLinux@lsi.com) | 6 | * (mailto:DL-MPTFusionLinux@lsi.com) |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
@@ -1390,12 +1390,12 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, | |||
1390 | if (ioc_status != MPI2_IOCSTATUS_SUCCESS) | 1390 | if (ioc_status != MPI2_IOCSTATUS_SUCCESS) |
1391 | goto out; | 1391 | goto out; |
1392 | for (i = 0; i < config_page->NumElements; i++) { | 1392 | for (i = 0; i < config_page->NumElements; i++) { |
1393 | if ((config_page->ConfigElement[i].ElementFlags & | 1393 | if ((le16_to_cpu(config_page->ConfigElement[i].ElementFlags) & |
1394 | MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) != | 1394 | MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) != |
1395 | MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT) | 1395 | MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT) |
1396 | continue; | 1396 | continue; |
1397 | if (config_page->ConfigElement[i].PhysDiskDevHandle == | 1397 | if (le16_to_cpu(config_page->ConfigElement[i]. |
1398 | pd_handle) { | 1398 | PhysDiskDevHandle) == pd_handle) { |
1399 | *volume_handle = le16_to_cpu(config_page-> | 1399 | *volume_handle = le16_to_cpu(config_page-> |
1400 | ConfigElement[i].VolDevHandle); | 1400 | ConfigElement[i].VolDevHandle); |
1401 | r = 0; | 1401 | r = 0; |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index fa9bf83819d5..d88e9756d8f5 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * controllers | 3 | * controllers |
4 | * | 4 | * |
5 | * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c | 5 | * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c |
6 | * Copyright (C) 2007-2009 LSI Corporation | 6 | * Copyright (C) 2007-2010 LSI Corporation |
7 | * (mailto:DL-MPTFusionLinux@lsi.com) | 7 | * (mailto:DL-MPTFusionLinux@lsi.com) |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
@@ -533,7 +533,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, | |||
533 | if (!found) { | 533 | if (!found) { |
534 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | 534 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " |
535 | "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name, | 535 | "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name, |
536 | desc, tm_request->DevHandle, lun)); | 536 | desc, le16_to_cpu(tm_request->DevHandle), lun)); |
537 | tm_reply = ioc->ctl_cmds.reply; | 537 | tm_reply = ioc->ctl_cmds.reply; |
538 | tm_reply->DevHandle = tm_request->DevHandle; | 538 | tm_reply->DevHandle = tm_request->DevHandle; |
539 | tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; | 539 | tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; |
@@ -551,7 +551,8 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, | |||
551 | 551 | ||
552 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | 552 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " |
553 | "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, | 553 | "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, |
554 | desc, tm_request->DevHandle, lun, tm_request->TaskMID)); | 554 | desc, le16_to_cpu(tm_request->DevHandle), lun, |
555 | le16_to_cpu(tm_request->TaskMID))); | ||
555 | return 0; | 556 | return 0; |
556 | } | 557 | } |
557 | 558 | ||
@@ -647,9 +648,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, | |||
647 | 648 | ||
648 | if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || | 649 | if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || |
649 | mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { | 650 | mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { |
650 | if (!mpi_request->FunctionDependent1 || | 651 | if (!le16_to_cpu(mpi_request->FunctionDependent1) || |
651 | mpi_request->FunctionDependent1 > | 652 | le16_to_cpu(mpi_request->FunctionDependent1) > |
652 | cpu_to_le16(ioc->facts.MaxDevHandle)) { | 653 | ioc->facts.MaxDevHandle) { |
653 | ret = -EINVAL; | 654 | ret = -EINVAL; |
654 | mpt2sas_base_free_smid(ioc, smid); | 655 | mpt2sas_base_free_smid(ioc, smid); |
655 | goto out; | 656 | goto out; |
@@ -743,8 +744,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, | |||
743 | mpt2sas_base_get_sense_buffer_dma(ioc, smid); | 744 | mpt2sas_base_get_sense_buffer_dma(ioc, smid); |
744 | priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid); | 745 | priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid); |
745 | memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE); | 746 | memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE); |
746 | mpt2sas_base_put_smid_scsi_io(ioc, smid, | 747 | if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) |
747 | le16_to_cpu(mpi_request->FunctionDependent1)); | 748 | mpt2sas_base_put_smid_scsi_io(ioc, smid, |
749 | le16_to_cpu(mpi_request->FunctionDependent1)); | ||
750 | else | ||
751 | mpt2sas_base_put_smid_default(ioc, smid); | ||
748 | break; | 752 | break; |
749 | } | 753 | } |
750 | case MPI2_FUNCTION_SCSI_TASK_MGMT: | 754 | case MPI2_FUNCTION_SCSI_TASK_MGMT: |
@@ -752,6 +756,10 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, | |||
752 | Mpi2SCSITaskManagementRequest_t *tm_request = | 756 | Mpi2SCSITaskManagementRequest_t *tm_request = |
753 | (Mpi2SCSITaskManagementRequest_t *)mpi_request; | 757 | (Mpi2SCSITaskManagementRequest_t *)mpi_request; |
754 | 758 | ||
759 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: " | ||
760 | "handle(0x%04x), task_type(0x%02x)\n", ioc->name, | ||
761 | le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); | ||
762 | |||
755 | if (tm_request->TaskType == | 763 | if (tm_request->TaskType == |
756 | MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || | 764 | MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || |
757 | tm_request->TaskType == | 765 | tm_request->TaskType == |
@@ -762,7 +770,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, | |||
762 | } | 770 | } |
763 | } | 771 | } |
764 | 772 | ||
765 | mutex_lock(&ioc->tm_cmds.mutex); | ||
766 | mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu( | 773 | mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu( |
767 | tm_request->DevHandle)); | 774 | tm_request->DevHandle)); |
768 | mpt2sas_base_put_smid_hi_priority(ioc, smid); | 775 | mpt2sas_base_put_smid_hi_priority(ioc, smid); |
@@ -818,7 +825,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, | |||
818 | if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { | 825 | if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { |
819 | Mpi2SCSITaskManagementRequest_t *tm_request = | 826 | Mpi2SCSITaskManagementRequest_t *tm_request = |
820 | (Mpi2SCSITaskManagementRequest_t *)mpi_request; | 827 | (Mpi2SCSITaskManagementRequest_t *)mpi_request; |
821 | mutex_unlock(&ioc->tm_cmds.mutex); | ||
822 | mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu( | 828 | mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu( |
823 | tm_request->DevHandle)); | 829 | tm_request->DevHandle)); |
824 | } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH || | 830 | } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH || |
@@ -897,14 +903,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, | |||
897 | MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { | 903 | MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { |
898 | printk(MPT2SAS_INFO_FMT "issue target reset: handle " | 904 | printk(MPT2SAS_INFO_FMT "issue target reset: handle " |
899 | "= (0x%04x)\n", ioc->name, | 905 | "= (0x%04x)\n", ioc->name, |
900 | mpi_request->FunctionDependent1); | 906 | le16_to_cpu(mpi_request->FunctionDependent1)); |
901 | mpt2sas_halt_firmware(ioc); | 907 | mpt2sas_halt_firmware(ioc); |
902 | mutex_lock(&ioc->tm_cmds.mutex); | ||
903 | mpt2sas_scsih_issue_tm(ioc, | 908 | mpt2sas_scsih_issue_tm(ioc, |
904 | mpi_request->FunctionDependent1, 0, | 909 | le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, |
905 | MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10); | 910 | 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10, |
911 | NULL); | ||
906 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; | 912 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; |
907 | mutex_unlock(&ioc->tm_cmds.mutex); | ||
908 | } else | 913 | } else |
909 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, | 914 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, |
910 | FORCE_BIG_HAMMER); | 915 | FORCE_BIG_HAMMER); |
@@ -1373,7 +1378,8 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc, | |||
1373 | 1378 | ||
1374 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), " | 1379 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), " |
1375 | "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data, | 1380 | "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data, |
1376 | (unsigned long long)request_data_dma, mpi_request->BufferLength)); | 1381 | (unsigned long long)request_data_dma, |
1382 | le32_to_cpu(mpi_request->BufferLength))); | ||
1377 | 1383 | ||
1378 | for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) | 1384 | for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) |
1379 | mpi_request->ProductSpecific[i] = | 1385 | mpi_request->ProductSpecific[i] = |
@@ -2334,8 +2340,8 @@ _ctl_version_nvdata_persistent_show(struct device *cdev, | |||
2334 | struct Scsi_Host *shost = class_to_shost(cdev); | 2340 | struct Scsi_Host *shost = class_to_shost(cdev); |
2335 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | 2341 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); |
2336 | 2342 | ||
2337 | return snprintf(buf, PAGE_SIZE, "%02xh\n", | 2343 | return snprintf(buf, PAGE_SIZE, "%08xh\n", |
2338 | le16_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); | 2344 | le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); |
2339 | } | 2345 | } |
2340 | static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, | 2346 | static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, |
2341 | _ctl_version_nvdata_persistent_show, NULL); | 2347 | _ctl_version_nvdata_persistent_show, NULL); |
@@ -2354,8 +2360,8 @@ _ctl_version_nvdata_default_show(struct device *cdev, | |||
2354 | struct Scsi_Host *shost = class_to_shost(cdev); | 2360 | struct Scsi_Host *shost = class_to_shost(cdev); |
2355 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | 2361 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); |
2356 | 2362 | ||
2357 | return snprintf(buf, PAGE_SIZE, "%02xh\n", | 2363 | return snprintf(buf, PAGE_SIZE, "%08xh\n", |
2358 | le16_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); | 2364 | le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); |
2359 | } | 2365 | } |
2360 | static DEVICE_ATTR(version_nvdata_default, S_IRUGO, | 2366 | static DEVICE_ATTR(version_nvdata_default, S_IRUGO, |
2361 | _ctl_version_nvdata_default_show, NULL); | 2367 | _ctl_version_nvdata_default_show, NULL); |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h index 8a5eeb1a5c84..69916e46e04f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h | |||
@@ -3,7 +3,7 @@ | |||
3 | * controllers | 3 | * controllers |
4 | * | 4 | * |
5 | * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h | 5 | * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h |
6 | * Copyright (C) 2007-2009 LSI Corporation | 6 | * Copyright (C) 2007-2010 LSI Corporation |
7 | * (mailto:DL-MPTFusionLinux@lsi.com) | 7 | * (mailto:DL-MPTFusionLinux@lsi.com) |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h index 5308a25cb307..3dcddfeb6f4c 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_debug.h +++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * Logging Support for MPT (Message Passing Technology) based controllers | 2 | * Logging Support for MPT (Message Passing Technology) based controllers |
3 | * | 3 | * |
4 | * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c | 4 | * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c |
5 | * Copyright (C) 2007-2009 LSI Corporation | 5 | * Copyright (C) 2007-2010 LSI Corporation |
6 | * (mailto:DL-MPTFusionLinux@lsi.com) | 6 | * (mailto:DL-MPTFusionLinux@lsi.com) |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index be171ed682e0..c5ff26a2a51d 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Scsi Host Layer for MPT (Message Passing Technology) based controllers | 2 | * Scsi Host Layer for MPT (Message Passing Technology) based controllers |
3 | * | 3 | * |
4 | * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c | 4 | * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c |
5 | * Copyright (C) 2007-2009 LSI Corporation | 5 | * Copyright (C) 2007-2010 LSI Corporation |
6 | * (mailto:DL-MPTFusionLinux@lsi.com) | 6 | * (mailto:DL-MPTFusionLinux@lsi.com) |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/delay.h> | 52 | #include <linux/delay.h> |
53 | #include <linux/pci.h> | 53 | #include <linux/pci.h> |
54 | #include <linux/interrupt.h> | 54 | #include <linux/interrupt.h> |
55 | #include <linux/aer.h> | ||
55 | #include <linux/raid_class.h> | 56 | #include <linux/raid_class.h> |
56 | #include <linux/slab.h> | 57 | #include <linux/slab.h> |
57 | 58 | ||
@@ -109,14 +110,16 @@ struct sense_info { | |||
109 | }; | 110 | }; |
110 | 111 | ||
111 | 112 | ||
113 | #define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF) | ||
114 | |||
112 | /** | 115 | /** |
113 | * struct fw_event_work - firmware event struct | 116 | * struct fw_event_work - firmware event struct |
114 | * @list: link list framework | 117 | * @list: link list framework |
115 | * @work: work object (ioc->fault_reset_work_q) | 118 | * @work: work object (ioc->fault_reset_work_q) |
119 | * @cancel_pending_work: flag set during reset handling | ||
116 | * @ioc: per adapter object | 120 | * @ioc: per adapter object |
117 | * @VF_ID: virtual function id | 121 | * @VF_ID: virtual function id |
118 | * @VP_ID: virtual port id | 122 | * @VP_ID: virtual port id |
119 | * @host_reset_handling: handling events during host reset | ||
120 | * @ignore: flag meaning this event has been marked to ignore | 123 | * @ignore: flag meaning this event has been marked to ignore |
121 | * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h | 124 | * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h |
122 | * @event_data: reply event data payload follows | 125 | * @event_data: reply event data payload follows |
@@ -125,11 +128,11 @@ struct sense_info { | |||
125 | */ | 128 | */ |
126 | struct fw_event_work { | 129 | struct fw_event_work { |
127 | struct list_head list; | 130 | struct list_head list; |
128 | struct work_struct work; | 131 | u8 cancel_pending_work; |
132 | struct delayed_work delayed_work; | ||
129 | struct MPT2SAS_ADAPTER *ioc; | 133 | struct MPT2SAS_ADAPTER *ioc; |
130 | u8 VF_ID; | 134 | u8 VF_ID; |
131 | u8 VP_ID; | 135 | u8 VP_ID; |
132 | u8 host_reset_handling; | ||
133 | u8 ignore; | 136 | u8 ignore; |
134 | u16 event; | 137 | u16 event; |
135 | void *event_data; | 138 | void *event_data; |
@@ -482,27 +485,17 @@ struct _sas_device * | |||
482 | mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, | 485 | mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, |
483 | u64 sas_address) | 486 | u64 sas_address) |
484 | { | 487 | { |
485 | struct _sas_device *sas_device, *r; | 488 | struct _sas_device *sas_device; |
486 | 489 | ||
487 | r = NULL; | 490 | list_for_each_entry(sas_device, &ioc->sas_device_list, list) |
488 | /* check the sas_device_init_list */ | 491 | if (sas_device->sas_address == sas_address) |
489 | list_for_each_entry(sas_device, &ioc->sas_device_init_list, | 492 | return sas_device; |
490 | list) { | ||
491 | if (sas_device->sas_address != sas_address) | ||
492 | continue; | ||
493 | r = sas_device; | ||
494 | goto out; | ||
495 | } | ||
496 | 493 | ||
497 | /* then check the sas_device_list */ | 494 | list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) |
498 | list_for_each_entry(sas_device, &ioc->sas_device_list, list) { | 495 | if (sas_device->sas_address == sas_address) |
499 | if (sas_device->sas_address != sas_address) | 496 | return sas_device; |
500 | continue; | 497 | |
501 | r = sas_device; | 498 | return NULL; |
502 | goto out; | ||
503 | } | ||
504 | out: | ||
505 | return r; | ||
506 | } | 499 | } |
507 | 500 | ||
508 | /** | 501 | /** |
@@ -517,28 +510,17 @@ mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, | |||
517 | static struct _sas_device * | 510 | static struct _sas_device * |
518 | _scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) | 511 | _scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) |
519 | { | 512 | { |
520 | struct _sas_device *sas_device, *r; | 513 | struct _sas_device *sas_device; |
521 | 514 | ||
522 | r = NULL; | 515 | list_for_each_entry(sas_device, &ioc->sas_device_list, list) |
523 | if (ioc->wait_for_port_enable_to_complete) { | 516 | if (sas_device->handle == handle) |
524 | list_for_each_entry(sas_device, &ioc->sas_device_init_list, | 517 | return sas_device; |
525 | list) { | ||
526 | if (sas_device->handle != handle) | ||
527 | continue; | ||
528 | r = sas_device; | ||
529 | goto out; | ||
530 | } | ||
531 | } else { | ||
532 | list_for_each_entry(sas_device, &ioc->sas_device_list, list) { | ||
533 | if (sas_device->handle != handle) | ||
534 | continue; | ||
535 | r = sas_device; | ||
536 | goto out; | ||
537 | } | ||
538 | } | ||
539 | 518 | ||
540 | out: | 519 | list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) |
541 | return r; | 520 | if (sas_device->handle == handle) |
521 | return sas_device; | ||
522 | |||
523 | return NULL; | ||
542 | } | 524 | } |
543 | 525 | ||
544 | /** | 526 | /** |
@@ -555,10 +537,15 @@ _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc, | |||
555 | { | 537 | { |
556 | unsigned long flags; | 538 | unsigned long flags; |
557 | 539 | ||
540 | if (!sas_device) | ||
541 | return; | ||
542 | |||
558 | spin_lock_irqsave(&ioc->sas_device_lock, flags); | 543 | spin_lock_irqsave(&ioc->sas_device_lock, flags); |
559 | list_del(&sas_device->list); | 544 | if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc, |
560 | memset(sas_device, 0, sizeof(struct _sas_device)); | 545 | sas_device->sas_address)) { |
561 | kfree(sas_device); | 546 | list_del(&sas_device->list); |
547 | kfree(sas_device); | ||
548 | } | ||
562 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | 549 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); |
563 | } | 550 | } |
564 | 551 | ||
@@ -988,7 +975,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, | |||
988 | u32 chain_offset; | 975 | u32 chain_offset; |
989 | u32 chain_length; | 976 | u32 chain_length; |
990 | u32 chain_flags; | 977 | u32 chain_flags; |
991 | u32 sges_left; | 978 | int sges_left; |
992 | u32 sges_in_segment; | 979 | u32 sges_in_segment; |
993 | u32 sgl_flags; | 980 | u32 sgl_flags; |
994 | u32 sgl_flags_last_element; | 981 | u32 sgl_flags_last_element; |
@@ -1009,7 +996,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, | |||
1009 | 996 | ||
1010 | sg_scmd = scsi_sglist(scmd); | 997 | sg_scmd = scsi_sglist(scmd); |
1011 | sges_left = scsi_dma_map(scmd); | 998 | sges_left = scsi_dma_map(scmd); |
1012 | if (!sges_left) { | 999 | if (sges_left < 0) { |
1013 | sdev_printk(KERN_ERR, scmd->device, "pci_map_sg" | 1000 | sdev_printk(KERN_ERR, scmd->device, "pci_map_sg" |
1014 | " failed: request for %d bytes!\n", scsi_bufflen(scmd)); | 1001 | " failed: request for %d bytes!\n", scsi_bufflen(scmd)); |
1015 | return -ENOMEM; | 1002 | return -ENOMEM; |
@@ -1395,7 +1382,7 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, | |||
1395 | } | 1382 | } |
1396 | 1383 | ||
1397 | flags = le16_to_cpu(sas_device_pg0.Flags); | 1384 | flags = le16_to_cpu(sas_device_pg0.Flags); |
1398 | device_info = le16_to_cpu(sas_device_pg0.DeviceInfo); | 1385 | device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); |
1399 | 1386 | ||
1400 | sdev_printk(KERN_INFO, sdev, | 1387 | sdev_printk(KERN_INFO, sdev, |
1401 | "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), " | 1388 | "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), " |
@@ -1963,65 +1950,78 @@ mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) | |||
1963 | } | 1950 | } |
1964 | } | 1951 | } |
1965 | 1952 | ||
1953 | |||
1966 | /** | 1954 | /** |
1967 | * mpt2sas_scsih_issue_tm - main routine for sending tm requests | 1955 | * mpt2sas_scsih_issue_tm - main routine for sending tm requests |
1968 | * @ioc: per adapter struct | 1956 | * @ioc: per adapter struct |
1969 | * @device_handle: device handle | 1957 | * @device_handle: device handle |
1958 | * @channel: the channel assigned by the OS | ||
1959 | * @id: the id assigned by the OS | ||
1970 | * @lun: lun number | 1960 | * @lun: lun number |
1971 | * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) | 1961 | * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) |
1972 | * @smid_task: smid assigned to the task | 1962 | * @smid_task: smid assigned to the task |
1973 | * @timeout: timeout in seconds | 1963 | * @timeout: timeout in seconds |
1974 | * Context: The calling function needs to acquire the tm_cmds.mutex | 1964 | * Context: user |
1975 | * | 1965 | * |
1976 | * A generic API for sending task management requests to firmware. | 1966 | * A generic API for sending task management requests to firmware. |
1977 | * | 1967 | * |
1978 | * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling | ||
1979 | * this API. | ||
1980 | * | ||
1981 | * The callback index is set inside `ioc->tm_cb_idx`. | 1968 | * The callback index is set inside `ioc->tm_cb_idx`. |
1982 | * | 1969 | * |
1983 | * Return nothing. | 1970 | * Return SUCCESS or FAILED. |
1984 | */ | 1971 | */ |
1985 | void | 1972 | int |
1986 | mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, | 1973 | mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, |
1987 | u8 type, u16 smid_task, ulong timeout) | 1974 | uint id, uint lun, u8 type, u16 smid_task, ulong timeout, |
1975 | struct scsi_cmnd *scmd) | ||
1988 | { | 1976 | { |
1989 | Mpi2SCSITaskManagementRequest_t *mpi_request; | 1977 | Mpi2SCSITaskManagementRequest_t *mpi_request; |
1990 | Mpi2SCSITaskManagementReply_t *mpi_reply; | 1978 | Mpi2SCSITaskManagementReply_t *mpi_reply; |
1991 | u16 smid = 0; | 1979 | u16 smid = 0; |
1992 | u32 ioc_state; | 1980 | u32 ioc_state; |
1993 | unsigned long timeleft; | 1981 | unsigned long timeleft; |
1982 | struct scsi_cmnd *scmd_lookup; | ||
1983 | int rc; | ||
1994 | 1984 | ||
1985 | mutex_lock(&ioc->tm_cmds.mutex); | ||
1995 | if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) { | 1986 | if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) { |
1996 | printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n", | 1987 | printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n", |
1997 | __func__, ioc->name); | 1988 | __func__, ioc->name); |
1998 | return; | 1989 | rc = FAILED; |
1990 | goto err_out; | ||
1999 | } | 1991 | } |
2000 | 1992 | ||
2001 | if (ioc->shost_recovery) { | 1993 | if (ioc->shost_recovery || ioc->remove_host) { |
2002 | printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", | 1994 | printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", |
2003 | __func__, ioc->name); | 1995 | __func__, ioc->name); |
2004 | return; | 1996 | rc = FAILED; |
1997 | goto err_out; | ||
2005 | } | 1998 | } |
2006 | 1999 | ||
2007 | ioc_state = mpt2sas_base_get_iocstate(ioc, 0); | 2000 | ioc_state = mpt2sas_base_get_iocstate(ioc, 0); |
2008 | if (ioc_state & MPI2_DOORBELL_USED) { | 2001 | if (ioc_state & MPI2_DOORBELL_USED) { |
2009 | dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell " | 2002 | dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell " |
2010 | "active!\n", ioc->name)); | 2003 | "active!\n", ioc->name)); |
2011 | goto issue_host_reset; | 2004 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, |
2005 | FORCE_BIG_HAMMER); | ||
2006 | rc = SUCCESS; | ||
2007 | goto err_out; | ||
2012 | } | 2008 | } |
2013 | 2009 | ||
2014 | if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { | 2010 | if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { |
2015 | mpt2sas_base_fault_info(ioc, ioc_state & | 2011 | mpt2sas_base_fault_info(ioc, ioc_state & |
2016 | MPI2_DOORBELL_DATA_MASK); | 2012 | MPI2_DOORBELL_DATA_MASK); |
2017 | goto issue_host_reset; | 2013 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, |
2014 | FORCE_BIG_HAMMER); | ||
2015 | rc = SUCCESS; | ||
2016 | goto err_out; | ||
2018 | } | 2017 | } |
2019 | 2018 | ||
2020 | smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx); | 2019 | smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx); |
2021 | if (!smid) { | 2020 | if (!smid) { |
2022 | printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", | 2021 | printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", |
2023 | ioc->name, __func__); | 2022 | ioc->name, __func__); |
2024 | return; | 2023 | rc = FAILED; |
2024 | goto err_out; | ||
2025 | } | 2025 | } |
2026 | 2026 | ||
2027 | dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," | 2027 | dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," |
@@ -2035,21 +2035,24 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, | |||
2035 | mpi_request->DevHandle = cpu_to_le16(handle); | 2035 | mpi_request->DevHandle = cpu_to_le16(handle); |
2036 | mpi_request->TaskType = type; | 2036 | mpi_request->TaskType = type; |
2037 | mpi_request->TaskMID = cpu_to_le16(smid_task); | 2037 | mpi_request->TaskMID = cpu_to_le16(smid_task); |
2038 | mpi_request->VP_ID = 0; /* TODO */ | ||
2039 | mpi_request->VF_ID = 0; | ||
2040 | int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); | 2038 | int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); |
2041 | mpt2sas_scsih_set_tm_flag(ioc, handle); | 2039 | mpt2sas_scsih_set_tm_flag(ioc, handle); |
2042 | init_completion(&ioc->tm_cmds.done); | 2040 | init_completion(&ioc->tm_cmds.done); |
2043 | mpt2sas_base_put_smid_hi_priority(ioc, smid); | 2041 | mpt2sas_base_put_smid_hi_priority(ioc, smid); |
2044 | timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); | 2042 | timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); |
2045 | mpt2sas_scsih_clear_tm_flag(ioc, handle); | ||
2046 | if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) { | 2043 | if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) { |
2047 | printk(MPT2SAS_ERR_FMT "%s: timeout\n", | 2044 | printk(MPT2SAS_ERR_FMT "%s: timeout\n", |
2048 | ioc->name, __func__); | 2045 | ioc->name, __func__); |
2049 | _debug_dump_mf(mpi_request, | 2046 | _debug_dump_mf(mpi_request, |
2050 | sizeof(Mpi2SCSITaskManagementRequest_t)/4); | 2047 | sizeof(Mpi2SCSITaskManagementRequest_t)/4); |
2051 | if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) | 2048 | if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) { |
2052 | goto issue_host_reset; | 2049 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, |
2050 | FORCE_BIG_HAMMER); | ||
2051 | rc = SUCCESS; | ||
2052 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; | ||
2053 | mpt2sas_scsih_clear_tm_flag(ioc, handle); | ||
2054 | goto err_out; | ||
2055 | } | ||
2053 | } | 2056 | } |
2054 | 2057 | ||
2055 | if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) { | 2058 | if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) { |
@@ -2059,12 +2062,57 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, | |||
2059 | ioc->name, le16_to_cpu(mpi_reply->IOCStatus), | 2062 | ioc->name, le16_to_cpu(mpi_reply->IOCStatus), |
2060 | le32_to_cpu(mpi_reply->IOCLogInfo), | 2063 | le32_to_cpu(mpi_reply->IOCLogInfo), |
2061 | le32_to_cpu(mpi_reply->TerminationCount))); | 2064 | le32_to_cpu(mpi_reply->TerminationCount))); |
2062 | if (ioc->logging_level & MPT_DEBUG_TM) | 2065 | if (ioc->logging_level & MPT_DEBUG_TM) { |
2063 | _scsih_response_code(ioc, mpi_reply->ResponseCode); | 2066 | _scsih_response_code(ioc, mpi_reply->ResponseCode); |
2067 | if (mpi_reply->IOCStatus) | ||
2068 | _debug_dump_mf(mpi_request, | ||
2069 | sizeof(Mpi2SCSITaskManagementRequest_t)/4); | ||
2070 | } | ||
2064 | } | 2071 | } |
2065 | return; | 2072 | |
2066 | issue_host_reset: | 2073 | /* sanity check: |
2067 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); | 2074 | * Check to see the commands were terminated. |
2075 | * This is only needed for eh callbacks, hence the scmd check. | ||
2076 | */ | ||
2077 | rc = FAILED; | ||
2078 | if (scmd == NULL) | ||
2079 | goto bypass_sanity_checks; | ||
2080 | switch (type) { | ||
2081 | case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: | ||
2082 | scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task); | ||
2083 | if (scmd_lookup && (scmd_lookup->serial_number == | ||
2084 | scmd->serial_number)) | ||
2085 | rc = FAILED; | ||
2086 | else | ||
2087 | rc = SUCCESS; | ||
2088 | break; | ||
2089 | |||
2090 | case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: | ||
2091 | if (_scsih_scsi_lookup_find_by_target(ioc, id, channel)) | ||
2092 | rc = FAILED; | ||
2093 | else | ||
2094 | rc = SUCCESS; | ||
2095 | break; | ||
2096 | |||
2097 | case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: | ||
2098 | if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel)) | ||
2099 | rc = FAILED; | ||
2100 | else | ||
2101 | rc = SUCCESS; | ||
2102 | break; | ||
2103 | } | ||
2104 | |||
2105 | bypass_sanity_checks: | ||
2106 | |||
2107 | mpt2sas_scsih_clear_tm_flag(ioc, handle); | ||
2108 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; | ||
2109 | mutex_unlock(&ioc->tm_cmds.mutex); | ||
2110 | |||
2111 | return rc; | ||
2112 | |||
2113 | err_out: | ||
2114 | mutex_unlock(&ioc->tm_cmds.mutex); | ||
2115 | return rc; | ||
2068 | } | 2116 | } |
2069 | 2117 | ||
2070 | /** | 2118 | /** |
@@ -2081,7 +2129,6 @@ _scsih_abort(struct scsi_cmnd *scmd) | |||
2081 | u16 smid; | 2129 | u16 smid; |
2082 | u16 handle; | 2130 | u16 handle; |
2083 | int r; | 2131 | int r; |
2084 | struct scsi_cmnd *scmd_lookup; | ||
2085 | 2132 | ||
2086 | printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n", | 2133 | printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n", |
2087 | ioc->name, scmd); | 2134 | ioc->name, scmd); |
@@ -2116,19 +2163,10 @@ _scsih_abort(struct scsi_cmnd *scmd) | |||
2116 | 2163 | ||
2117 | mpt2sas_halt_firmware(ioc); | 2164 | mpt2sas_halt_firmware(ioc); |
2118 | 2165 | ||
2119 | mutex_lock(&ioc->tm_cmds.mutex); | ||
2120 | handle = sas_device_priv_data->sas_target->handle; | 2166 | handle = sas_device_priv_data->sas_target->handle; |
2121 | mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun, | 2167 | r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, |
2122 | MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30); | 2168 | scmd->device->id, scmd->device->lun, |
2123 | 2169 | MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd); | |
2124 | /* sanity check - see whether command actually completed */ | ||
2125 | scmd_lookup = _scsih_scsi_lookup_get(ioc, smid); | ||
2126 | if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number)) | ||
2127 | r = FAILED; | ||
2128 | else | ||
2129 | r = SUCCESS; | ||
2130 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; | ||
2131 | mutex_unlock(&ioc->tm_cmds.mutex); | ||
2132 | 2170 | ||
2133 | out: | 2171 | out: |
2134 | printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n", | 2172 | printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n", |
@@ -2185,22 +2223,9 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) | |||
2185 | goto out; | 2223 | goto out; |
2186 | } | 2224 | } |
2187 | 2225 | ||
2188 | mutex_lock(&ioc->tm_cmds.mutex); | 2226 | r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, |
2189 | mpt2sas_scsih_issue_tm(ioc, handle, 0, | 2227 | scmd->device->id, scmd->device->lun, |
2190 | MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun, | 2228 | MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd); |
2191 | 30); | ||
2192 | |||
2193 | /* | ||
2194 | * sanity check see whether all commands to this device been | ||
2195 | * completed | ||
2196 | */ | ||
2197 | if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id, | ||
2198 | scmd->device->lun, scmd->device->channel)) | ||
2199 | r = FAILED; | ||
2200 | else | ||
2201 | r = SUCCESS; | ||
2202 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; | ||
2203 | mutex_unlock(&ioc->tm_cmds.mutex); | ||
2204 | 2229 | ||
2205 | out: | 2230 | out: |
2206 | printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n", | 2231 | printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n", |
@@ -2257,21 +2282,9 @@ _scsih_target_reset(struct scsi_cmnd *scmd) | |||
2257 | goto out; | 2282 | goto out; |
2258 | } | 2283 | } |
2259 | 2284 | ||
2260 | mutex_lock(&ioc->tm_cmds.mutex); | 2285 | r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, |
2261 | mpt2sas_scsih_issue_tm(ioc, handle, 0, | 2286 | scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, |
2262 | MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30); | 2287 | 30, scmd); |
2263 | |||
2264 | /* | ||
2265 | * sanity check see whether all commands to this target been | ||
2266 | * completed | ||
2267 | */ | ||
2268 | if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id, | ||
2269 | scmd->device->channel)) | ||
2270 | r = FAILED; | ||
2271 | else | ||
2272 | r = SUCCESS; | ||
2273 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; | ||
2274 | mutex_unlock(&ioc->tm_cmds.mutex); | ||
2275 | 2288 | ||
2276 | out: | 2289 | out: |
2277 | printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n", | 2290 | printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n", |
@@ -2325,8 +2338,9 @@ _scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) | |||
2325 | 2338 | ||
2326 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | 2339 | spin_lock_irqsave(&ioc->fw_event_lock, flags); |
2327 | list_add_tail(&fw_event->list, &ioc->fw_event_list); | 2340 | list_add_tail(&fw_event->list, &ioc->fw_event_list); |
2328 | INIT_WORK(&fw_event->work, _firmware_event_work); | 2341 | INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work); |
2329 | queue_work(ioc->firmware_event_thread, &fw_event->work); | 2342 | queue_delayed_work(ioc->firmware_event_thread, |
2343 | &fw_event->delayed_work, 0); | ||
2330 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | 2344 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); |
2331 | } | 2345 | } |
2332 | 2346 | ||
@@ -2353,61 +2367,53 @@ _scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work | |||
2353 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | 2367 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); |
2354 | } | 2368 | } |
2355 | 2369 | ||
2370 | |||
2356 | /** | 2371 | /** |
2357 | * _scsih_fw_event_add - requeue an event | 2372 | * _scsih_queue_rescan - queue a topology rescan from user context |
2358 | * @ioc: per adapter object | 2373 | * @ioc: per adapter object |
2359 | * @fw_event: object describing the event | ||
2360 | * Context: This function will acquire ioc->fw_event_lock. | ||
2361 | * | 2374 | * |
2362 | * Return nothing. | 2375 | * Return nothing. |
2363 | */ | 2376 | */ |
2364 | static void | 2377 | static void |
2365 | _scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work | 2378 | _scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc) |
2366 | *fw_event, unsigned long delay) | ||
2367 | { | 2379 | { |
2368 | unsigned long flags; | 2380 | struct fw_event_work *fw_event; |
2369 | if (ioc->firmware_event_thread == NULL) | ||
2370 | return; | ||
2371 | 2381 | ||
2372 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | 2382 | if (ioc->wait_for_port_enable_to_complete) |
2373 | queue_work(ioc->firmware_event_thread, &fw_event->work); | 2383 | return; |
2374 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | 2384 | fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); |
2385 | if (!fw_event) | ||
2386 | return; | ||
2387 | fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET; | ||
2388 | fw_event->ioc = ioc; | ||
2389 | _scsih_fw_event_add(ioc, fw_event); | ||
2375 | } | 2390 | } |
2376 | 2391 | ||
2377 | /** | 2392 | /** |
2378 | * _scsih_fw_event_off - turn flag off preventing event handling | 2393 | * _scsih_fw_event_cleanup_queue - cleanup event queue |
2379 | * @ioc: per adapter object | 2394 | * @ioc: per adapter object |
2380 | * | 2395 | * |
2381 | * Used to prevent handling of firmware events during adapter reset | 2396 | * Walk the firmware event queue, either killing timers, or waiting |
2382 | * driver unload. | 2397 | * for outstanding events to complete |
2383 | * | 2398 | * |
2384 | * Return nothing. | 2399 | * Return nothing. |
2385 | */ | 2400 | */ |
2386 | static void | 2401 | static void |
2387 | _scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc) | 2402 | _scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc) |
2388 | { | 2403 | { |
2389 | unsigned long flags; | 2404 | struct fw_event_work *fw_event, *next; |
2390 | 2405 | ||
2391 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | 2406 | if (list_empty(&ioc->fw_event_list) || |
2392 | ioc->fw_events_off = 1; | 2407 | !ioc->firmware_event_thread || in_interrupt()) |
2393 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | 2408 | return; |
2394 | |||
2395 | } | ||
2396 | |||
2397 | /** | ||
2398 | * _scsih_fw_event_on - turn flag on allowing firmware event handling | ||
2399 | * @ioc: per adapter object | ||
2400 | * | ||
2401 | * Returns nothing. | ||
2402 | */ | ||
2403 | static void | ||
2404 | _scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc) | ||
2405 | { | ||
2406 | unsigned long flags; | ||
2407 | 2409 | ||
2408 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | 2410 | list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { |
2409 | ioc->fw_events_off = 0; | 2411 | if (cancel_delayed_work(&fw_event->delayed_work)) { |
2410 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | 2412 | _scsih_fw_event_free(ioc, fw_event); |
2413 | continue; | ||
2414 | } | ||
2415 | fw_event->cancel_pending_work = 1; | ||
2416 | } | ||
2411 | } | 2417 | } |
2412 | 2418 | ||
2413 | /** | 2419 | /** |
@@ -2571,25 +2577,24 @@ static void | |||
2571 | _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) | 2577 | _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) |
2572 | { | 2578 | { |
2573 | Mpi2SCSITaskManagementRequest_t *mpi_request; | 2579 | Mpi2SCSITaskManagementRequest_t *mpi_request; |
2574 | struct MPT2SAS_TARGET *sas_target_priv_data; | ||
2575 | u16 smid; | 2580 | u16 smid; |
2576 | struct _sas_device *sas_device; | 2581 | struct _sas_device *sas_device; |
2577 | unsigned long flags; | 2582 | unsigned long flags; |
2578 | struct _tr_list *delayed_tr; | 2583 | struct _tr_list *delayed_tr; |
2579 | 2584 | ||
2580 | if (ioc->shost_recovery) { | 2585 | if (ioc->shost_recovery || ioc->remove_host) { |
2581 | printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", | 2586 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " |
2582 | __func__, ioc->name); | 2587 | "progress!\n", __func__, ioc->name)); |
2583 | return; | 2588 | return; |
2584 | } | 2589 | } |
2585 | 2590 | ||
2586 | spin_lock_irqsave(&ioc->sas_device_lock, flags); | 2591 | spin_lock_irqsave(&ioc->sas_device_lock, flags); |
2587 | sas_device = _scsih_sas_device_find_by_handle(ioc, handle); | 2592 | sas_device = _scsih_sas_device_find_by_handle(ioc, handle); |
2588 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | 2593 | if (sas_device && sas_device->hidden_raid_component) { |
2589 | 2594 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | |
2590 | /* skip is hidden raid component */ | ||
2591 | if (sas_device && sas_device->hidden_raid_component) | ||
2592 | return; | 2595 | return; |
2596 | } | ||
2597 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | ||
2593 | 2598 | ||
2594 | smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); | 2599 | smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); |
2595 | if (!smid) { | 2600 | if (!smid) { |
@@ -2598,36 +2603,16 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) | |||
2598 | return; | 2603 | return; |
2599 | INIT_LIST_HEAD(&delayed_tr->list); | 2604 | INIT_LIST_HEAD(&delayed_tr->list); |
2600 | delayed_tr->handle = handle; | 2605 | delayed_tr->handle = handle; |
2601 | delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL; | 2606 | list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); |
2602 | list_add_tail(&delayed_tr->list, | ||
2603 | &ioc->delayed_tr_list); | ||
2604 | if (sas_device && sas_device->starget) { | ||
2605 | dewtprintk(ioc, starget_printk(KERN_INFO, | ||
2606 | sas_device->starget, "DELAYED:tr:handle(0x%04x), " | ||
2607 | "(open)\n", handle)); | ||
2608 | } else { | ||
2609 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT | ||
2610 | "DELAYED:tr:handle(0x%04x), (open)\n", | ||
2611 | ioc->name, handle)); | ||
2612 | } | ||
2613 | return; | ||
2614 | } | ||
2615 | |||
2616 | if (sas_device) { | ||
2617 | sas_device->state |= MPTSAS_STATE_TR_SEND; | ||
2618 | sas_device->state |= MPT2SAS_REQ_SAS_CNTRL; | ||
2619 | if (sas_device->starget && sas_device->starget->hostdata) { | ||
2620 | sas_target_priv_data = sas_device->starget->hostdata; | ||
2621 | sas_target_priv_data->tm_busy = 1; | ||
2622 | dewtprintk(ioc, starget_printk(KERN_INFO, | ||
2623 | sas_device->starget, "tr:handle(0x%04x), (open)\n", | ||
2624 | handle)); | ||
2625 | } | ||
2626 | } else { | ||
2627 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT | 2607 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT |
2628 | "tr:handle(0x%04x), (open)\n", ioc->name, handle)); | 2608 | "DELAYED:tr:handle(0x%04x), (open)\n", |
2609 | ioc->name, handle)); | ||
2610 | return; | ||
2629 | } | 2611 | } |
2630 | 2612 | ||
2613 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " | ||
2614 | "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, | ||
2615 | ioc->tm_tr_cb_idx)); | ||
2631 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); | 2616 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); |
2632 | memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); | 2617 | memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); |
2633 | mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; | 2618 | mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; |
@@ -2657,35 +2642,15 @@ static u8 | |||
2657 | _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, | 2642 | _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, |
2658 | u8 msix_index, u32 reply) | 2643 | u8 msix_index, u32 reply) |
2659 | { | 2644 | { |
2660 | unsigned long flags; | ||
2661 | u16 handle; | ||
2662 | struct _sas_device *sas_device; | ||
2663 | Mpi2SasIoUnitControlReply_t *mpi_reply = | 2645 | Mpi2SasIoUnitControlReply_t *mpi_reply = |
2664 | mpt2sas_base_get_reply_virt_addr(ioc, reply); | 2646 | mpt2sas_base_get_reply_virt_addr(ioc, reply); |
2665 | 2647 | ||
2666 | handle = le16_to_cpu(mpi_reply->DevHandle); | 2648 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT |
2667 | 2649 | "sc_complete:handle(0x%04x), (open) " | |
2668 | spin_lock_irqsave(&ioc->sas_device_lock, flags); | 2650 | "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", |
2669 | sas_device = _scsih_sas_device_find_by_handle(ioc, handle); | 2651 | ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, |
2670 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | 2652 | le16_to_cpu(mpi_reply->IOCStatus), |
2671 | 2653 | le32_to_cpu(mpi_reply->IOCLogInfo))); | |
2672 | if (sas_device) { | ||
2673 | sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE; | ||
2674 | if (sas_device->starget) | ||
2675 | dewtprintk(ioc, starget_printk(KERN_INFO, | ||
2676 | sas_device->starget, | ||
2677 | "sc_complete:handle(0x%04x), " | ||
2678 | "ioc_status(0x%04x), loginfo(0x%08x)\n", | ||
2679 | handle, le16_to_cpu(mpi_reply->IOCStatus), | ||
2680 | le32_to_cpu(mpi_reply->IOCLogInfo))); | ||
2681 | } else { | ||
2682 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT | ||
2683 | "sc_complete:handle(0x%04x), " | ||
2684 | "ioc_status(0x%04x), loginfo(0x%08x)\n", | ||
2685 | ioc->name, handle, le16_to_cpu(mpi_reply->IOCStatus), | ||
2686 | le32_to_cpu(mpi_reply->IOCLogInfo))); | ||
2687 | } | ||
2688 | |||
2689 | return 1; | 2654 | return 1; |
2690 | } | 2655 | } |
2691 | 2656 | ||
@@ -2709,87 +2674,63 @@ static u8 | |||
2709 | _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, | 2674 | _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, |
2710 | u32 reply) | 2675 | u32 reply) |
2711 | { | 2676 | { |
2712 | unsigned long flags; | ||
2713 | u16 handle; | 2677 | u16 handle; |
2714 | struct _sas_device *sas_device; | 2678 | Mpi2SCSITaskManagementRequest_t *mpi_request_tm; |
2715 | Mpi2SCSITaskManagementReply_t *mpi_reply = | 2679 | Mpi2SCSITaskManagementReply_t *mpi_reply = |
2716 | mpt2sas_base_get_reply_virt_addr(ioc, reply); | 2680 | mpt2sas_base_get_reply_virt_addr(ioc, reply); |
2717 | Mpi2SasIoUnitControlRequest_t *mpi_request; | 2681 | Mpi2SasIoUnitControlRequest_t *mpi_request; |
2718 | u16 smid_sas_ctrl; | 2682 | u16 smid_sas_ctrl; |
2719 | struct MPT2SAS_TARGET *sas_target_priv_data; | ||
2720 | struct _tr_list *delayed_tr; | 2683 | struct _tr_list *delayed_tr; |
2721 | u8 rc; | ||
2722 | 2684 | ||
2723 | handle = le16_to_cpu(mpi_reply->DevHandle); | 2685 | if (ioc->shost_recovery || ioc->remove_host) { |
2724 | spin_lock_irqsave(&ioc->sas_device_lock, flags); | 2686 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " |
2725 | sas_device = _scsih_sas_device_find_by_handle(ioc, handle); | 2687 | "progress!\n", __func__, ioc->name)); |
2726 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | 2688 | return 1; |
2727 | |||
2728 | if (sas_device) { | ||
2729 | sas_device->state |= MPTSAS_STATE_TR_COMPLETE; | ||
2730 | if (sas_device->starget) { | ||
2731 | dewtprintk(ioc, starget_printk(KERN_INFO, | ||
2732 | sas_device->starget, "tr_complete:handle(0x%04x), " | ||
2733 | "(%s) ioc_status(0x%04x), loginfo(0x%08x), " | ||
2734 | "completed(%d)\n", sas_device->handle, | ||
2735 | (sas_device->state & MPT2SAS_REQ_SAS_CNTRL) ? | ||
2736 | "open" : "active", | ||
2737 | le16_to_cpu(mpi_reply->IOCStatus), | ||
2738 | le32_to_cpu(mpi_reply->IOCLogInfo), | ||
2739 | le32_to_cpu(mpi_reply->TerminationCount))); | ||
2740 | if (sas_device->starget->hostdata) { | ||
2741 | sas_target_priv_data = | ||
2742 | sas_device->starget->hostdata; | ||
2743 | sas_target_priv_data->tm_busy = 0; | ||
2744 | } | ||
2745 | } | ||
2746 | } else { | ||
2747 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT | ||
2748 | "tr_complete:handle(0x%04x), (open) ioc_status(0x%04x), " | ||
2749 | "loginfo(0x%08x), completed(%d)\n", ioc->name, | ||
2750 | handle, le16_to_cpu(mpi_reply->IOCStatus), | ||
2751 | le32_to_cpu(mpi_reply->IOCLogInfo), | ||
2752 | le32_to_cpu(mpi_reply->TerminationCount))); | ||
2753 | } | 2689 | } |
2754 | 2690 | ||
2755 | if (!list_empty(&ioc->delayed_tr_list)) { | 2691 | mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); |
2756 | delayed_tr = list_entry(ioc->delayed_tr_list.next, | 2692 | handle = le16_to_cpu(mpi_request_tm->DevHandle); |
2757 | struct _tr_list, list); | 2693 | if (handle != le16_to_cpu(mpi_reply->DevHandle)) { |
2758 | mpt2sas_base_free_smid(ioc, smid); | 2694 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: " |
2759 | if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL) | 2695 | "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle, |
2760 | _scsih_tm_tr_send(ioc, delayed_tr->handle); | 2696 | le16_to_cpu(mpi_reply->DevHandle), smid)); |
2761 | list_del(&delayed_tr->list); | 2697 | return 0; |
2762 | kfree(delayed_tr); | ||
2763 | rc = 0; /* tells base_interrupt not to free mf */ | ||
2764 | } else | ||
2765 | rc = 1; | ||
2766 | |||
2767 | if (sas_device && !(sas_device->state & MPT2SAS_REQ_SAS_CNTRL)) | ||
2768 | return rc; | ||
2769 | |||
2770 | if (ioc->shost_recovery) { | ||
2771 | printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", | ||
2772 | __func__, ioc->name); | ||
2773 | return rc; | ||
2774 | } | 2698 | } |
2775 | 2699 | ||
2700 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT | ||
2701 | "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " | ||
2702 | "loginfo(0x%08x), completed(%d)\n", ioc->name, | ||
2703 | handle, smid, le16_to_cpu(mpi_reply->IOCStatus), | ||
2704 | le32_to_cpu(mpi_reply->IOCLogInfo), | ||
2705 | le32_to_cpu(mpi_reply->TerminationCount))); | ||
2706 | |||
2776 | smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); | 2707 | smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); |
2777 | if (!smid_sas_ctrl) { | 2708 | if (!smid_sas_ctrl) { |
2778 | printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", | 2709 | printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", |
2779 | ioc->name, __func__); | 2710 | ioc->name, __func__); |
2780 | return rc; | 2711 | return 1; |
2781 | } | 2712 | } |
2782 | 2713 | ||
2783 | if (sas_device) | 2714 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), " |
2784 | sas_device->state |= MPTSAS_STATE_CNTRL_SEND; | 2715 | "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl, |
2785 | 2716 | ioc->tm_sas_control_cb_idx)); | |
2786 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl); | 2717 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl); |
2787 | memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); | 2718 | memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); |
2788 | mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; | 2719 | mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; |
2789 | mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; | 2720 | mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; |
2790 | mpi_request->DevHandle = mpi_reply->DevHandle; | 2721 | mpi_request->DevHandle = mpi_request_tm->DevHandle; |
2791 | mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); | 2722 | mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); |
2792 | return rc; | 2723 | |
2724 | if (!list_empty(&ioc->delayed_tr_list)) { | ||
2725 | delayed_tr = list_entry(ioc->delayed_tr_list.next, | ||
2726 | struct _tr_list, list); | ||
2727 | mpt2sas_base_free_smid(ioc, smid); | ||
2728 | _scsih_tm_tr_send(ioc, delayed_tr->handle); | ||
2729 | list_del(&delayed_tr->list); | ||
2730 | kfree(delayed_tr); | ||
2731 | return 0; /* tells base_interrupt not to free mf */ | ||
2732 | } | ||
2733 | return 1; | ||
2793 | } | 2734 | } |
2794 | 2735 | ||
2795 | /** | 2736 | /** |
@@ -3021,25 +2962,32 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) | |||
3021 | 2962 | ||
3022 | scmd->scsi_done = done; | 2963 | scmd->scsi_done = done; |
3023 | sas_device_priv_data = scmd->device->hostdata; | 2964 | sas_device_priv_data = scmd->device->hostdata; |
3024 | if (!sas_device_priv_data) { | 2965 | if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { |
3025 | scmd->result = DID_NO_CONNECT << 16; | 2966 | scmd->result = DID_NO_CONNECT << 16; |
3026 | scmd->scsi_done(scmd); | 2967 | scmd->scsi_done(scmd); |
3027 | return 0; | 2968 | return 0; |
3028 | } | 2969 | } |
3029 | 2970 | ||
3030 | sas_target_priv_data = sas_device_priv_data->sas_target; | 2971 | sas_target_priv_data = sas_device_priv_data->sas_target; |
3031 | if (!sas_target_priv_data || sas_target_priv_data->handle == | 2972 | /* invalid device handle */ |
3032 | MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) { | 2973 | if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) { |
3033 | scmd->result = DID_NO_CONNECT << 16; | 2974 | scmd->result = DID_NO_CONNECT << 16; |
3034 | scmd->scsi_done(scmd); | 2975 | scmd->scsi_done(scmd); |
3035 | return 0; | 2976 | return 0; |
3036 | } | 2977 | } |
3037 | 2978 | ||
3038 | /* see if we are busy with task managment stuff */ | 2979 | /* host recovery or link resets sent via IOCTLs */ |
3039 | if (sas_device_priv_data->block || sas_target_priv_data->tm_busy) | 2980 | if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) |
3040 | return SCSI_MLQUEUE_DEVICE_BUSY; | ||
3041 | else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) | ||
3042 | return SCSI_MLQUEUE_HOST_BUSY; | 2981 | return SCSI_MLQUEUE_HOST_BUSY; |
2982 | /* device busy with task managment */ | ||
2983 | else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy) | ||
2984 | return SCSI_MLQUEUE_DEVICE_BUSY; | ||
2985 | /* device has been deleted */ | ||
2986 | else if (sas_target_priv_data->deleted) { | ||
2987 | scmd->result = DID_NO_CONNECT << 16; | ||
2988 | scmd->scsi_done(scmd); | ||
2989 | return 0; | ||
2990 | } | ||
3043 | 2991 | ||
3044 | if (scmd->sc_data_direction == DMA_FROM_DEVICE) | 2992 | if (scmd->sc_data_direction == DMA_FROM_DEVICE) |
3045 | mpi_control = MPI2_SCSIIO_CONTROL_READ; | 2993 | mpi_control = MPI2_SCSIIO_CONTROL_READ; |
@@ -3110,8 +3058,11 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) | |||
3110 | } | 3058 | } |
3111 | } | 3059 | } |
3112 | 3060 | ||
3113 | mpt2sas_base_put_smid_scsi_io(ioc, smid, | 3061 | if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) |
3114 | sas_device_priv_data->sas_target->handle); | 3062 | mpt2sas_base_put_smid_scsi_io(ioc, smid, |
3063 | sas_device_priv_data->sas_target->handle); | ||
3064 | else | ||
3065 | mpt2sas_base_put_smid_default(ioc, smid); | ||
3115 | return 0; | 3066 | return 0; |
3116 | 3067 | ||
3117 | out: | 3068 | out: |
@@ -3301,8 +3252,8 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, | |||
3301 | struct sense_info data; | 3252 | struct sense_info data; |
3302 | _scsih_normalize_sense(scmd->sense_buffer, &data); | 3253 | _scsih_normalize_sense(scmd->sense_buffer, &data); |
3303 | printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: " | 3254 | printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: " |
3304 | "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey, | 3255 | "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey, |
3305 | data.asc, data.ascq); | 3256 | data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount)); |
3306 | } | 3257 | } |
3307 | 3258 | ||
3308 | if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { | 3259 | if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { |
@@ -3356,7 +3307,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) | |||
3356 | mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; | 3307 | mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; |
3357 | mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; | 3308 | mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; |
3358 | mpi_request.SlotStatus = | 3309 | mpi_request.SlotStatus = |
3359 | MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT; | 3310 | cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); |
3360 | mpi_request.DevHandle = cpu_to_le16(handle); | 3311 | mpi_request.DevHandle = cpu_to_le16(handle); |
3361 | mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS; | 3312 | mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS; |
3362 | if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, | 3313 | if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, |
@@ -4008,6 +3959,134 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) | |||
4008 | } | 3959 | } |
4009 | 3960 | ||
4010 | /** | 3961 | /** |
3962 | * _scsih_check_access_status - check access flags | ||
3963 | * @ioc: per adapter object | ||
3964 | * @sas_address: sas address | ||
3965 | * @handle: sas device handle | ||
3966 | * @access_flags: errors returned during discovery of the device | ||
3967 | * | ||
3968 | * Return 0 for success, else failure | ||
3969 | */ | ||
3970 | static u8 | ||
3971 | _scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, | ||
3972 | u16 handle, u8 access_status) | ||
3973 | { | ||
3974 | u8 rc = 1; | ||
3975 | char *desc = NULL; | ||
3976 | |||
3977 | switch (access_status) { | ||
3978 | case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS: | ||
3979 | case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION: | ||
3980 | rc = 0; | ||
3981 | break; | ||
3982 | case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED: | ||
3983 | desc = "sata capability failed"; | ||
3984 | break; | ||
3985 | case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT: | ||
3986 | desc = "sata affiliation conflict"; | ||
3987 | break; | ||
3988 | case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE: | ||
3989 | desc = "route not addressable"; | ||
3990 | break; | ||
3991 | case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE: | ||
3992 | desc = "smp error not addressable"; | ||
3993 | break; | ||
3994 | case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED: | ||
3995 | desc = "device blocked"; | ||
3996 | break; | ||
3997 | case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED: | ||
3998 | case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN: | ||
3999 | case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT: | ||
4000 | case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG: | ||
4001 | case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION: | ||
4002 | case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER: | ||
4003 | case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN: | ||
4004 | case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN: | ||
4005 | case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN: | ||
4006 | case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION: | ||
4007 | case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE: | ||
4008 | case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX: | ||
4009 | desc = "sata initialization failed"; | ||
4010 | break; | ||
4011 | default: | ||
4012 | desc = "unknown"; | ||
4013 | break; | ||
4014 | } | ||
4015 | |||
4016 | if (!rc) | ||
4017 | return 0; | ||
4018 | |||
4019 | printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), " | ||
4020 | "handle(0x%04x)\n", ioc->name, desc, | ||
4021 | (unsigned long long)sas_address, handle); | ||
4022 | return rc; | ||
4023 | } | ||
4024 | |||
4025 | static void | ||
4026 | _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) | ||
4027 | { | ||
4028 | Mpi2ConfigReply_t mpi_reply; | ||
4029 | Mpi2SasDevicePage0_t sas_device_pg0; | ||
4030 | struct _sas_device *sas_device; | ||
4031 | u32 ioc_status; | ||
4032 | unsigned long flags; | ||
4033 | u64 sas_address; | ||
4034 | struct scsi_target *starget; | ||
4035 | struct MPT2SAS_TARGET *sas_target_priv_data; | ||
4036 | u32 device_info; | ||
4037 | |||
4038 | if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, | ||
4039 | MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) | ||
4040 | return; | ||
4041 | |||
4042 | ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; | ||
4043 | if (ioc_status != MPI2_IOCSTATUS_SUCCESS) | ||
4044 | return; | ||
4045 | |||
4046 | /* check if this is end device */ | ||
4047 | device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); | ||
4048 | if (!(_scsih_is_end_device(device_info))) | ||
4049 | return; | ||
4050 | |||
4051 | spin_lock_irqsave(&ioc->sas_device_lock, flags); | ||
4052 | sas_address = le64_to_cpu(sas_device_pg0.SASAddress); | ||
4053 | sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, | ||
4054 | sas_address); | ||
4055 | |||
4056 | if (!sas_device) { | ||
4057 | printk(MPT2SAS_ERR_FMT "device is not present " | ||
4058 | "handle(0x%04x), no sas_device!!!\n", ioc->name, handle); | ||
4059 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | ||
4060 | return; | ||
4061 | } | ||
4062 | |||
4063 | if (unlikely(sas_device->handle != handle)) { | ||
4064 | starget = sas_device->starget; | ||
4065 | sas_target_priv_data = starget->hostdata; | ||
4066 | starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)" | ||
4067 | " to (0x%04x)!!!\n", sas_device->handle, handle); | ||
4068 | sas_target_priv_data->handle = handle; | ||
4069 | sas_device->handle = handle; | ||
4070 | } | ||
4071 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | ||
4072 | |||
4073 | /* check if device is present */ | ||
4074 | if (!(le16_to_cpu(sas_device_pg0.Flags) & | ||
4075 | MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { | ||
4076 | printk(MPT2SAS_ERR_FMT "device is not present " | ||
4077 | "handle(0x%04x), flags!!!\n", ioc->name, handle); | ||
4078 | return; | ||
4079 | } | ||
4080 | |||
4081 | /* check if there were any issues with discovery */ | ||
4082 | if (_scsih_check_access_status(ioc, sas_address, handle, | ||
4083 | sas_device_pg0.AccessStatus)) | ||
4084 | return; | ||
4085 | _scsih_ublock_io_device(ioc, handle); | ||
4086 | |||
4087 | } | ||
4088 | |||
4089 | /** | ||
4011 | * _scsih_add_device - creating sas device object | 4090 | * _scsih_add_device - creating sas device object |
4012 | * @ioc: per adapter object | 4091 | * @ioc: per adapter object |
4013 | * @handle: sas device handle | 4092 | * @handle: sas device handle |
@@ -4045,6 +4124,8 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) | |||
4045 | return -1; | 4124 | return -1; |
4046 | } | 4125 | } |
4047 | 4126 | ||
4127 | sas_address = le64_to_cpu(sas_device_pg0.SASAddress); | ||
4128 | |||
4048 | /* check if device is present */ | 4129 | /* check if device is present */ |
4049 | if (!(le16_to_cpu(sas_device_pg0.Flags) & | 4130 | if (!(le16_to_cpu(sas_device_pg0.Flags) & |
4050 | MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { | 4131 | MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { |
@@ -4055,15 +4136,10 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) | |||
4055 | return -1; | 4136 | return -1; |
4056 | } | 4137 | } |
4057 | 4138 | ||
4058 | /* check if there were any issus with discovery */ | 4139 | /* check if there were any issues with discovery */ |
4059 | if (sas_device_pg0.AccessStatus == | 4140 | if (_scsih_check_access_status(ioc, sas_address, handle, |
4060 | MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) { | 4141 | sas_device_pg0.AccessStatus)) |
4061 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", | ||
4062 | ioc->name, __FILE__, __LINE__, __func__); | ||
4063 | printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n", | ||
4064 | ioc->name, sas_device_pg0.AccessStatus); | ||
4065 | return -1; | 4142 | return -1; |
4066 | } | ||
4067 | 4143 | ||
4068 | /* check if this is end device */ | 4144 | /* check if this is end device */ |
4069 | device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); | 4145 | device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); |
@@ -4073,17 +4149,14 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) | |||
4073 | return -1; | 4149 | return -1; |
4074 | } | 4150 | } |
4075 | 4151 | ||
4076 | sas_address = le64_to_cpu(sas_device_pg0.SASAddress); | ||
4077 | 4152 | ||
4078 | spin_lock_irqsave(&ioc->sas_device_lock, flags); | 4153 | spin_lock_irqsave(&ioc->sas_device_lock, flags); |
4079 | sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, | 4154 | sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, |
4080 | sas_address); | 4155 | sas_address); |
4081 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | 4156 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); |
4082 | 4157 | ||
4083 | if (sas_device) { | 4158 | if (sas_device) |
4084 | _scsih_ublock_io_device(ioc, handle); | ||
4085 | return 0; | 4159 | return 0; |
4086 | } | ||
4087 | 4160 | ||
4088 | sas_device = kzalloc(sizeof(struct _sas_device), | 4161 | sas_device = kzalloc(sizeof(struct _sas_device), |
4089 | GFP_KERNEL); | 4162 | GFP_KERNEL); |
@@ -4126,67 +4199,38 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) | |||
4126 | } | 4199 | } |
4127 | 4200 | ||
4128 | /** | 4201 | /** |
4129 | * _scsih_remove_device - removing sas device object | 4202 | * _scsih_remove_pd_device - removing sas device pd object |
4130 | * @ioc: per adapter object | 4203 | * @ioc: per adapter object |
4131 | * @sas_device: the sas_device object | 4204 | * @sas_device_delete: the sas_device object |
4132 | * | 4205 | * |
4206 | * For hidden raid components, we do driver-fw handshake from | ||
4207 | * hotplug work threads. | ||
4133 | * Return nothing. | 4208 | * Return nothing. |
4134 | */ | 4209 | */ |
4135 | static void | 4210 | static void |
4136 | _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device | 4211 | _scsih_remove_pd_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device |
4137 | *sas_device) | 4212 | sas_device) |
4138 | { | 4213 | { |
4139 | struct MPT2SAS_TARGET *sas_target_priv_data; | ||
4140 | Mpi2SasIoUnitControlReply_t mpi_reply; | 4214 | Mpi2SasIoUnitControlReply_t mpi_reply; |
4141 | Mpi2SasIoUnitControlRequest_t mpi_request; | 4215 | Mpi2SasIoUnitControlRequest_t mpi_request; |
4142 | u16 device_handle, handle; | 4216 | u16 vol_handle, handle; |
4143 | |||
4144 | if (!sas_device) | ||
4145 | return; | ||
4146 | 4217 | ||
4147 | handle = sas_device->handle; | 4218 | handle = sas_device.handle; |
4148 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x)," | 4219 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x)," |
4149 | " sas_addr(0x%016llx)\n", ioc->name, __func__, handle, | 4220 | " sas_addr(0x%016llx)\n", ioc->name, __func__, handle, |
4150 | (unsigned long long) sas_device->sas_address)); | 4221 | (unsigned long long) sas_device.sas_address)); |
4151 | |||
4152 | if (sas_device->starget && sas_device->starget->hostdata) { | ||
4153 | sas_target_priv_data = sas_device->starget->hostdata; | ||
4154 | sas_target_priv_data->deleted = 1; | ||
4155 | } | ||
4156 | |||
4157 | if (ioc->remove_host || ioc->shost_recovery || !handle) | ||
4158 | goto out; | ||
4159 | 4222 | ||
4160 | if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) { | 4223 | vol_handle = sas_device.volume_handle; |
4161 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip " | 4224 | if (!vol_handle) |
4162 | "target_reset handle(0x%04x)\n", ioc->name, | 4225 | return; |
4163 | handle)); | 4226 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: " |
4164 | goto skip_tr; | 4227 | "handle(0x%04x)\n", ioc->name, vol_handle)); |
4165 | } | 4228 | mpt2sas_scsih_issue_tm(ioc, vol_handle, 0, 0, 0, |
4166 | 4229 | MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, NULL); | |
4167 | /* Target Reset to flush out all the outstanding IO */ | 4230 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset " |
4168 | device_handle = (sas_device->hidden_raid_component) ? | 4231 | "done: handle(0x%04x)\n", ioc->name, vol_handle)); |
4169 | sas_device->volume_handle : handle; | 4232 | if (ioc->shost_recovery) |
4170 | if (device_handle) { | 4233 | return; |
4171 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: " | ||
4172 | "handle(0x%04x)\n", ioc->name, device_handle)); | ||
4173 | mutex_lock(&ioc->tm_cmds.mutex); | ||
4174 | mpt2sas_scsih_issue_tm(ioc, device_handle, 0, | ||
4175 | MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10); | ||
4176 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; | ||
4177 | mutex_unlock(&ioc->tm_cmds.mutex); | ||
4178 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset " | ||
4179 | "done: handle(0x%04x)\n", ioc->name, device_handle)); | ||
4180 | if (ioc->shost_recovery) | ||
4181 | goto out; | ||
4182 | } | ||
4183 | skip_tr: | ||
4184 | |||
4185 | if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) { | ||
4186 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip " | ||
4187 | "sas_cntrl handle(0x%04x)\n", ioc->name, handle)); | ||
4188 | goto out; | ||
4189 | } | ||
4190 | 4234 | ||
4191 | /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */ | 4235 | /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */ |
4192 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle" | 4236 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle" |
@@ -4194,34 +4238,68 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device | |||
4194 | memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); | 4238 | memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); |
4195 | mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; | 4239 | mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; |
4196 | mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE; | 4240 | mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE; |
4197 | mpi_request.DevHandle = handle; | 4241 | mpi_request.DevHandle = cpu_to_le16(handle); |
4198 | mpi_request.VF_ID = 0; /* TODO */ | ||
4199 | mpi_request.VP_ID = 0; | ||
4200 | if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, | 4242 | if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, |
4201 | &mpi_request)) != 0) { | 4243 | &mpi_request)) != 0) |
4202 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", | 4244 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", |
4203 | ioc->name, __FILE__, __LINE__, __func__); | 4245 | ioc->name, __FILE__, __LINE__, __func__); |
4204 | } | ||
4205 | 4246 | ||
4206 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status" | 4247 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status" |
4207 | "(0x%04x), loginfo(0x%08x)\n", ioc->name, | 4248 | "(0x%04x), loginfo(0x%08x)\n", ioc->name, |
4208 | le16_to_cpu(mpi_reply.IOCStatus), | 4249 | le16_to_cpu(mpi_reply.IOCStatus), |
4209 | le32_to_cpu(mpi_reply.IOCLogInfo))); | 4250 | le32_to_cpu(mpi_reply.IOCLogInfo))); |
4210 | 4251 | ||
4211 | out: | 4252 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle(0x%04x)," |
4253 | " sas_addr(0x%016llx)\n", ioc->name, __func__, handle, | ||
4254 | (unsigned long long) sas_device.sas_address)); | ||
4255 | } | ||
4212 | 4256 | ||
4213 | _scsih_ublock_io_device(ioc, handle); | 4257 | /** |
4258 | * _scsih_remove_device - removing sas device object | ||
4259 | * @ioc: per adapter object | ||
4260 | * @sas_device_delete: the sas_device object | ||
4261 | * | ||
4262 | * Return nothing. | ||
4263 | */ | ||
4264 | static void | ||
4265 | _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, | ||
4266 | struct _sas_device *sas_device) | ||
4267 | { | ||
4268 | struct _sas_device sas_device_backup; | ||
4269 | struct MPT2SAS_TARGET *sas_target_priv_data; | ||
4214 | 4270 | ||
4215 | mpt2sas_transport_port_remove(ioc, sas_device->sas_address, | 4271 | if (!sas_device) |
4216 | sas_device->sas_address_parent); | 4272 | return; |
4217 | 4273 | ||
4218 | printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" | 4274 | memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device)); |
4219 | "(0x%016llx)\n", ioc->name, handle, | ||
4220 | (unsigned long long) sas_device->sas_address); | ||
4221 | _scsih_sas_device_remove(ioc, sas_device); | 4275 | _scsih_sas_device_remove(ioc, sas_device); |
4222 | 4276 | ||
4223 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle" | 4277 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: " |
4224 | "(0x%04x)\n", ioc->name, __func__, handle)); | 4278 | "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, |
4279 | sas_device_backup.handle, (unsigned long long) | ||
4280 | sas_device_backup.sas_address)); | ||
4281 | |||
4282 | if (sas_device_backup.starget && sas_device_backup.starget->hostdata) { | ||
4283 | sas_target_priv_data = sas_device_backup.starget->hostdata; | ||
4284 | sas_target_priv_data->deleted = 1; | ||
4285 | } | ||
4286 | |||
4287 | if (sas_device_backup.hidden_raid_component) | ||
4288 | _scsih_remove_pd_device(ioc, sas_device_backup); | ||
4289 | |||
4290 | _scsih_ublock_io_device(ioc, sas_device_backup.handle); | ||
4291 | |||
4292 | mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address, | ||
4293 | sas_device_backup.sas_address_parent); | ||
4294 | |||
4295 | printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" | ||
4296 | "(0x%016llx)\n", ioc->name, sas_device_backup.handle, | ||
4297 | (unsigned long long) sas_device_backup.sas_address); | ||
4298 | |||
4299 | dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: " | ||
4300 | "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, | ||
4301 | sas_device_backup.handle, (unsigned long long) | ||
4302 | sas_device_backup.sas_address)); | ||
4225 | } | 4303 | } |
4226 | 4304 | ||
4227 | #ifdef CONFIG_SCSI_MPT2SAS_LOGGING | 4305 | #ifdef CONFIG_SCSI_MPT2SAS_LOGGING |
@@ -4331,7 +4409,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, | |||
4331 | _scsih_sas_topology_change_event_debug(ioc, event_data); | 4409 | _scsih_sas_topology_change_event_debug(ioc, event_data); |
4332 | #endif | 4410 | #endif |
4333 | 4411 | ||
4334 | if (ioc->shost_recovery) | 4412 | if (ioc->shost_recovery || ioc->remove_host) |
4335 | return; | 4413 | return; |
4336 | 4414 | ||
4337 | if (!ioc->sas_hba.num_phys) | 4415 | if (!ioc->sas_hba.num_phys) |
@@ -4370,7 +4448,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, | |||
4370 | "expander event\n", ioc->name)); | 4448 | "expander event\n", ioc->name)); |
4371 | return; | 4449 | return; |
4372 | } | 4450 | } |
4373 | if (ioc->shost_recovery) | 4451 | if (ioc->shost_recovery || ioc->remove_host) |
4374 | return; | 4452 | return; |
4375 | phy_number = event_data->StartPhyNum + i; | 4453 | phy_number = event_data->StartPhyNum + i; |
4376 | reason_code = event_data->PHY[i].PhyStatus & | 4454 | reason_code = event_data->PHY[i].PhyStatus & |
@@ -4393,8 +4471,10 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, | |||
4393 | mpt2sas_transport_update_links(ioc, sas_address, | 4471 | mpt2sas_transport_update_links(ioc, sas_address, |
4394 | handle, phy_number, link_rate); | 4472 | handle, phy_number, link_rate); |
4395 | 4473 | ||
4396 | if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5) | 4474 | if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) |
4397 | _scsih_ublock_io_device(ioc, handle); | 4475 | break; |
4476 | |||
4477 | _scsih_check_device(ioc, handle); | ||
4398 | break; | 4478 | break; |
4399 | case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: | 4479 | case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: |
4400 | 4480 | ||
@@ -4520,10 +4600,10 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, | |||
4520 | event_data); | 4600 | event_data); |
4521 | #endif | 4601 | #endif |
4522 | 4602 | ||
4523 | if (!(event_data->ReasonCode == | 4603 | if (event_data->ReasonCode != |
4524 | MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && | 4604 | MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && |
4525 | event_data->ReasonCode == | 4605 | event_data->ReasonCode != |
4526 | MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)) | 4606 | MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET) |
4527 | return; | 4607 | return; |
4528 | 4608 | ||
4529 | spin_lock_irqsave(&ioc->sas_device_lock, flags); | 4609 | spin_lock_irqsave(&ioc->sas_device_lock, flags); |
@@ -4630,7 +4710,6 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, | |||
4630 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, | 4710 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, |
4631 | __func__)); | 4711 | __func__)); |
4632 | 4712 | ||
4633 | mutex_lock(&ioc->tm_cmds.mutex); | ||
4634 | termination_count = 0; | 4713 | termination_count = 0; |
4635 | query_count = 0; | 4714 | query_count = 0; |
4636 | mpi_reply = ioc->tm_cmds.reply; | 4715 | mpi_reply = ioc->tm_cmds.reply; |
@@ -4654,8 +4733,8 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, | |||
4654 | lun = sas_device_priv_data->lun; | 4733 | lun = sas_device_priv_data->lun; |
4655 | query_count++; | 4734 | query_count++; |
4656 | 4735 | ||
4657 | mpt2sas_scsih_issue_tm(ioc, handle, lun, | 4736 | mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, |
4658 | MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30); | 4737 | MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL); |
4659 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; | 4738 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; |
4660 | ioc_status = le16_to_cpu(mpi_reply->IOCStatus) | 4739 | ioc_status = le16_to_cpu(mpi_reply->IOCStatus) |
4661 | & MPI2_IOCSTATUS_MASK; | 4740 | & MPI2_IOCSTATUS_MASK; |
@@ -4666,13 +4745,11 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, | |||
4666 | MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) | 4745 | MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) |
4667 | continue; | 4746 | continue; |
4668 | 4747 | ||
4669 | mpt2sas_scsih_issue_tm(ioc, handle, lun, | 4748 | mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, |
4670 | MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30); | 4749 | MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30, NULL); |
4671 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; | ||
4672 | termination_count += le32_to_cpu(mpi_reply->TerminationCount); | 4750 | termination_count += le32_to_cpu(mpi_reply->TerminationCount); |
4673 | } | 4751 | } |
4674 | ioc->broadcast_aen_busy = 0; | 4752 | ioc->broadcast_aen_busy = 0; |
4675 | mutex_unlock(&ioc->tm_cmds.mutex); | ||
4676 | 4753 | ||
4677 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT | 4754 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT |
4678 | "%s - exit, query_count = %d termination_count = %d\n", | 4755 | "%s - exit, query_count = %d termination_count = %d\n", |
@@ -5442,6 +5519,26 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work | |||
5442 | } | 5519 | } |
5443 | 5520 | ||
5444 | /** | 5521 | /** |
5522 | * _scsih_prep_device_scan - initialize parameters prior to device scan | ||
5523 | * @ioc: per adapter object | ||
5524 | * | ||
5525 | * Set the deleted flag prior to device scan. If the device is found during | ||
5526 | * the scan, then we clear the deleted flag. | ||
5527 | */ | ||
5528 | static void | ||
5529 | _scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc) | ||
5530 | { | ||
5531 | struct MPT2SAS_DEVICE *sas_device_priv_data; | ||
5532 | struct scsi_device *sdev; | ||
5533 | |||
5534 | shost_for_each_device(sdev, ioc->shost) { | ||
5535 | sas_device_priv_data = sdev->hostdata; | ||
5536 | if (sas_device_priv_data && sas_device_priv_data->sas_target) | ||
5537 | sas_device_priv_data->sas_target->deleted = 1; | ||
5538 | } | ||
5539 | } | ||
5540 | |||
5541 | /** | ||
5445 | * _scsih_mark_responding_sas_device - mark a sas_devices as responding | 5542 | * _scsih_mark_responding_sas_device - mark a sas_devices as responding |
5446 | * @ioc: per adapter object | 5543 | * @ioc: per adapter object |
5447 | * @sas_address: sas address | 5544 | * @sas_address: sas address |
@@ -5467,10 +5564,13 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, | |||
5467 | if (sas_device->sas_address == sas_address && | 5564 | if (sas_device->sas_address == sas_address && |
5468 | sas_device->slot == slot && sas_device->starget) { | 5565 | sas_device->slot == slot && sas_device->starget) { |
5469 | sas_device->responding = 1; | 5566 | sas_device->responding = 1; |
5470 | sas_device->state = 0; | ||
5471 | starget = sas_device->starget; | 5567 | starget = sas_device->starget; |
5472 | sas_target_priv_data = starget->hostdata; | 5568 | if (starget && starget->hostdata) { |
5473 | sas_target_priv_data->tm_busy = 0; | 5569 | sas_target_priv_data = starget->hostdata; |
5570 | sas_target_priv_data->tm_busy = 0; | ||
5571 | sas_target_priv_data->deleted = 0; | ||
5572 | } else | ||
5573 | sas_target_priv_data = NULL; | ||
5474 | starget_printk(KERN_INFO, sas_device->starget, | 5574 | starget_printk(KERN_INFO, sas_device->starget, |
5475 | "handle(0x%04x), sas_addr(0x%016llx), enclosure " | 5575 | "handle(0x%04x), sas_addr(0x%016llx), enclosure " |
5476 | "logical id(0x%016llx), slot(%d)\n", handle, | 5576 | "logical id(0x%016llx), slot(%d)\n", handle, |
@@ -5483,7 +5583,8 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, | |||
5483 | printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", | 5583 | printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", |
5484 | sas_device->handle); | 5584 | sas_device->handle); |
5485 | sas_device->handle = handle; | 5585 | sas_device->handle = handle; |
5486 | sas_target_priv_data->handle = handle; | 5586 | if (sas_target_priv_data) |
5587 | sas_target_priv_data->handle = handle; | ||
5487 | goto out; | 5588 | goto out; |
5488 | } | 5589 | } |
5489 | } | 5590 | } |
@@ -5558,6 +5659,12 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, | |||
5558 | spin_lock_irqsave(&ioc->raid_device_lock, flags); | 5659 | spin_lock_irqsave(&ioc->raid_device_lock, flags); |
5559 | list_for_each_entry(raid_device, &ioc->raid_device_list, list) { | 5660 | list_for_each_entry(raid_device, &ioc->raid_device_list, list) { |
5560 | if (raid_device->wwid == wwid && raid_device->starget) { | 5661 | if (raid_device->wwid == wwid && raid_device->starget) { |
5662 | starget = raid_device->starget; | ||
5663 | if (starget && starget->hostdata) { | ||
5664 | sas_target_priv_data = starget->hostdata; | ||
5665 | sas_target_priv_data->deleted = 0; | ||
5666 | } else | ||
5667 | sas_target_priv_data = NULL; | ||
5561 | raid_device->responding = 1; | 5668 | raid_device->responding = 1; |
5562 | starget_printk(KERN_INFO, raid_device->starget, | 5669 | starget_printk(KERN_INFO, raid_device->starget, |
5563 | "handle(0x%04x), wwid(0x%016llx)\n", handle, | 5670 | "handle(0x%04x), wwid(0x%016llx)\n", handle, |
@@ -5567,9 +5674,8 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, | |||
5567 | printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", | 5674 | printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", |
5568 | raid_device->handle); | 5675 | raid_device->handle); |
5569 | raid_device->handle = handle; | 5676 | raid_device->handle = handle; |
5570 | starget = raid_device->starget; | 5677 | if (sas_target_priv_data) |
5571 | sas_target_priv_data = starget->hostdata; | 5678 | sas_target_priv_data->handle = handle; |
5572 | sas_target_priv_data->handle = handle; | ||
5573 | goto out; | 5679 | goto out; |
5574 | } | 5680 | } |
5575 | } | 5681 | } |
@@ -5694,13 +5800,13 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc) | |||
5694 | } | 5800 | } |
5695 | 5801 | ||
5696 | /** | 5802 | /** |
5697 | * _scsih_remove_unresponding_devices - removing unresponding devices | 5803 | * _scsih_remove_unresponding_sas_devices - removing unresponding devices |
5698 | * @ioc: per adapter object | 5804 | * @ioc: per adapter object |
5699 | * | 5805 | * |
5700 | * Return nothing. | 5806 | * Return nothing. |
5701 | */ | 5807 | */ |
5702 | static void | 5808 | static void |
5703 | _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) | 5809 | _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) |
5704 | { | 5810 | { |
5705 | struct _sas_device *sas_device, *sas_device_next; | 5811 | struct _sas_device *sas_device, *sas_device_next; |
5706 | struct _sas_node *sas_expander; | 5812 | struct _sas_node *sas_expander; |
@@ -5722,8 +5828,6 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) | |||
5722 | (unsigned long long) | 5828 | (unsigned long long) |
5723 | sas_device->enclosure_logical_id, | 5829 | sas_device->enclosure_logical_id, |
5724 | sas_device->slot); | 5830 | sas_device->slot); |
5725 | /* invalidate the device handle */ | ||
5726 | sas_device->handle = 0; | ||
5727 | _scsih_remove_device(ioc, sas_device); | 5831 | _scsih_remove_device(ioc, sas_device); |
5728 | } | 5832 | } |
5729 | 5833 | ||
@@ -5774,32 +5878,33 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) | |||
5774 | case MPT2_IOC_PRE_RESET: | 5878 | case MPT2_IOC_PRE_RESET: |
5775 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | 5879 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " |
5776 | "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); | 5880 | "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); |
5777 | _scsih_fw_event_off(ioc); | ||
5778 | break; | 5881 | break; |
5779 | case MPT2_IOC_AFTER_RESET: | 5882 | case MPT2_IOC_AFTER_RESET: |
5780 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | 5883 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " |
5781 | "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); | 5884 | "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); |
5885 | if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) { | ||
5886 | ioc->scsih_cmds.status |= MPT2_CMD_RESET; | ||
5887 | mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid); | ||
5888 | complete(&ioc->scsih_cmds.done); | ||
5889 | } | ||
5782 | if (ioc->tm_cmds.status & MPT2_CMD_PENDING) { | 5890 | if (ioc->tm_cmds.status & MPT2_CMD_PENDING) { |
5783 | ioc->tm_cmds.status |= MPT2_CMD_RESET; | 5891 | ioc->tm_cmds.status |= MPT2_CMD_RESET; |
5784 | mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid); | 5892 | mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid); |
5785 | complete(&ioc->tm_cmds.done); | 5893 | complete(&ioc->tm_cmds.done); |
5786 | } | 5894 | } |
5787 | _scsih_fw_event_on(ioc); | 5895 | _scsih_fw_event_cleanup_queue(ioc); |
5788 | _scsih_flush_running_cmds(ioc); | 5896 | _scsih_flush_running_cmds(ioc); |
5897 | _scsih_queue_rescan(ioc); | ||
5789 | break; | 5898 | break; |
5790 | case MPT2_IOC_DONE_RESET: | 5899 | case MPT2_IOC_DONE_RESET: |
5791 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | 5900 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " |
5792 | "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); | 5901 | "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); |
5793 | _scsih_sas_host_refresh(ioc); | 5902 | _scsih_sas_host_refresh(ioc); |
5903 | _scsih_prep_device_scan(ioc); | ||
5794 | _scsih_search_responding_sas_devices(ioc); | 5904 | _scsih_search_responding_sas_devices(ioc); |
5795 | _scsih_search_responding_raid_devices(ioc); | 5905 | _scsih_search_responding_raid_devices(ioc); |
5796 | _scsih_search_responding_expanders(ioc); | 5906 | _scsih_search_responding_expanders(ioc); |
5797 | break; | 5907 | break; |
5798 | case MPT2_IOC_RUNNING: | ||
5799 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | ||
5800 | "MPT2_IOC_RUNNING\n", ioc->name, __func__)); | ||
5801 | _scsih_remove_unresponding_devices(ioc); | ||
5802 | break; | ||
5803 | } | 5908 | } |
5804 | } | 5909 | } |
5805 | 5910 | ||
@@ -5815,21 +5920,28 @@ static void | |||
5815 | _firmware_event_work(struct work_struct *work) | 5920 | _firmware_event_work(struct work_struct *work) |
5816 | { | 5921 | { |
5817 | struct fw_event_work *fw_event = container_of(work, | 5922 | struct fw_event_work *fw_event = container_of(work, |
5818 | struct fw_event_work, work); | 5923 | struct fw_event_work, delayed_work.work); |
5819 | unsigned long flags; | 5924 | unsigned long flags; |
5820 | struct MPT2SAS_ADAPTER *ioc = fw_event->ioc; | 5925 | struct MPT2SAS_ADAPTER *ioc = fw_event->ioc; |
5821 | 5926 | ||
5822 | /* the queue is being flushed so ignore this event */ | 5927 | /* the queue is being flushed so ignore this event */ |
5823 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | 5928 | if (ioc->remove_host || fw_event->cancel_pending_work) { |
5824 | if (ioc->fw_events_off || ioc->remove_host) { | ||
5825 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
5826 | _scsih_fw_event_free(ioc, fw_event); | 5929 | _scsih_fw_event_free(ioc, fw_event); |
5827 | return; | 5930 | return; |
5828 | } | 5931 | } |
5829 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
5830 | 5932 | ||
5831 | if (ioc->shost_recovery) { | 5933 | if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) { |
5832 | _scsih_fw_event_requeue(ioc, fw_event, 1000); | 5934 | _scsih_fw_event_free(ioc, fw_event); |
5935 | spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); | ||
5936 | if (ioc->shost_recovery) { | ||
5937 | init_completion(&ioc->shost_recovery_done); | ||
5938 | spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, | ||
5939 | flags); | ||
5940 | wait_for_completion(&ioc->shost_recovery_done); | ||
5941 | } else | ||
5942 | spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, | ||
5943 | flags); | ||
5944 | _scsih_remove_unresponding_sas_devices(ioc); | ||
5833 | return; | 5945 | return; |
5834 | } | 5946 | } |
5835 | 5947 | ||
@@ -5891,16 +6003,12 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, | |||
5891 | { | 6003 | { |
5892 | struct fw_event_work *fw_event; | 6004 | struct fw_event_work *fw_event; |
5893 | Mpi2EventNotificationReply_t *mpi_reply; | 6005 | Mpi2EventNotificationReply_t *mpi_reply; |
5894 | unsigned long flags; | ||
5895 | u16 event; | 6006 | u16 event; |
6007 | u16 sz; | ||
5896 | 6008 | ||
5897 | /* events turned off due to host reset or driver unloading */ | 6009 | /* events turned off due to host reset or driver unloading */ |
5898 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | 6010 | if (ioc->remove_host) |
5899 | if (ioc->fw_events_off || ioc->remove_host) { | ||
5900 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
5901 | return 1; | 6011 | return 1; |
5902 | } | ||
5903 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
5904 | 6012 | ||
5905 | mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); | 6013 | mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); |
5906 | event = le16_to_cpu(mpi_reply->Event); | 6014 | event = le16_to_cpu(mpi_reply->Event); |
@@ -5947,8 +6055,8 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, | |||
5947 | ioc->name, __FILE__, __LINE__, __func__); | 6055 | ioc->name, __FILE__, __LINE__, __func__); |
5948 | return 1; | 6056 | return 1; |
5949 | } | 6057 | } |
5950 | fw_event->event_data = | 6058 | sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; |
5951 | kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC); | 6059 | fw_event->event_data = kzalloc(sz, GFP_ATOMIC); |
5952 | if (!fw_event->event_data) { | 6060 | if (!fw_event->event_data) { |
5953 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", | 6061 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", |
5954 | ioc->name, __FILE__, __LINE__, __func__); | 6062 | ioc->name, __FILE__, __LINE__, __func__); |
@@ -5957,7 +6065,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, | |||
5957 | } | 6065 | } |
5958 | 6066 | ||
5959 | memcpy(fw_event->event_data, mpi_reply->EventData, | 6067 | memcpy(fw_event->event_data, mpi_reply->EventData, |
5960 | mpi_reply->EventDataLength*4); | 6068 | sz); |
5961 | fw_event->ioc = ioc; | 6069 | fw_event->ioc = ioc; |
5962 | fw_event->VF_ID = mpi_reply->VF_ID; | 6070 | fw_event->VF_ID = mpi_reply->VF_ID; |
5963 | fw_event->VP_ID = mpi_reply->VP_ID; | 6071 | fw_event->VP_ID = mpi_reply->VP_ID; |
@@ -6158,6 +6266,18 @@ _scsih_shutdown(struct pci_dev *pdev) | |||
6158 | { | 6266 | { |
6159 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | 6267 | struct Scsi_Host *shost = pci_get_drvdata(pdev); |
6160 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | 6268 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); |
6269 | struct workqueue_struct *wq; | ||
6270 | unsigned long flags; | ||
6271 | |||
6272 | ioc->remove_host = 1; | ||
6273 | _scsih_fw_event_cleanup_queue(ioc); | ||
6274 | |||
6275 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
6276 | wq = ioc->firmware_event_thread; | ||
6277 | ioc->firmware_event_thread = NULL; | ||
6278 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
6279 | if (wq) | ||
6280 | destroy_workqueue(wq); | ||
6161 | 6281 | ||
6162 | _scsih_ir_shutdown(ioc); | 6282 | _scsih_ir_shutdown(ioc); |
6163 | mpt2sas_base_detach(ioc); | 6283 | mpt2sas_base_detach(ioc); |
@@ -6184,7 +6304,7 @@ _scsih_remove(struct pci_dev *pdev) | |||
6184 | unsigned long flags; | 6304 | unsigned long flags; |
6185 | 6305 | ||
6186 | ioc->remove_host = 1; | 6306 | ioc->remove_host = 1; |
6187 | _scsih_fw_event_off(ioc); | 6307 | _scsih_fw_event_cleanup_queue(ioc); |
6188 | 6308 | ||
6189 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | 6309 | spin_lock_irqsave(&ioc->fw_event_lock, flags); |
6190 | wq = ioc->firmware_event_thread; | 6310 | wq = ioc->firmware_event_thread; |
@@ -6557,6 +6677,122 @@ _scsih_resume(struct pci_dev *pdev) | |||
6557 | } | 6677 | } |
6558 | #endif /* CONFIG_PM */ | 6678 | #endif /* CONFIG_PM */ |
6559 | 6679 | ||
6680 | /** | ||
6681 | * _scsih_pci_error_detected - Called when a PCI error is detected. | ||
6682 | * @pdev: PCI device struct | ||
6683 | * @state: PCI channel state | ||
6684 | * | ||
6685 | * Description: Called when a PCI error is detected. | ||
6686 | * | ||
6687 | * Return value: | ||
6688 | * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT | ||
6689 | */ | ||
6690 | static pci_ers_result_t | ||
6691 | _scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) | ||
6692 | { | ||
6693 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | ||
6694 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
6695 | |||
6696 | printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n", | ||
6697 | ioc->name, state); | ||
6698 | |||
6699 | switch (state) { | ||
6700 | case pci_channel_io_normal: | ||
6701 | return PCI_ERS_RESULT_CAN_RECOVER; | ||
6702 | case pci_channel_io_frozen: | ||
6703 | scsi_block_requests(ioc->shost); | ||
6704 | mpt2sas_base_stop_watchdog(ioc); | ||
6705 | mpt2sas_base_free_resources(ioc); | ||
6706 | return PCI_ERS_RESULT_NEED_RESET; | ||
6707 | case pci_channel_io_perm_failure: | ||
6708 | _scsih_remove(pdev); | ||
6709 | return PCI_ERS_RESULT_DISCONNECT; | ||
6710 | } | ||
6711 | return PCI_ERS_RESULT_NEED_RESET; | ||
6712 | } | ||
6713 | |||
6714 | /** | ||
6715 | * _scsih_pci_slot_reset - Called when PCI slot has been reset. | ||
6716 | * @pdev: PCI device struct | ||
6717 | * | ||
6718 | * Description: This routine is called by the pci error recovery | ||
6719 | * code after the PCI slot has been reset, just before we | ||
6720 | * should resume normal operations. | ||
6721 | */ | ||
6722 | static pci_ers_result_t | ||
6723 | _scsih_pci_slot_reset(struct pci_dev *pdev) | ||
6724 | { | ||
6725 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | ||
6726 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
6727 | int rc; | ||
6728 | |||
6729 | printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n", | ||
6730 | ioc->name); | ||
6731 | |||
6732 | ioc->pdev = pdev; | ||
6733 | rc = mpt2sas_base_map_resources(ioc); | ||
6734 | if (rc) | ||
6735 | return PCI_ERS_RESULT_DISCONNECT; | ||
6736 | |||
6737 | |||
6738 | rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, | ||
6739 | FORCE_BIG_HAMMER); | ||
6740 | |||
6741 | printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name, | ||
6742 | (rc == 0) ? "success" : "failed"); | ||
6743 | |||
6744 | if (!rc) | ||
6745 | return PCI_ERS_RESULT_RECOVERED; | ||
6746 | else | ||
6747 | return PCI_ERS_RESULT_DISCONNECT; | ||
6748 | } | ||
6749 | |||
6750 | /** | ||
6751 | * _scsih_pci_resume() - resume normal ops after PCI reset | ||
6752 | * @pdev: pointer to PCI device | ||
6753 | * | ||
6754 | * Called when the error recovery driver tells us that its | ||
6755 | * OK to resume normal operation. Use completion to allow | ||
6756 | * halted scsi ops to resume. | ||
6757 | */ | ||
6758 | static void | ||
6759 | _scsih_pci_resume(struct pci_dev *pdev) | ||
6760 | { | ||
6761 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | ||
6762 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
6763 | |||
6764 | printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name); | ||
6765 | |||
6766 | pci_cleanup_aer_uncorrect_error_status(pdev); | ||
6767 | mpt2sas_base_start_watchdog(ioc); | ||
6768 | scsi_unblock_requests(ioc->shost); | ||
6769 | } | ||
6770 | |||
6771 | /** | ||
6772 | * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers | ||
6773 | * @pdev: pointer to PCI device | ||
6774 | */ | ||
6775 | static pci_ers_result_t | ||
6776 | _scsih_pci_mmio_enabled(struct pci_dev *pdev) | ||
6777 | { | ||
6778 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | ||
6779 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
6780 | |||
6781 | printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n", | ||
6782 | ioc->name); | ||
6783 | |||
6784 | /* TODO - dump whatever for debugging purposes */ | ||
6785 | |||
6786 | /* Request a slot reset. */ | ||
6787 | return PCI_ERS_RESULT_NEED_RESET; | ||
6788 | } | ||
6789 | |||
6790 | static struct pci_error_handlers _scsih_err_handler = { | ||
6791 | .error_detected = _scsih_pci_error_detected, | ||
6792 | .mmio_enabled = _scsih_pci_mmio_enabled, | ||
6793 | .slot_reset = _scsih_pci_slot_reset, | ||
6794 | .resume = _scsih_pci_resume, | ||
6795 | }; | ||
6560 | 6796 | ||
6561 | static struct pci_driver scsih_driver = { | 6797 | static struct pci_driver scsih_driver = { |
6562 | .name = MPT2SAS_DRIVER_NAME, | 6798 | .name = MPT2SAS_DRIVER_NAME, |
@@ -6564,6 +6800,7 @@ static struct pci_driver scsih_driver = { | |||
6564 | .probe = _scsih_probe, | 6800 | .probe = _scsih_probe, |
6565 | .remove = __devexit_p(_scsih_remove), | 6801 | .remove = __devexit_p(_scsih_remove), |
6566 | .shutdown = _scsih_shutdown, | 6802 | .shutdown = _scsih_shutdown, |
6803 | .err_handler = &_scsih_err_handler, | ||
6567 | #ifdef CONFIG_PM | 6804 | #ifdef CONFIG_PM |
6568 | .suspend = _scsih_suspend, | 6805 | .suspend = _scsih_suspend, |
6569 | .resume = _scsih_resume, | 6806 | .resume = _scsih_resume, |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index bd7ca2b49f81..2727c3b65104 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * SAS Transport Layer for MPT (Message Passing Technology) based controllers | 2 | * SAS Transport Layer for MPT (Message Passing Technology) based controllers |
3 | * | 3 | * |
4 | * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c | 4 | * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c |
5 | * Copyright (C) 2007-2009 LSI Corporation | 5 | * Copyright (C) 2007-2010 LSI Corporation |
6 | * (mailto:DL-MPTFusionLinux@lsi.com) | 6 | * (mailto:DL-MPTFusionLinux@lsi.com) |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
@@ -465,6 +465,85 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, | |||
465 | return rc; | 465 | return rc; |
466 | } | 466 | } |
467 | 467 | ||
468 | |||
469 | /** | ||
470 | * _transport_delete_duplicate_port - (see below description) | ||
471 | * @ioc: per adapter object | ||
472 | * @sas_node: sas node object (either expander or sas host) | ||
473 | * @sas_address: sas address of device being added | ||
474 | * @phy_num: phy number | ||
475 | * | ||
476 | * This function is called when attempting to add a new port that is claiming | ||
477 | * the same phy resources already in use by another port. If we don't release | ||
478 | * the claimed phy resources, the sas transport layer will hang from the BUG | ||
479 | * in sas_port_add_phy. | ||
480 | * | ||
481 | * The reason we would hit this issue is becuase someone is changing the | ||
482 | * sas address of a device on the fly, meanwhile controller firmware sends | ||
483 | * EVENTs out of order when removing the previous instance of the device. | ||
484 | */ | ||
485 | static void | ||
486 | _transport_delete_duplicate_port(struct MPT2SAS_ADAPTER *ioc, | ||
487 | struct _sas_node *sas_node, u64 sas_address, int phy_num) | ||
488 | { | ||
489 | struct _sas_port *mpt2sas_port, *mpt2sas_port_duplicate; | ||
490 | struct _sas_phy *mpt2sas_phy; | ||
491 | |||
492 | printk(MPT2SAS_ERR_FMT "new device located at sas_addr(0x%016llx), " | ||
493 | "phy_id(%d)\n", ioc->name, (unsigned long long)sas_address, | ||
494 | phy_num); | ||
495 | |||
496 | mpt2sas_port_duplicate = NULL; | ||
497 | list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, port_list) { | ||
498 | dev_printk(KERN_ERR, &mpt2sas_port->port->dev, | ||
499 | "existing device at sas_addr(0x%016llx), num_phys(%d)\n", | ||
500 | (unsigned long long) | ||
501 | mpt2sas_port->remote_identify.sas_address, | ||
502 | mpt2sas_port->num_phys); | ||
503 | list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list, | ||
504 | port_siblings) { | ||
505 | dev_printk(KERN_ERR, &mpt2sas_phy->phy->dev, | ||
506 | "phy_number(%d)\n", mpt2sas_phy->phy_id); | ||
507 | if (mpt2sas_phy->phy_id == phy_num) | ||
508 | mpt2sas_port_duplicate = mpt2sas_port; | ||
509 | } | ||
510 | } | ||
511 | |||
512 | if (!mpt2sas_port_duplicate) | ||
513 | return; | ||
514 | |||
515 | dev_printk(KERN_ERR, &mpt2sas_port_duplicate->port->dev, | ||
516 | "deleting duplicate device at sas_addr(0x%016llx), phy(%d)!!!!\n", | ||
517 | (unsigned long long) | ||
518 | mpt2sas_port_duplicate->remote_identify.sas_address, phy_num); | ||
519 | ioc->logging_level |= MPT_DEBUG_TRANSPORT; | ||
520 | mpt2sas_transport_port_remove(ioc, | ||
521 | mpt2sas_port_duplicate->remote_identify.sas_address, | ||
522 | sas_node->sas_address); | ||
523 | ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; | ||
524 | } | ||
525 | |||
526 | /** | ||
527 | * _transport_sanity_check - sanity check when adding a new port | ||
528 | * @ioc: per adapter object | ||
529 | * @sas_node: sas node object (either expander or sas host) | ||
530 | * @sas_address: sas address of device being added | ||
531 | * | ||
532 | * See the explanation above from _transport_delete_duplicate_port | ||
533 | */ | ||
534 | static void | ||
535 | _transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node, | ||
536 | u64 sas_address) | ||
537 | { | ||
538 | int i; | ||
539 | |||
540 | for (i = 0; i < sas_node->num_phys; i++) | ||
541 | if (sas_node->phy[i].remote_identify.sas_address == sas_address) | ||
542 | if (sas_node->phy[i].phy_belongs_to_port) | ||
543 | _transport_delete_duplicate_port(ioc, sas_node, | ||
544 | sas_address, i); | ||
545 | } | ||
546 | |||
468 | /** | 547 | /** |
469 | * mpt2sas_transport_port_add - insert port to the list | 548 | * mpt2sas_transport_port_add - insert port to the list |
470 | * @ioc: per adapter object | 549 | * @ioc: per adapter object |
@@ -522,6 +601,9 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, | |||
522 | goto out_fail; | 601 | goto out_fail; |
523 | } | 602 | } |
524 | 603 | ||
604 | _transport_sanity_check(ioc, sas_node, | ||
605 | mpt2sas_port->remote_identify.sas_address); | ||
606 | |||
525 | for (i = 0; i < sas_node->num_phys; i++) { | 607 | for (i = 0; i < sas_node->num_phys; i++) { |
526 | if (sas_node->phy[i].remote_identify.sas_address != | 608 | if (sas_node->phy[i].remote_identify.sas_address != |
527 | mpt2sas_port->remote_identify.sas_address) | 609 | mpt2sas_port->remote_identify.sas_address) |
@@ -553,6 +635,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, | |||
553 | mpt2sas_port->remote_identify.sas_address, | 635 | mpt2sas_port->remote_identify.sas_address, |
554 | mpt2sas_phy->phy_id); | 636 | mpt2sas_phy->phy_id); |
555 | sas_port_add_phy(port, mpt2sas_phy->phy); | 637 | sas_port_add_phy(port, mpt2sas_phy->phy); |
638 | mpt2sas_phy->phy_belongs_to_port = 1; | ||
556 | } | 639 | } |
557 | 640 | ||
558 | mpt2sas_port->port = port; | 641 | mpt2sas_port->port = port; |
@@ -651,6 +734,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, | |||
651 | (unsigned long long) | 734 | (unsigned long long) |
652 | mpt2sas_port->remote_identify.sas_address, | 735 | mpt2sas_port->remote_identify.sas_address, |
653 | mpt2sas_phy->phy_id); | 736 | mpt2sas_phy->phy_id); |
737 | mpt2sas_phy->phy_belongs_to_port = 0; | ||
654 | sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); | 738 | sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); |
655 | list_del(&mpt2sas_phy->port_siblings); | 739 | list_del(&mpt2sas_phy->port_siblings); |
656 | } | 740 | } |
@@ -1341,7 +1425,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
1341 | memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); | 1425 | memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); |
1342 | req->sense_len = sizeof(*mpi_reply); | 1426 | req->sense_len = sizeof(*mpi_reply); |
1343 | req->resid_len = 0; | 1427 | req->resid_len = 0; |
1344 | rsp->resid_len -= mpi_reply->ResponseDataLength; | 1428 | rsp->resid_len -= |
1429 | le16_to_cpu(mpi_reply->ResponseDataLength); | ||
1345 | } else { | 1430 | } else { |
1346 | dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT | 1431 | dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT |
1347 | "%s - no reply\n", ioc->name, __func__)); | 1432 | "%s - no reply\n", ioc->name, __func__)); |