diff options
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_scsih.c')
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 1055 |
1 files changed, 646 insertions, 409 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index be171ed682e..c5ff26a2a51 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, |