diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2008-04-03 16:13:24 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-04-07 13:19:15 -0400 |
commit | 523ec773b8ffb1c607bc3a54c9526558e3b1eab1 (patch) | |
tree | 9cb3fc8a68af97a6359704e4341652aad9cc65d1 /drivers/scsi/qla2xxx | |
parent | 3fe7cfb910ea138ae623d1320c71e2a7a0bdc527 (diff) |
[SCSI] qla2xxx: Add midlayer target/device reset support.
Now that infrastructure is present within the midlayer and there
is a clear distinction between what is expected from a device and
target reset, convert the current device-reset codes to a
target-reset, and add codes to perform a proper device-reset (LUN
reset).
In the process of adding reset support, collapse and consolidate
large sections of mailbox-command (TMF issuance) codes,
generalize the two 'wait-for-commands-to-complete' functions, and
add a generic-reset routine for use by midlayer reset functions.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 3 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_fw.h | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 8 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 123 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 254 |
5 files changed, 192 insertions, 198 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 3843eaa3af06..f7919d348ccd 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -2062,7 +2062,8 @@ struct isp_operations { | |||
2062 | void (*disable_intrs) (struct scsi_qla_host *); | 2062 | void (*disable_intrs) (struct scsi_qla_host *); |
2063 | 2063 | ||
2064 | int (*abort_command) (struct scsi_qla_host *, srb_t *); | 2064 | int (*abort_command) (struct scsi_qla_host *, srb_t *); |
2065 | int (*abort_target) (struct fc_port *); | 2065 | int (*target_reset) (struct fc_port *, unsigned int); |
2066 | int (*lun_reset) (struct fc_port *, unsigned int); | ||
2066 | int (*fabric_login) (struct scsi_qla_host *, uint16_t, uint8_t, | 2067 | int (*fabric_login) (struct scsi_qla_host *, uint16_t, uint8_t, |
2067 | uint8_t, uint8_t, uint16_t *, uint8_t); | 2068 | uint8_t, uint8_t, uint16_t *, uint8_t); |
2068 | int (*fabric_logout) (struct scsi_qla_host *, uint16_t, uint8_t, | 2069 | int (*fabric_logout) (struct scsi_qla_host *, uint16_t, uint8_t, |
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 38adc0f06e93..c6a5e49a25be 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h | |||
@@ -719,7 +719,7 @@ struct tsk_mgmt_entry { | |||
719 | 719 | ||
720 | uint16_t timeout; /* Command timeout. */ | 720 | uint16_t timeout; /* Command timeout. */ |
721 | 721 | ||
722 | uint8_t lun[8]; /* FCP LUN (BE). */ | 722 | struct scsi_lun lun; /* FCP LUN (BE). */ |
723 | 723 | ||
724 | uint32_t control_flags; /* Control Flags. */ | 724 | uint32_t control_flags; /* Control Flags. */ |
725 | #define TCF_NOTMCMD_TO_TARGET BIT_31 | 725 | #define TCF_NOTMCMD_TO_TARGET BIT_31 |
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index f25aa63ad191..f2133647bf25 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
@@ -153,7 +153,10 @@ extern int | |||
153 | qla2x00_abort_command(scsi_qla_host_t *, srb_t *); | 153 | qla2x00_abort_command(scsi_qla_host_t *, srb_t *); |
154 | 154 | ||
155 | extern int | 155 | extern int |
156 | qla2x00_abort_target(fc_port_t *); | 156 | qla2x00_abort_target(struct fc_port *, unsigned int); |
157 | |||
158 | extern int | ||
159 | qla2x00_lun_reset(struct fc_port *, unsigned int); | ||
157 | 160 | ||
158 | extern int | 161 | extern int |
159 | qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, | 162 | qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, |
@@ -219,7 +222,8 @@ qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *, | |||
219 | dma_addr_t); | 222 | dma_addr_t); |
220 | 223 | ||
221 | extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *); | 224 | extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *); |
222 | extern int qla24xx_abort_target(fc_port_t *); | 225 | extern int qla24xx_abort_target(struct fc_port *, unsigned int); |
226 | extern int qla24xx_lun_reset(struct fc_port *, unsigned int); | ||
223 | 227 | ||
224 | extern int | 228 | extern int |
225 | qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); | 229 | qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); |
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index b25c15a86c7f..c1af56dec4d4 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c | |||
@@ -784,35 +784,20 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) | |||
784 | return rval; | 784 | return rval; |
785 | } | 785 | } |
786 | 786 | ||
787 | /* | ||
788 | * qla2x00_abort_target | ||
789 | * Issue abort target mailbox command. | ||
790 | * | ||
791 | * Input: | ||
792 | * ha = adapter block pointer. | ||
793 | * | ||
794 | * Returns: | ||
795 | * qla2x00 local function return status code. | ||
796 | * | ||
797 | * Context: | ||
798 | * Kernel context. | ||
799 | */ | ||
800 | int | 787 | int |
801 | qla2x00_abort_target(fc_port_t *fcport) | 788 | qla2x00_abort_target(struct fc_port *fcport, unsigned int l) |
802 | { | 789 | { |
803 | int rval; | 790 | int rval, rval2; |
804 | mbx_cmd_t mc; | 791 | mbx_cmd_t mc; |
805 | mbx_cmd_t *mcp = &mc; | 792 | mbx_cmd_t *mcp = &mc; |
806 | scsi_qla_host_t *ha; | 793 | scsi_qla_host_t *ha; |
807 | 794 | ||
808 | if (fcport == NULL) | ||
809 | return 0; | ||
810 | |||
811 | DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); | 795 | DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); |
812 | 796 | ||
797 | l = l; | ||
813 | ha = fcport->ha; | 798 | ha = fcport->ha; |
814 | mcp->mb[0] = MBC_ABORT_TARGET; | 799 | mcp->mb[0] = MBC_ABORT_TARGET; |
815 | mcp->out_mb = MBX_2|MBX_1|MBX_0; | 800 | mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0; |
816 | if (HAS_EXTENDED_IDS(ha)) { | 801 | if (HAS_EXTENDED_IDS(ha)) { |
817 | mcp->mb[1] = fcport->loop_id; | 802 | mcp->mb[1] = fcport->loop_id; |
818 | mcp->mb[10] = 0; | 803 | mcp->mb[10] = 0; |
@@ -821,22 +806,66 @@ qla2x00_abort_target(fc_port_t *fcport) | |||
821 | mcp->mb[1] = fcport->loop_id << 8; | 806 | mcp->mb[1] = fcport->loop_id << 8; |
822 | } | 807 | } |
823 | mcp->mb[2] = ha->loop_reset_delay; | 808 | mcp->mb[2] = ha->loop_reset_delay; |
809 | mcp->mb[9] = ha->vp_idx; | ||
824 | 810 | ||
825 | mcp->in_mb = MBX_0; | 811 | mcp->in_mb = MBX_0; |
826 | mcp->tov = 30; | 812 | mcp->tov = 30; |
827 | mcp->flags = 0; | 813 | mcp->flags = 0; |
828 | rval = qla2x00_mailbox_command(ha, mcp); | 814 | rval = qla2x00_mailbox_command(ha, mcp); |
815 | if (rval != QLA_SUCCESS) { | ||
816 | DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, | ||
817 | ha->host_no, rval)); | ||
818 | } | ||
819 | |||
820 | /* Issue marker IOCB. */ | ||
821 | rval2 = qla2x00_marker(ha, fcport->loop_id, 0, MK_SYNC_ID); | ||
822 | if (rval2 != QLA_SUCCESS) { | ||
823 | DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " | ||
824 | "(%x).\n", __func__, ha->host_no, rval2)); | ||
825 | } else { | ||
826 | DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); | ||
827 | } | ||
828 | |||
829 | return rval; | ||
830 | } | ||
831 | |||
832 | int | ||
833 | qla2x00_lun_reset(struct fc_port *fcport, unsigned int l) | ||
834 | { | ||
835 | int rval, rval2; | ||
836 | mbx_cmd_t mc; | ||
837 | mbx_cmd_t *mcp = &mc; | ||
838 | scsi_qla_host_t *ha; | ||
839 | |||
840 | DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); | ||
829 | 841 | ||
830 | /* Issue marker command. */ | 842 | ha = fcport->ha; |
831 | ha->marker_needed = 1; | 843 | mcp->mb[0] = MBC_LUN_RESET; |
844 | mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; | ||
845 | if (HAS_EXTENDED_IDS(ha)) | ||
846 | mcp->mb[1] = fcport->loop_id; | ||
847 | else | ||
848 | mcp->mb[1] = fcport->loop_id << 8; | ||
849 | mcp->mb[2] = l; | ||
850 | mcp->mb[3] = 0; | ||
851 | mcp->mb[9] = ha->vp_idx; | ||
832 | 852 | ||
853 | mcp->in_mb = MBX_0; | ||
854 | mcp->tov = 30; | ||
855 | mcp->flags = 0; | ||
856 | rval = qla2x00_mailbox_command(ha, mcp); | ||
833 | if (rval != QLA_SUCCESS) { | 857 | if (rval != QLA_SUCCESS) { |
834 | DEBUG2_3_11(printk("qla2x00_abort_target(%ld): failed=%x.\n", | 858 | DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, |
835 | ha->host_no, rval)); | 859 | ha->host_no, rval)); |
860 | } | ||
861 | |||
862 | /* Issue marker IOCB. */ | ||
863 | rval2 = qla2x00_marker(ha, fcport->loop_id, l, MK_SYNC_ID_LUN); | ||
864 | if (rval2 != QLA_SUCCESS) { | ||
865 | DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " | ||
866 | "(%x).\n", __func__, ha->host_no, rval2)); | ||
836 | } else { | 867 | } else { |
837 | /*EMPTY*/ | 868 | DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); |
838 | DEBUG11(printk("qla2x00_abort_target(%ld): done.\n", | ||
839 | ha->host_no)); | ||
840 | } | 869 | } |
841 | 870 | ||
842 | return rval; | 871 | return rval; |
@@ -2186,17 +2215,15 @@ struct tsk_mgmt_cmd { | |||
2186 | } p; | 2215 | } p; |
2187 | }; | 2216 | }; |
2188 | 2217 | ||
2189 | int | 2218 | static int |
2190 | qla24xx_abort_target(fc_port_t *fcport) | 2219 | __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, |
2220 | unsigned int l) | ||
2191 | { | 2221 | { |
2192 | int rval; | 2222 | int rval, rval2; |
2193 | struct tsk_mgmt_cmd *tsk; | 2223 | struct tsk_mgmt_cmd *tsk; |
2194 | dma_addr_t tsk_dma; | 2224 | dma_addr_t tsk_dma; |
2195 | scsi_qla_host_t *ha, *pha; | 2225 | scsi_qla_host_t *ha, *pha; |
2196 | 2226 | ||
2197 | if (fcport == NULL) | ||
2198 | return 0; | ||
2199 | |||
2200 | DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); | 2227 | DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); |
2201 | 2228 | ||
2202 | ha = fcport->ha; | 2229 | ha = fcport->ha; |
@@ -2213,47 +2240,61 @@ qla24xx_abort_target(fc_port_t *fcport) | |||
2213 | tsk->p.tsk.entry_count = 1; | 2240 | tsk->p.tsk.entry_count = 1; |
2214 | tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id); | 2241 | tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id); |
2215 | tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); | 2242 | tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); |
2216 | tsk->p.tsk.control_flags = __constant_cpu_to_le32(TCF_TARGET_RESET); | 2243 | tsk->p.tsk.control_flags = cpu_to_le32(type); |
2217 | tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa; | 2244 | tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa; |
2218 | tsk->p.tsk.port_id[1] = fcport->d_id.b.area; | 2245 | tsk->p.tsk.port_id[1] = fcport->d_id.b.area; |
2219 | tsk->p.tsk.port_id[2] = fcport->d_id.b.domain; | 2246 | tsk->p.tsk.port_id[2] = fcport->d_id.b.domain; |
2220 | tsk->p.tsk.vp_index = fcport->vp_idx; | 2247 | tsk->p.tsk.vp_index = fcport->vp_idx; |
2248 | if (type == TCF_LUN_RESET) { | ||
2249 | int_to_scsilun(l, &tsk->p.tsk.lun); | ||
2250 | host_to_fcp_swap((uint8_t *)&tsk->p.tsk.lun, | ||
2251 | sizeof(tsk->p.tsk.lun)); | ||
2252 | } | ||
2221 | 2253 | ||
2222 | rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0); | 2254 | rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0); |
2223 | if (rval != QLA_SUCCESS) { | 2255 | if (rval != QLA_SUCCESS) { |
2224 | DEBUG2_3_11(printk("%s(%ld): failed to issue Target Reset IOCB " | 2256 | DEBUG2_3_11(printk("%s(%ld): failed to issue %s Reset IOCB " |
2225 | "(%x).\n", __func__, ha->host_no, rval)); | 2257 | "(%x).\n", __func__, ha->host_no, name, rval)); |
2226 | goto atarget_done; | ||
2227 | } else if (tsk->p.sts.entry_status != 0) { | 2258 | } else if (tsk->p.sts.entry_status != 0) { |
2228 | DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " | 2259 | DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " |
2229 | "-- error status (%x).\n", __func__, ha->host_no, | 2260 | "-- error status (%x).\n", __func__, ha->host_no, |
2230 | tsk->p.sts.entry_status)); | 2261 | tsk->p.sts.entry_status)); |
2231 | rval = QLA_FUNCTION_FAILED; | 2262 | rval = QLA_FUNCTION_FAILED; |
2232 | goto atarget_done; | ||
2233 | } else if (tsk->p.sts.comp_status != | 2263 | } else if (tsk->p.sts.comp_status != |
2234 | __constant_cpu_to_le16(CS_COMPLETE)) { | 2264 | __constant_cpu_to_le16(CS_COMPLETE)) { |
2235 | DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " | 2265 | DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " |
2236 | "-- completion status (%x).\n", __func__, | 2266 | "-- completion status (%x).\n", __func__, |
2237 | ha->host_no, le16_to_cpu(tsk->p.sts.comp_status))); | 2267 | ha->host_no, le16_to_cpu(tsk->p.sts.comp_status))); |
2238 | rval = QLA_FUNCTION_FAILED; | 2268 | rval = QLA_FUNCTION_FAILED; |
2239 | goto atarget_done; | ||
2240 | } | 2269 | } |
2241 | 2270 | ||
2242 | /* Issue marker IOCB. */ | 2271 | /* Issue marker IOCB. */ |
2243 | rval = qla2x00_marker(ha, fcport->loop_id, 0, MK_SYNC_ID); | 2272 | rval2 = qla2x00_marker(ha, fcport->loop_id, l, |
2244 | if (rval != QLA_SUCCESS) { | 2273 | type == TCF_LUN_RESET ? MK_SYNC_ID_LUN: MK_SYNC_ID); |
2274 | if (rval2 != QLA_SUCCESS) { | ||
2245 | DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " | 2275 | DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " |
2246 | "(%x).\n", __func__, ha->host_no, rval)); | 2276 | "(%x).\n", __func__, ha->host_no, rval2)); |
2247 | } else { | 2277 | } else { |
2248 | DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); | 2278 | DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); |
2249 | } | 2279 | } |
2250 | 2280 | ||
2251 | atarget_done: | ||
2252 | dma_pool_free(pha->s_dma_pool, tsk, tsk_dma); | 2281 | dma_pool_free(pha->s_dma_pool, tsk, tsk_dma); |
2253 | 2282 | ||
2254 | return rval; | 2283 | return rval; |
2255 | } | 2284 | } |
2256 | 2285 | ||
2286 | int | ||
2287 | qla24xx_abort_target(struct fc_port *fcport, unsigned int l) | ||
2288 | { | ||
2289 | return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l); | ||
2290 | } | ||
2291 | |||
2292 | int | ||
2293 | qla24xx_lun_reset(struct fc_port *fcport, unsigned int l) | ||
2294 | { | ||
2295 | return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l); | ||
2296 | } | ||
2297 | |||
2257 | #if 0 | 2298 | #if 0 |
2258 | 2299 | ||
2259 | int | 2300 | int |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ba7d2ca3a0e8..5cddc503bd2b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -100,6 +100,7 @@ static int qla24xx_queuecommand(struct scsi_cmnd *cmd, | |||
100 | void (*fn)(struct scsi_cmnd *)); | 100 | void (*fn)(struct scsi_cmnd *)); |
101 | static int qla2xxx_eh_abort(struct scsi_cmnd *); | 101 | static int qla2xxx_eh_abort(struct scsi_cmnd *); |
102 | static int qla2xxx_eh_device_reset(struct scsi_cmnd *); | 102 | static int qla2xxx_eh_device_reset(struct scsi_cmnd *); |
103 | static int qla2xxx_eh_target_reset(struct scsi_cmnd *); | ||
103 | static int qla2xxx_eh_bus_reset(struct scsi_cmnd *); | 104 | static int qla2xxx_eh_bus_reset(struct scsi_cmnd *); |
104 | static int qla2xxx_eh_host_reset(struct scsi_cmnd *); | 105 | static int qla2xxx_eh_host_reset(struct scsi_cmnd *); |
105 | 106 | ||
@@ -113,6 +114,7 @@ static struct scsi_host_template qla2x00_driver_template = { | |||
113 | 114 | ||
114 | .eh_abort_handler = qla2xxx_eh_abort, | 115 | .eh_abort_handler = qla2xxx_eh_abort, |
115 | .eh_device_reset_handler = qla2xxx_eh_device_reset, | 116 | .eh_device_reset_handler = qla2xxx_eh_device_reset, |
117 | .eh_target_reset_handler = qla2xxx_eh_target_reset, | ||
116 | .eh_bus_reset_handler = qla2xxx_eh_bus_reset, | 118 | .eh_bus_reset_handler = qla2xxx_eh_bus_reset, |
117 | .eh_host_reset_handler = qla2xxx_eh_host_reset, | 119 | .eh_host_reset_handler = qla2xxx_eh_host_reset, |
118 | 120 | ||
@@ -144,6 +146,7 @@ struct scsi_host_template qla24xx_driver_template = { | |||
144 | 146 | ||
145 | .eh_abort_handler = qla2xxx_eh_abort, | 147 | .eh_abort_handler = qla2xxx_eh_abort, |
146 | .eh_device_reset_handler = qla2xxx_eh_device_reset, | 148 | .eh_device_reset_handler = qla2xxx_eh_device_reset, |
149 | .eh_target_reset_handler = qla2xxx_eh_target_reset, | ||
147 | .eh_bus_reset_handler = qla2xxx_eh_bus_reset, | 150 | .eh_bus_reset_handler = qla2xxx_eh_bus_reset, |
148 | .eh_host_reset_handler = qla2xxx_eh_host_reset, | 151 | .eh_host_reset_handler = qla2xxx_eh_host_reset, |
149 | 152 | ||
@@ -566,8 +569,6 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha) | |||
566 | else | 569 | else |
567 | return_status = QLA_FUNCTION_FAILED; | 570 | return_status = QLA_FUNCTION_FAILED; |
568 | 571 | ||
569 | DEBUG2(printk("%s return_status=%d\n",__func__,return_status)); | ||
570 | |||
571 | return (return_status); | 572 | return (return_status); |
572 | } | 573 | } |
573 | 574 | ||
@@ -714,181 +715,122 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) | |||
714 | return ret; | 715 | return ret; |
715 | } | 716 | } |
716 | 717 | ||
717 | /************************************************************************** | 718 | enum nexus_wait_type { |
718 | * qla2x00_eh_wait_for_pending_target_commands | 719 | WAIT_HOST = 0, |
719 | * | 720 | WAIT_TARGET, |
720 | * Description: | 721 | WAIT_LUN, |
721 | * Waits for all the commands to come back from the specified target. | 722 | }; |
722 | * | 723 | |
723 | * Input: | ||
724 | * ha - pointer to scsi_qla_host structure. | ||
725 | * t - target | ||
726 | * Returns: | ||
727 | * Either SUCCESS or FAILED. | ||
728 | * | ||
729 | * Note: | ||
730 | **************************************************************************/ | ||
731 | static int | 724 | static int |
732 | qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t) | 725 | qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha, unsigned int t, |
726 | unsigned int l, enum nexus_wait_type type) | ||
733 | { | 727 | { |
734 | int cnt; | 728 | int cnt, match, status; |
735 | int status; | 729 | srb_t *sp; |
736 | srb_t *sp; | ||
737 | struct scsi_cmnd *cmd; | ||
738 | unsigned long flags; | 730 | unsigned long flags; |
739 | scsi_qla_host_t *pha = to_qla_parent(ha); | 731 | scsi_qla_host_t *pha = to_qla_parent(ha); |
740 | 732 | ||
741 | status = 0; | 733 | status = QLA_SUCCESS; |
742 | 734 | spin_lock_irqsave(&pha->hardware_lock, flags); | |
743 | /* | 735 | for (cnt = 1; status == QLA_SUCCESS && cnt < MAX_OUTSTANDING_COMMANDS; |
744 | * Waiting for all commands for the designated target in the active | 736 | cnt++) { |
745 | * array | ||
746 | */ | ||
747 | for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { | ||
748 | spin_lock_irqsave(&pha->hardware_lock, flags); | ||
749 | sp = pha->outstanding_cmds[cnt]; | 737 | sp = pha->outstanding_cmds[cnt]; |
750 | if (sp) { | 738 | if (!sp) |
751 | cmd = sp->cmd; | 739 | continue; |
752 | spin_unlock_irqrestore(&pha->hardware_lock, flags); | 740 | if (ha->vp_idx != sp->ha->vp_idx) |
753 | if (cmd->device->id == t && | 741 | continue; |
754 | ha->vp_idx == sp->ha->vp_idx) { | 742 | match = 0; |
755 | if (!qla2x00_eh_wait_on_command(ha, cmd)) { | 743 | switch (type) { |
756 | status = 1; | 744 | case WAIT_HOST: |
757 | break; | 745 | match = 1; |
758 | } | 746 | break; |
759 | } | 747 | case WAIT_TARGET: |
760 | } else { | 748 | match = sp->cmd->device->id == t; |
761 | spin_unlock_irqrestore(&pha->hardware_lock, flags); | 749 | break; |
750 | case WAIT_LUN: | ||
751 | match = (sp->cmd->device->id == t && | ||
752 | sp->cmd->device->lun == l); | ||
753 | break; | ||
762 | } | 754 | } |
755 | if (!match) | ||
756 | continue; | ||
757 | |||
758 | spin_unlock_irqrestore(&pha->hardware_lock, flags); | ||
759 | status = qla2x00_eh_wait_on_command(ha, sp->cmd); | ||
760 | spin_lock_irqsave(&pha->hardware_lock, flags); | ||
763 | } | 761 | } |
764 | return (status); | 762 | spin_unlock_irqrestore(&pha->hardware_lock, flags); |
763 | |||
764 | return status; | ||
765 | } | 765 | } |
766 | 766 | ||
767 | static char *reset_errors[] = { | ||
768 | "HBA not online", | ||
769 | "HBA not ready", | ||
770 | "Task management failed", | ||
771 | "Waiting for command completions", | ||
772 | }; | ||
767 | 773 | ||
768 | /************************************************************************** | ||
769 | * qla2xxx_eh_device_reset | ||
770 | * | ||
771 | * Description: | ||
772 | * The device reset function will reset the target and abort any | ||
773 | * executing commands. | ||
774 | * | ||
775 | * NOTE: The use of SP is undefined within this context. Do *NOT* | ||
776 | * attempt to use this value, even if you determine it is | ||
777 | * non-null. | ||
778 | * | ||
779 | * Input: | ||
780 | * cmd = Linux SCSI command packet of the command that cause the | ||
781 | * bus device reset. | ||
782 | * | ||
783 | * Returns: | ||
784 | * SUCCESS/FAILURE (defined as macro in scsi.h). | ||
785 | * | ||
786 | **************************************************************************/ | ||
787 | static int | 774 | static int |
788 | qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) | 775 | __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, |
776 | struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int)) | ||
789 | { | 777 | { |
790 | scsi_qla_host_t *ha = shost_priv(cmd->device->host); | 778 | scsi_qla_host_t *ha = shost_priv(cmd->device->host); |
791 | fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; | 779 | fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; |
792 | int ret = FAILED; | 780 | int err; |
793 | unsigned int id, lun; | ||
794 | unsigned long serial; | ||
795 | 781 | ||
796 | qla2x00_block_error_handler(cmd); | 782 | qla2x00_block_error_handler(cmd); |
797 | 783 | ||
798 | id = cmd->device->id; | ||
799 | lun = cmd->device->lun; | ||
800 | serial = cmd->serial_number; | ||
801 | |||
802 | if (!fcport) | 784 | if (!fcport) |
803 | return ret; | 785 | return FAILED; |
804 | 786 | ||
805 | qla_printk(KERN_INFO, ha, | 787 | qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET ISSUED.\n", |
806 | "scsi(%ld:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, id, lun); | 788 | ha->host_no, cmd->device->id, cmd->device->lun, name); |
807 | 789 | ||
790 | err = 0; | ||
808 | if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) | 791 | if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) |
809 | goto eh_dev_reset_done; | 792 | goto eh_reset_failed; |
810 | 793 | err = 1; | |
811 | if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) { | 794 | if (qla2x00_wait_for_loop_ready(ha) != QLA_SUCCESS) |
812 | if (ha->isp_ops->abort_target(fcport) == 0) | 795 | goto eh_reset_failed; |
813 | ret = SUCCESS; | 796 | err = 2; |
814 | } else { | 797 | if (do_reset(fcport, cmd->device->lun) != QLA_SUCCESS) |
815 | DEBUG2(printk(KERN_INFO | 798 | goto eh_reset_failed; |
816 | "%s failed: loop not ready\n",__func__)); | 799 | err = 3; |
817 | } | 800 | if (qla2x00_eh_wait_for_pending_commands(ha, cmd->device->id, |
818 | 801 | cmd->device->lun, type) != QLA_SUCCESS) | |
819 | if (ret == FAILED) { | 802 | goto eh_reset_failed; |
820 | DEBUG3(printk("%s(%ld): device reset failed\n", | 803 | |
821 | __func__, ha->host_no)); | 804 | qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n", |
822 | qla_printk(KERN_INFO, ha, "%s: device reset failed\n", | 805 | ha->host_no, cmd->device->id, cmd->device->lun, name); |
823 | __func__); | 806 | |
807 | return SUCCESS; | ||
808 | |||
809 | eh_reset_failed: | ||
810 | qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n", | ||
811 | ha->host_no, cmd->device->id, cmd->device->lun, name, | ||
812 | reset_errors[err]); | ||
813 | return FAILED; | ||
814 | } | ||
824 | 815 | ||
825 | goto eh_dev_reset_done; | 816 | static int |
826 | } | 817 | qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) |
818 | { | ||
819 | scsi_qla_host_t *ha = shost_priv(cmd->device->host); | ||
827 | 820 | ||
828 | /* Flush outstanding commands. */ | 821 | return __qla2xxx_eh_generic_reset("DEVICE", WAIT_LUN, cmd, |
829 | if (qla2x00_eh_wait_for_pending_target_commands(ha, id)) | 822 | ha->isp_ops->lun_reset); |
830 | ret = FAILED; | ||
831 | if (ret == FAILED) { | ||
832 | DEBUG3(printk("%s(%ld): failed while waiting for commands\n", | ||
833 | __func__, ha->host_no)); | ||
834 | qla_printk(KERN_INFO, ha, | ||
835 | "%s: failed while waiting for commands\n", __func__); | ||
836 | } else | ||
837 | qla_printk(KERN_INFO, ha, | ||
838 | "scsi(%ld:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no, | ||
839 | id, lun); | ||
840 | eh_dev_reset_done: | ||
841 | return ret; | ||
842 | } | 823 | } |
843 | 824 | ||
844 | /************************************************************************** | ||
845 | * qla2x00_eh_wait_for_pending_commands | ||
846 | * | ||
847 | * Description: | ||
848 | * Waits for all the commands to come back from the specified host. | ||
849 | * | ||
850 | * Input: | ||
851 | * ha - pointer to scsi_qla_host structure. | ||
852 | * | ||
853 | * Returns: | ||
854 | * 1 : SUCCESS | ||
855 | * 0 : FAILED | ||
856 | * | ||
857 | * Note: | ||
858 | **************************************************************************/ | ||
859 | static int | 825 | static int |
860 | qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha) | 826 | qla2xxx_eh_target_reset(struct scsi_cmnd *cmd) |
861 | { | 827 | { |
862 | int cnt; | 828 | scsi_qla_host_t *ha = shost_priv(cmd->device->host); |
863 | int status; | ||
864 | srb_t *sp; | ||
865 | struct scsi_cmnd *cmd; | ||
866 | unsigned long flags; | ||
867 | |||
868 | status = 1; | ||
869 | 829 | ||
870 | /* | 830 | return __qla2xxx_eh_generic_reset("TARGET", WAIT_TARGET, cmd, |
871 | * Waiting for all commands for the designated target in the active | 831 | ha->isp_ops->target_reset); |
872 | * array | ||
873 | */ | ||
874 | for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { | ||
875 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
876 | sp = ha->outstanding_cmds[cnt]; | ||
877 | if (sp) { | ||
878 | cmd = sp->cmd; | ||
879 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
880 | status = qla2x00_eh_wait_on_command(ha, cmd); | ||
881 | if (status == 0) | ||
882 | break; | ||
883 | } | ||
884 | else { | ||
885 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
886 | } | ||
887 | } | ||
888 | return (status); | ||
889 | } | 832 | } |
890 | 833 | ||
891 | |||
892 | /************************************************************************** | 834 | /************************************************************************** |
893 | * qla2xxx_eh_bus_reset | 835 | * qla2xxx_eh_bus_reset |
894 | * | 836 | * |
@@ -939,7 +881,8 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) | |||
939 | goto eh_bus_reset_done; | 881 | goto eh_bus_reset_done; |
940 | 882 | ||
941 | /* Flush outstanding commands. */ | 883 | /* Flush outstanding commands. */ |
942 | if (!qla2x00_eh_wait_for_pending_commands(pha)) | 884 | if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) != |
885 | QLA_SUCCESS) | ||
943 | ret = FAILED; | 886 | ret = FAILED; |
944 | 887 | ||
945 | eh_bus_reset_done: | 888 | eh_bus_reset_done: |
@@ -1010,7 +953,8 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) | |||
1010 | clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags); | 953 | clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags); |
1011 | 954 | ||
1012 | /* Waiting for our command in done_queue to be returned to OS.*/ | 955 | /* Waiting for our command in done_queue to be returned to OS.*/ |
1013 | if (qla2x00_eh_wait_for_pending_commands(pha)) | 956 | if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) == |
957 | QLA_SUCCESS) | ||
1014 | ret = SUCCESS; | 958 | ret = SUCCESS; |
1015 | 959 | ||
1016 | if (ha->parent) | 960 | if (ha->parent) |
@@ -1066,7 +1010,7 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) | |||
1066 | if (fcport->port_type != FCT_TARGET) | 1010 | if (fcport->port_type != FCT_TARGET) |
1067 | continue; | 1011 | continue; |
1068 | 1012 | ||
1069 | ret = ha->isp_ops->abort_target(fcport); | 1013 | ret = ha->isp_ops->target_reset(fcport, 0); |
1070 | if (ret != QLA_SUCCESS) { | 1014 | if (ret != QLA_SUCCESS) { |
1071 | DEBUG2_3(printk("%s(%ld): bus_reset failed: " | 1015 | DEBUG2_3(printk("%s(%ld): bus_reset failed: " |
1072 | "target_reset=%d d_id=%x.\n", __func__, | 1016 | "target_reset=%d d_id=%x.\n", __func__, |
@@ -1258,7 +1202,8 @@ static struct isp_operations qla2100_isp_ops = { | |||
1258 | .enable_intrs = qla2x00_enable_intrs, | 1202 | .enable_intrs = qla2x00_enable_intrs, |
1259 | .disable_intrs = qla2x00_disable_intrs, | 1203 | .disable_intrs = qla2x00_disable_intrs, |
1260 | .abort_command = qla2x00_abort_command, | 1204 | .abort_command = qla2x00_abort_command, |
1261 | .abort_target = qla2x00_abort_target, | 1205 | .target_reset = qla2x00_abort_target, |
1206 | .lun_reset = qla2x00_lun_reset, | ||
1262 | .fabric_login = qla2x00_login_fabric, | 1207 | .fabric_login = qla2x00_login_fabric, |
1263 | .fabric_logout = qla2x00_fabric_logout, | 1208 | .fabric_logout = qla2x00_fabric_logout, |
1264 | .calc_req_entries = qla2x00_calc_iocbs_32, | 1209 | .calc_req_entries = qla2x00_calc_iocbs_32, |
@@ -1291,7 +1236,8 @@ static struct isp_operations qla2300_isp_ops = { | |||
1291 | .enable_intrs = qla2x00_enable_intrs, | 1236 | .enable_intrs = qla2x00_enable_intrs, |
1292 | .disable_intrs = qla2x00_disable_intrs, | 1237 | .disable_intrs = qla2x00_disable_intrs, |
1293 | .abort_command = qla2x00_abort_command, | 1238 | .abort_command = qla2x00_abort_command, |
1294 | .abort_target = qla2x00_abort_target, | 1239 | .target_reset = qla2x00_abort_target, |
1240 | .lun_reset = qla2x00_lun_reset, | ||
1295 | .fabric_login = qla2x00_login_fabric, | 1241 | .fabric_login = qla2x00_login_fabric, |
1296 | .fabric_logout = qla2x00_fabric_logout, | 1242 | .fabric_logout = qla2x00_fabric_logout, |
1297 | .calc_req_entries = qla2x00_calc_iocbs_32, | 1243 | .calc_req_entries = qla2x00_calc_iocbs_32, |
@@ -1324,7 +1270,8 @@ static struct isp_operations qla24xx_isp_ops = { | |||
1324 | .enable_intrs = qla24xx_enable_intrs, | 1270 | .enable_intrs = qla24xx_enable_intrs, |
1325 | .disable_intrs = qla24xx_disable_intrs, | 1271 | .disable_intrs = qla24xx_disable_intrs, |
1326 | .abort_command = qla24xx_abort_command, | 1272 | .abort_command = qla24xx_abort_command, |
1327 | .abort_target = qla24xx_abort_target, | 1273 | .target_reset = qla24xx_abort_target, |
1274 | .lun_reset = qla24xx_lun_reset, | ||
1328 | .fabric_login = qla24xx_login_fabric, | 1275 | .fabric_login = qla24xx_login_fabric, |
1329 | .fabric_logout = qla24xx_fabric_logout, | 1276 | .fabric_logout = qla24xx_fabric_logout, |
1330 | .calc_req_entries = NULL, | 1277 | .calc_req_entries = NULL, |
@@ -1357,7 +1304,8 @@ static struct isp_operations qla25xx_isp_ops = { | |||
1357 | .enable_intrs = qla24xx_enable_intrs, | 1304 | .enable_intrs = qla24xx_enable_intrs, |
1358 | .disable_intrs = qla24xx_disable_intrs, | 1305 | .disable_intrs = qla24xx_disable_intrs, |
1359 | .abort_command = qla24xx_abort_command, | 1306 | .abort_command = qla24xx_abort_command, |
1360 | .abort_target = qla24xx_abort_target, | 1307 | .target_reset = qla24xx_abort_target, |
1308 | .lun_reset = qla24xx_lun_reset, | ||
1361 | .fabric_login = qla24xx_login_fabric, | 1309 | .fabric_login = qla24xx_login_fabric, |
1362 | .fabric_logout = qla24xx_fabric_logout, | 1310 | .fabric_logout = qla24xx_fabric_logout, |
1363 | .calc_req_entries = NULL, | 1311 | .calc_req_entries = NULL, |