diff options
-rw-r--r-- | drivers/scsi/cxlflash/Kconfig | 2 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/common.h | 11 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/main.c | 174 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/main.h | 6 | ||||
-rw-r--r--[-rwxr-xr-x] | drivers/scsi/cxlflash/sislite.h | 0 |
5 files changed, 177 insertions, 16 deletions
diff --git a/drivers/scsi/cxlflash/Kconfig b/drivers/scsi/cxlflash/Kconfig index c7075084cfdb..c052104e523e 100644 --- a/drivers/scsi/cxlflash/Kconfig +++ b/drivers/scsi/cxlflash/Kconfig | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | config CXLFLASH | 5 | config CXLFLASH |
6 | tristate "Support for IBM CAPI Flash" | 6 | tristate "Support for IBM CAPI Flash" |
7 | depends on PCI && SCSI && CXL | 7 | depends on PCI && SCSI && CXL && EEH |
8 | default m | 8 | default m |
9 | help | 9 | help |
10 | Allows CAPI Accelerated IO to Flash | 10 | Allows CAPI Accelerated IO to Flash |
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 5f43608dc8a1..ffdbc572d180 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h | |||
@@ -76,6 +76,12 @@ enum cxlflash_init_state { | |||
76 | INIT_STATE_SCSI | 76 | INIT_STATE_SCSI |
77 | }; | 77 | }; |
78 | 78 | ||
79 | enum cxlflash_state { | ||
80 | STATE_NORMAL, /* Normal running state, everything good */ | ||
81 | STATE_LIMBO, /* Limbo running state, trying to reset/recover */ | ||
82 | STATE_FAILTERM /* Failed/terminating state, error out users/threads */ | ||
83 | }; | ||
84 | |||
79 | /* | 85 | /* |
80 | * Each context has its own set of resource handles that is visible | 86 | * Each context has its own set of resource handles that is visible |
81 | * only from that context. | 87 | * only from that context. |
@@ -91,8 +97,6 @@ struct cxlflash_cfg { | |||
91 | 97 | ||
92 | ulong cxlflash_regs_pci; | 98 | ulong cxlflash_regs_pci; |
93 | 99 | ||
94 | wait_queue_head_t eeh_waitq; | ||
95 | |||
96 | struct work_struct work_q; | 100 | struct work_struct work_q; |
97 | enum cxlflash_init_state init_state; | 101 | enum cxlflash_init_state init_state; |
98 | enum cxlflash_lr_state lr_state; | 102 | enum cxlflash_lr_state lr_state; |
@@ -105,7 +109,8 @@ struct cxlflash_cfg { | |||
105 | 109 | ||
106 | wait_queue_head_t tmf_waitq; | 110 | wait_queue_head_t tmf_waitq; |
107 | bool tmf_active; | 111 | bool tmf_active; |
108 | u8 err_recovery_active:1; | 112 | wait_queue_head_t limbo_waitq; |
113 | enum cxlflash_state state; | ||
109 | }; | 114 | }; |
110 | 115 | ||
111 | struct afu_cmd { | 116 | struct afu_cmd { |
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 0720d2f13c2a..3ae8dca236ef 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c | |||
@@ -353,6 +353,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) | |||
353 | struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; | 353 | struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; |
354 | struct afu *afu = cfg->afu; | 354 | struct afu *afu = cfg->afu; |
355 | struct pci_dev *pdev = cfg->dev; | 355 | struct pci_dev *pdev = cfg->dev; |
356 | struct device *dev = &cfg->dev->dev; | ||
356 | struct afu_cmd *cmd; | 357 | struct afu_cmd *cmd; |
357 | u32 port_sel = scp->device->channel + 1; | 358 | u32 port_sel = scp->device->channel + 1; |
358 | int nseg, i, ncount; | 359 | int nseg, i, ncount; |
@@ -380,6 +381,21 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) | |||
380 | } | 381 | } |
381 | spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); | 382 | spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); |
382 | 383 | ||
384 | switch (cfg->state) { | ||
385 | case STATE_LIMBO: | ||
386 | dev_dbg_ratelimited(dev, "%s: device in limbo!\n", __func__); | ||
387 | rc = SCSI_MLQUEUE_HOST_BUSY; | ||
388 | goto out; | ||
389 | case STATE_FAILTERM: | ||
390 | dev_dbg_ratelimited(dev, "%s: device has failed!\n", __func__); | ||
391 | scp->result = (DID_NO_CONNECT << 16); | ||
392 | scp->scsi_done(scp); | ||
393 | rc = 0; | ||
394 | goto out; | ||
395 | default: | ||
396 | break; | ||
397 | } | ||
398 | |||
383 | cmd = cxlflash_cmd_checkout(afu); | 399 | cmd = cxlflash_cmd_checkout(afu); |
384 | if (unlikely(!cmd)) { | 400 | if (unlikely(!cmd)) { |
385 | pr_err("%s: could not get a free command\n", __func__); | 401 | pr_err("%s: could not get a free command\n", __func__); |
@@ -455,9 +471,21 @@ static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) | |||
455 | get_unaligned_be32(&((u32 *)scp->cmnd)[2]), | 471 | get_unaligned_be32(&((u32 *)scp->cmnd)[2]), |
456 | get_unaligned_be32(&((u32 *)scp->cmnd)[3])); | 472 | get_unaligned_be32(&((u32 *)scp->cmnd)[3])); |
457 | 473 | ||
458 | rcr = send_tmf(afu, scp, TMF_LUN_RESET); | 474 | switch (cfg->state) { |
459 | if (unlikely(rcr)) | 475 | case STATE_NORMAL: |
476 | rcr = send_tmf(afu, scp, TMF_LUN_RESET); | ||
477 | if (unlikely(rcr)) | ||
478 | rc = FAILED; | ||
479 | break; | ||
480 | case STATE_LIMBO: | ||
481 | wait_event(cfg->limbo_waitq, cfg->state != STATE_LIMBO); | ||
482 | if (cfg->state == STATE_NORMAL) | ||
483 | break; | ||
484 | /* fall through */ | ||
485 | default: | ||
460 | rc = FAILED; | 486 | rc = FAILED; |
487 | break; | ||
488 | } | ||
461 | 489 | ||
462 | pr_debug("%s: returning rc=%d\n", __func__, rc); | 490 | pr_debug("%s: returning rc=%d\n", __func__, rc); |
463 | return rc; | 491 | return rc; |
@@ -487,11 +515,29 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) | |||
487 | get_unaligned_be32(&((u32 *)scp->cmnd)[2]), | 515 | get_unaligned_be32(&((u32 *)scp->cmnd)[2]), |
488 | get_unaligned_be32(&((u32 *)scp->cmnd)[3])); | 516 | get_unaligned_be32(&((u32 *)scp->cmnd)[3])); |
489 | 517 | ||
490 | rcr = cxlflash_afu_reset(cfg); | 518 | switch (cfg->state) { |
491 | if (rcr == 0) | 519 | case STATE_NORMAL: |
492 | rc = SUCCESS; | 520 | cfg->state = STATE_LIMBO; |
493 | else | 521 | scsi_block_requests(cfg->host); |
522 | |||
523 | rcr = cxlflash_afu_reset(cfg); | ||
524 | if (rcr) { | ||
525 | rc = FAILED; | ||
526 | cfg->state = STATE_FAILTERM; | ||
527 | } else | ||
528 | cfg->state = STATE_NORMAL; | ||
529 | wake_up_all(&cfg->limbo_waitq); | ||
530 | scsi_unblock_requests(cfg->host); | ||
531 | break; | ||
532 | case STATE_LIMBO: | ||
533 | wait_event(cfg->limbo_waitq, cfg->state != STATE_LIMBO); | ||
534 | if (cfg->state == STATE_NORMAL) | ||
535 | break; | ||
536 | /* fall through */ | ||
537 | default: | ||
494 | rc = FAILED; | 538 | rc = FAILED; |
539 | break; | ||
540 | } | ||
495 | 541 | ||
496 | pr_debug("%s: returning rc=%d\n", __func__, rc); | 542 | pr_debug("%s: returning rc=%d\n", __func__, rc); |
497 | return rc; | 543 | return rc; |
@@ -642,7 +688,7 @@ static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) | |||
642 | struct pci_dev *pdev = cfg->dev; | 688 | struct pci_dev *pdev = cfg->dev; |
643 | 689 | ||
644 | if (pci_channel_offline(pdev)) | 690 | if (pci_channel_offline(pdev)) |
645 | wait_event_timeout(cfg->eeh_waitq, | 691 | wait_event_timeout(cfg->limbo_waitq, |
646 | !pci_channel_offline(pdev), | 692 | !pci_channel_offline(pdev), |
647 | CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT); | 693 | CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT); |
648 | } | 694 | } |
@@ -825,6 +871,8 @@ static void cxlflash_remove(struct pci_dev *pdev) | |||
825 | !cfg->tmf_active); | 871 | !cfg->tmf_active); |
826 | spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); | 872 | spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); |
827 | 873 | ||
874 | cfg->state = STATE_FAILTERM; | ||
875 | |||
828 | switch (cfg->init_state) { | 876 | switch (cfg->init_state) { |
829 | case INIT_STATE_SCSI: | 877 | case INIT_STATE_SCSI: |
830 | scsi_remove_host(cfg->host); | 878 | scsi_remove_host(cfg->host); |
@@ -1879,6 +1927,8 @@ static int init_afu(struct cxlflash_cfg *cfg) | |||
1879 | struct afu *afu = cfg->afu; | 1927 | struct afu *afu = cfg->afu; |
1880 | struct device *dev = &cfg->dev->dev; | 1928 | struct device *dev = &cfg->dev->dev; |
1881 | 1929 | ||
1930 | cxl_perst_reloads_same_image(cfg->cxl_afu, true); | ||
1931 | |||
1882 | rc = init_mc(cfg); | 1932 | rc = init_mc(cfg); |
1883 | if (rc) { | 1933 | if (rc) { |
1884 | dev_err(dev, "%s: call to init_mc failed, rc=%d!\n", | 1934 | dev_err(dev, "%s: call to init_mc failed, rc=%d!\n", |
@@ -2021,6 +2071,12 @@ void cxlflash_wait_resp(struct afu *afu, struct afu_cmd *cmd) | |||
2021 | * the sync. This design point requires calling threads to not be on interrupt | 2071 | * the sync. This design point requires calling threads to not be on interrupt |
2022 | * context due to the possibility of sleeping during concurrent sync operations. | 2072 | * context due to the possibility of sleeping during concurrent sync operations. |
2023 | * | 2073 | * |
2074 | * AFU sync operations are only necessary and allowed when the device is | ||
2075 | * operating normally. When not operating normally, sync requests can occur as | ||
2076 | * part of cleaning up resources associated with an adapter prior to removal. | ||
2077 | * In this scenario, these requests are simply ignored (safe due to the AFU | ||
2078 | * going away). | ||
2079 | * | ||
2024 | * Return: | 2080 | * Return: |
2025 | * 0 on success | 2081 | * 0 on success |
2026 | * -1 on failure | 2082 | * -1 on failure |
@@ -2028,11 +2084,17 @@ void cxlflash_wait_resp(struct afu *afu, struct afu_cmd *cmd) | |||
2028 | int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, | 2084 | int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, |
2029 | res_hndl_t res_hndl_u, u8 mode) | 2085 | res_hndl_t res_hndl_u, u8 mode) |
2030 | { | 2086 | { |
2087 | struct cxlflash_cfg *cfg = afu->parent; | ||
2031 | struct afu_cmd *cmd = NULL; | 2088 | struct afu_cmd *cmd = NULL; |
2032 | int rc = 0; | 2089 | int rc = 0; |
2033 | int retry_cnt = 0; | 2090 | int retry_cnt = 0; |
2034 | static DEFINE_MUTEX(sync_active); | 2091 | static DEFINE_MUTEX(sync_active); |
2035 | 2092 | ||
2093 | if (cfg->state != STATE_NORMAL) { | ||
2094 | pr_debug("%s: Sync not required! (%u)\n", __func__, cfg->state); | ||
2095 | return 0; | ||
2096 | } | ||
2097 | |||
2036 | mutex_lock(&sync_active); | 2098 | mutex_lock(&sync_active); |
2037 | retry: | 2099 | retry: |
2038 | cmd = cxlflash_cmd_checkout(afu); | 2100 | cmd = cxlflash_cmd_checkout(afu); |
@@ -2116,12 +2178,17 @@ int cxlflash_afu_reset(struct cxlflash_cfg *cfg) | |||
2116 | */ | 2178 | */ |
2117 | static void cxlflash_worker_thread(struct work_struct *work) | 2179 | static void cxlflash_worker_thread(struct work_struct *work) |
2118 | { | 2180 | { |
2119 | struct cxlflash_cfg *cfg = | 2181 | struct cxlflash_cfg *cfg = container_of(work, struct cxlflash_cfg, |
2120 | container_of(work, struct cxlflash_cfg, work_q); | 2182 | work_q); |
2121 | struct afu *afu = cfg->afu; | 2183 | struct afu *afu = cfg->afu; |
2122 | int port; | 2184 | int port; |
2123 | ulong lock_flags; | 2185 | ulong lock_flags; |
2124 | 2186 | ||
2187 | /* Avoid MMIO if the device has failed */ | ||
2188 | |||
2189 | if (cfg->state != STATE_NORMAL) | ||
2190 | return; | ||
2191 | |||
2125 | spin_lock_irqsave(cfg->host->host_lock, lock_flags); | 2192 | spin_lock_irqsave(cfg->host->host_lock, lock_flags); |
2126 | 2193 | ||
2127 | if (cfg->lr_state == LINK_RESET_REQUIRED) { | 2194 | if (cfg->lr_state == LINK_RESET_REQUIRED) { |
@@ -2200,10 +2267,9 @@ static int cxlflash_probe(struct pci_dev *pdev, | |||
2200 | cfg->dev = pdev; | 2267 | cfg->dev = pdev; |
2201 | cfg->dev_id = (struct pci_device_id *)dev_id; | 2268 | cfg->dev_id = (struct pci_device_id *)dev_id; |
2202 | cfg->mcctx = NULL; | 2269 | cfg->mcctx = NULL; |
2203 | cfg->err_recovery_active = 0; | ||
2204 | 2270 | ||
2205 | init_waitqueue_head(&cfg->tmf_waitq); | 2271 | init_waitqueue_head(&cfg->tmf_waitq); |
2206 | init_waitqueue_head(&cfg->eeh_waitq); | 2272 | init_waitqueue_head(&cfg->limbo_waitq); |
2207 | 2273 | ||
2208 | INIT_WORK(&cfg->work_q, cxlflash_worker_thread); | 2274 | INIT_WORK(&cfg->work_q, cxlflash_worker_thread); |
2209 | cfg->lr_state = LINK_RESET_INVALID; | 2275 | cfg->lr_state = LINK_RESET_INVALID; |
@@ -2259,6 +2325,91 @@ out_remove: | |||
2259 | goto out; | 2325 | goto out; |
2260 | } | 2326 | } |
2261 | 2327 | ||
2328 | /** | ||
2329 | * cxlflash_pci_error_detected() - called when a PCI error is detected | ||
2330 | * @pdev: PCI device struct. | ||
2331 | * @state: PCI channel state. | ||
2332 | * | ||
2333 | * Return: PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT | ||
2334 | */ | ||
2335 | static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, | ||
2336 | pci_channel_state_t state) | ||
2337 | { | ||
2338 | struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); | ||
2339 | struct device *dev = &cfg->dev->dev; | ||
2340 | |||
2341 | dev_dbg(dev, "%s: pdev=%p state=%u\n", __func__, pdev, state); | ||
2342 | |||
2343 | switch (state) { | ||
2344 | case pci_channel_io_frozen: | ||
2345 | cfg->state = STATE_LIMBO; | ||
2346 | |||
2347 | /* Turn off legacy I/O */ | ||
2348 | scsi_block_requests(cfg->host); | ||
2349 | |||
2350 | term_mc(cfg, UNDO_START); | ||
2351 | stop_afu(cfg); | ||
2352 | |||
2353 | return PCI_ERS_RESULT_NEED_RESET; | ||
2354 | case pci_channel_io_perm_failure: | ||
2355 | cfg->state = STATE_FAILTERM; | ||
2356 | wake_up_all(&cfg->limbo_waitq); | ||
2357 | scsi_unblock_requests(cfg->host); | ||
2358 | return PCI_ERS_RESULT_DISCONNECT; | ||
2359 | default: | ||
2360 | break; | ||
2361 | } | ||
2362 | return PCI_ERS_RESULT_NEED_RESET; | ||
2363 | } | ||
2364 | |||
2365 | /** | ||
2366 | * cxlflash_pci_slot_reset() - called when PCI slot has been reset | ||
2367 | * @pdev: PCI device struct. | ||
2368 | * | ||
2369 | * This routine is called by the pci error recovery code after the PCI | ||
2370 | * slot has been reset, just before we should resume normal operations. | ||
2371 | * | ||
2372 | * Return: PCI_ERS_RESULT_RECOVERED or PCI_ERS_RESULT_DISCONNECT | ||
2373 | */ | ||
2374 | static pci_ers_result_t cxlflash_pci_slot_reset(struct pci_dev *pdev) | ||
2375 | { | ||
2376 | int rc = 0; | ||
2377 | struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); | ||
2378 | struct device *dev = &cfg->dev->dev; | ||
2379 | |||
2380 | dev_dbg(dev, "%s: pdev=%p\n", __func__, pdev); | ||
2381 | |||
2382 | rc = init_afu(cfg); | ||
2383 | if (unlikely(rc)) { | ||
2384 | dev_err(dev, "%s: EEH recovery failed! (%d)\n", __func__, rc); | ||
2385 | return PCI_ERS_RESULT_DISCONNECT; | ||
2386 | } | ||
2387 | |||
2388 | return PCI_ERS_RESULT_RECOVERED; | ||
2389 | } | ||
2390 | |||
2391 | /** | ||
2392 | * cxlflash_pci_resume() - called when normal operation can resume | ||
2393 | * @pdev: PCI device struct | ||
2394 | */ | ||
2395 | static void cxlflash_pci_resume(struct pci_dev *pdev) | ||
2396 | { | ||
2397 | struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); | ||
2398 | struct device *dev = &cfg->dev->dev; | ||
2399 | |||
2400 | dev_dbg(dev, "%s: pdev=%p\n", __func__, pdev); | ||
2401 | |||
2402 | cfg->state = STATE_NORMAL; | ||
2403 | wake_up_all(&cfg->limbo_waitq); | ||
2404 | scsi_unblock_requests(cfg->host); | ||
2405 | } | ||
2406 | |||
2407 | static const struct pci_error_handlers cxlflash_err_handler = { | ||
2408 | .error_detected = cxlflash_pci_error_detected, | ||
2409 | .slot_reset = cxlflash_pci_slot_reset, | ||
2410 | .resume = cxlflash_pci_resume, | ||
2411 | }; | ||
2412 | |||
2262 | /* | 2413 | /* |
2263 | * PCI device structure | 2414 | * PCI device structure |
2264 | */ | 2415 | */ |
@@ -2267,6 +2418,7 @@ static struct pci_driver cxlflash_driver = { | |||
2267 | .id_table = cxlflash_pci_table, | 2418 | .id_table = cxlflash_pci_table, |
2268 | .probe = cxlflash_probe, | 2419 | .probe = cxlflash_probe, |
2269 | .remove = cxlflash_remove, | 2420 | .remove = cxlflash_remove, |
2421 | .err_handler = &cxlflash_err_handler, | ||
2270 | }; | 2422 | }; |
2271 | 2423 | ||
2272 | /** | 2424 | /** |
diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index 7f890ccf3289..cf0e80938b13 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h | |||
@@ -22,7 +22,7 @@ | |||
22 | 22 | ||
23 | #define CXLFLASH_NAME "cxlflash" | 23 | #define CXLFLASH_NAME "cxlflash" |
24 | #define CXLFLASH_ADAPTER_NAME "IBM POWER CXL Flash Adapter" | 24 | #define CXLFLASH_ADAPTER_NAME "IBM POWER CXL Flash Adapter" |
25 | #define CXLFLASH_DRIVER_DATE "(June 2, 2015)" | 25 | #define CXLFLASH_DRIVER_DATE "(August 13, 2015)" |
26 | 26 | ||
27 | #define PCI_DEVICE_ID_IBM_CORSA 0x04F0 | 27 | #define PCI_DEVICE_ID_IBM_CORSA 0x04F0 |
28 | #define CXLFLASH_SUBS_DEV_ID 0x04F0 | 28 | #define CXLFLASH_SUBS_DEV_ID 0x04F0 |
@@ -101,4 +101,8 @@ struct asyc_intr_info { | |||
101 | #define LINK_RESET 0x02 | 101 | #define LINK_RESET 0x02 |
102 | }; | 102 | }; |
103 | 103 | ||
104 | #ifndef CONFIG_CXL_EEH | ||
105 | #define cxl_perst_reloads_same_image(_a, _b) do { } while (0) | ||
106 | #endif | ||
107 | |||
104 | #endif /* _CXLFLASH_MAIN_H */ | 108 | #endif /* _CXLFLASH_MAIN_H */ |
diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index bf5d39978630..bf5d39978630 100755..100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h | |||