diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_scsi.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 250 |
1 files changed, 178 insertions, 72 deletions
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 9dc42a68fbdd..58201e1ae478 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Interface to Linux SCSI midlayer. | 4 | * Interface to Linux SCSI midlayer. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2002, 2008 | 6 | * Copyright IBM Corporation 2002, 2009 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define KMSG_COMPONENT "zfcp" | 9 | #define KMSG_COMPONENT "zfcp" |
@@ -27,9 +27,7 @@ char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) | |||
27 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) | 27 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) |
28 | { | 28 | { |
29 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; | 29 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; |
30 | atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); | ||
31 | unit->device = NULL; | 30 | unit->device = NULL; |
32 | zfcp_erp_unit_failed(unit, 12, NULL); | ||
33 | zfcp_unit_put(unit); | 31 | zfcp_unit_put(unit); |
34 | } | 32 | } |
35 | 33 | ||
@@ -58,8 +56,8 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | |||
58 | { | 56 | { |
59 | struct zfcp_unit *unit; | 57 | struct zfcp_unit *unit; |
60 | struct zfcp_adapter *adapter; | 58 | struct zfcp_adapter *adapter; |
61 | int status; | 59 | int status, scsi_result, ret; |
62 | int ret; | 60 | struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device)); |
63 | 61 | ||
64 | /* reset the status for this request */ | 62 | /* reset the status for this request */ |
65 | scpnt->result = 0; | 63 | scpnt->result = 0; |
@@ -81,6 +79,14 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | |||
81 | return 0; | 79 | return 0; |
82 | } | 80 | } |
83 | 81 | ||
82 | scsi_result = fc_remote_port_chkready(rport); | ||
83 | if (unlikely(scsi_result)) { | ||
84 | scpnt->result = scsi_result; | ||
85 | zfcp_scsi_dbf_event_result("fail", 4, adapter, scpnt, NULL); | ||
86 | scpnt->scsi_done(scpnt); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
84 | status = atomic_read(&unit->status); | 90 | status = atomic_read(&unit->status); |
85 | if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || | 91 | if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || |
86 | !(status & ZFCP_STATUS_COMMON_RUNNING))) { | 92 | !(status & ZFCP_STATUS_COMMON_RUNNING))) { |
@@ -88,8 +94,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | |||
88 | return 0;; | 94 | return 0;; |
89 | } | 95 | } |
90 | 96 | ||
91 | ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, 0, | 97 | ret = zfcp_fsf_send_fcp_command_task(unit, scpnt); |
92 | ZFCP_REQ_AUTO_CLEANUP); | ||
93 | if (unlikely(ret == -EBUSY)) | 98 | if (unlikely(ret == -EBUSY)) |
94 | return SCSI_MLQUEUE_DEVICE_BUSY; | 99 | return SCSI_MLQUEUE_DEVICE_BUSY; |
95 | else if (unlikely(ret < 0)) | 100 | else if (unlikely(ret < 0)) |
@@ -133,8 +138,7 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdp) | |||
133 | 138 | ||
134 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 139 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
135 | unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun); | 140 | unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun); |
136 | if (unit && | 141 | if (unit) { |
137 | (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_REGISTERED)) { | ||
138 | sdp->hostdata = unit; | 142 | sdp->hostdata = unit; |
139 | unit->device = sdp; | 143 | unit->device = sdp; |
140 | zfcp_unit_get(unit); | 144 | zfcp_unit_get(unit); |
@@ -147,79 +151,91 @@ out: | |||
147 | 151 | ||
148 | static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | 152 | static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) |
149 | { | 153 | { |
150 | struct Scsi_Host *scsi_host; | 154 | struct Scsi_Host *scsi_host = scpnt->device->host; |
151 | struct zfcp_adapter *adapter; | 155 | struct zfcp_adapter *adapter = |
152 | struct zfcp_unit *unit; | 156 | (struct zfcp_adapter *) scsi_host->hostdata[0]; |
153 | struct zfcp_fsf_req *fsf_req; | 157 | struct zfcp_unit *unit = scpnt->device->hostdata; |
158 | struct zfcp_fsf_req *old_req, *abrt_req; | ||
154 | unsigned long flags; | 159 | unsigned long flags; |
155 | unsigned long old_req_id = (unsigned long) scpnt->host_scribble; | 160 | unsigned long old_req_id = (unsigned long) scpnt->host_scribble; |
156 | int retval = SUCCESS; | 161 | int retval = SUCCESS; |
157 | 162 | int retry = 3; | |
158 | scsi_host = scpnt->device->host; | ||
159 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | ||
160 | unit = scpnt->device->hostdata; | ||
161 | 163 | ||
162 | /* avoid race condition between late normal completion and abort */ | 164 | /* avoid race condition between late normal completion and abort */ |
163 | write_lock_irqsave(&adapter->abort_lock, flags); | 165 | write_lock_irqsave(&adapter->abort_lock, flags); |
164 | 166 | ||
165 | /* Check whether corresponding fsf_req is still pending */ | ||
166 | spin_lock(&adapter->req_list_lock); | 167 | spin_lock(&adapter->req_list_lock); |
167 | fsf_req = zfcp_reqlist_find(adapter, old_req_id); | 168 | old_req = zfcp_reqlist_find(adapter, old_req_id); |
168 | spin_unlock(&adapter->req_list_lock); | 169 | spin_unlock(&adapter->req_list_lock); |
169 | if (!fsf_req) { | 170 | if (!old_req) { |
170 | write_unlock_irqrestore(&adapter->abort_lock, flags); | 171 | write_unlock_irqrestore(&adapter->abort_lock, flags); |
171 | zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0); | 172 | zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, |
172 | return retval; | 173 | old_req_id); |
174 | return SUCCESS; | ||
173 | } | 175 | } |
174 | fsf_req->data = NULL; | 176 | old_req->data = NULL; |
175 | 177 | ||
176 | /* don't access old fsf_req after releasing the abort_lock */ | 178 | /* don't access old fsf_req after releasing the abort_lock */ |
177 | write_unlock_irqrestore(&adapter->abort_lock, flags); | 179 | write_unlock_irqrestore(&adapter->abort_lock, flags); |
178 | 180 | ||
179 | fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0); | 181 | while (retry--) { |
180 | if (!fsf_req) { | 182 | abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit); |
181 | zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, | 183 | if (abrt_req) |
182 | old_req_id); | 184 | break; |
183 | retval = FAILED; | 185 | |
184 | return retval; | 186 | zfcp_erp_wait(adapter); |
187 | if (!(atomic_read(&adapter->status) & | ||
188 | ZFCP_STATUS_COMMON_RUNNING)) { | ||
189 | zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, | ||
190 | old_req_id); | ||
191 | return SUCCESS; | ||
192 | } | ||
185 | } | 193 | } |
194 | if (!abrt_req) | ||
195 | return FAILED; | ||
186 | 196 | ||
187 | __wait_event(fsf_req->completion_wq, | 197 | wait_event(abrt_req->completion_wq, |
188 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | 198 | abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); |
189 | 199 | ||
190 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { | 200 | if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) |
191 | zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0); | 201 | zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0); |
192 | } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { | 202 | else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) |
193 | zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0); | 203 | zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0); |
194 | } else { | 204 | else { |
195 | zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0); | 205 | zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0); |
196 | retval = FAILED; | 206 | retval = FAILED; |
197 | } | 207 | } |
198 | zfcp_fsf_req_free(fsf_req); | 208 | zfcp_fsf_req_free(abrt_req); |
199 | |||
200 | return retval; | 209 | return retval; |
201 | } | 210 | } |
202 | 211 | ||
203 | static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags, | 212 | static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) |
204 | struct scsi_cmnd *scpnt) | ||
205 | { | 213 | { |
214 | struct zfcp_unit *unit = scpnt->device->hostdata; | ||
206 | struct zfcp_adapter *adapter = unit->port->adapter; | 215 | struct zfcp_adapter *adapter = unit->port->adapter; |
207 | struct zfcp_fsf_req *fsf_req; | 216 | struct zfcp_fsf_req *fsf_req; |
208 | int retval = SUCCESS; | 217 | int retval = SUCCESS; |
209 | 218 | int retry = 3; | |
210 | /* issue task management function */ | 219 | |
211 | fsf_req = zfcp_fsf_send_fcp_ctm(adapter, unit, tm_flags, 0); | 220 | while (retry--) { |
212 | if (!fsf_req) { | 221 | fsf_req = zfcp_fsf_send_fcp_ctm(unit, tm_flags); |
213 | zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); | 222 | if (fsf_req) |
214 | return FAILED; | 223 | break; |
224 | |||
225 | zfcp_erp_wait(adapter); | ||
226 | if (!(atomic_read(&adapter->status) & | ||
227 | ZFCP_STATUS_COMMON_RUNNING)) { | ||
228 | zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, | ||
229 | scpnt); | ||
230 | return SUCCESS; | ||
231 | } | ||
215 | } | 232 | } |
233 | if (!fsf_req) | ||
234 | return FAILED; | ||
216 | 235 | ||
217 | __wait_event(fsf_req->completion_wq, | 236 | wait_event(fsf_req->completion_wq, |
218 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | 237 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); |
219 | 238 | ||
220 | /* | ||
221 | * check completion status of task management function | ||
222 | */ | ||
223 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { | 239 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { |
224 | zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); | 240 | zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); |
225 | retval = FAILED; | 241 | retval = FAILED; |
@@ -230,40 +246,25 @@ static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags, | |||
230 | zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); | 246 | zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); |
231 | 247 | ||
232 | zfcp_fsf_req_free(fsf_req); | 248 | zfcp_fsf_req_free(fsf_req); |
233 | |||
234 | return retval; | 249 | return retval; |
235 | } | 250 | } |
236 | 251 | ||
237 | static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) | 252 | static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) |
238 | { | 253 | { |
239 | struct zfcp_unit *unit = scpnt->device->hostdata; | 254 | return zfcp_task_mgmt_function(scpnt, FCP_LOGICAL_UNIT_RESET); |
240 | |||
241 | if (!unit) { | ||
242 | WARN_ON(1); | ||
243 | return SUCCESS; | ||
244 | } | ||
245 | return zfcp_task_mgmt_function(unit, FCP_LOGICAL_UNIT_RESET, scpnt); | ||
246 | } | 255 | } |
247 | 256 | ||
248 | static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) | 257 | static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) |
249 | { | 258 | { |
250 | struct zfcp_unit *unit = scpnt->device->hostdata; | 259 | return zfcp_task_mgmt_function(scpnt, FCP_TARGET_RESET); |
251 | |||
252 | if (!unit) { | ||
253 | WARN_ON(1); | ||
254 | return SUCCESS; | ||
255 | } | ||
256 | return zfcp_task_mgmt_function(unit, FCP_TARGET_RESET, scpnt); | ||
257 | } | 260 | } |
258 | 261 | ||
259 | static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) | 262 | static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) |
260 | { | 263 | { |
261 | struct zfcp_unit *unit; | 264 | struct zfcp_unit *unit = scpnt->device->hostdata; |
262 | struct zfcp_adapter *adapter; | 265 | struct zfcp_adapter *adapter = unit->port->adapter; |
263 | 266 | ||
264 | unit = scpnt->device->hostdata; | 267 | zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt); |
265 | adapter = unit->port->adapter; | ||
266 | zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt); | ||
267 | zfcp_erp_wait(adapter); | 268 | zfcp_erp_wait(adapter); |
268 | 269 | ||
269 | return SUCCESS; | 270 | return SUCCESS; |
@@ -479,6 +480,109 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) | |||
479 | rport->dev_loss_tmo = timeout; | 480 | rport->dev_loss_tmo = timeout; |
480 | } | 481 | } |
481 | 482 | ||
483 | /** | ||
484 | * zfcp_scsi_dev_loss_tmo_callbk - Free any reference to rport | ||
485 | * @rport: The rport that is about to be deleted. | ||
486 | */ | ||
487 | static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport) | ||
488 | { | ||
489 | struct zfcp_port *port = rport->dd_data; | ||
490 | |||
491 | write_lock_irq(&zfcp_data.config_lock); | ||
492 | port->rport = NULL; | ||
493 | write_unlock_irq(&zfcp_data.config_lock); | ||
494 | } | ||
495 | |||
496 | /** | ||
497 | * zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport | ||
498 | * @rport: The FC rport where to teminate I/O | ||
499 | * | ||
500 | * Abort all pending SCSI commands for a port by closing the | ||
501 | * port. Using a reopen for avoids a conflict with a shutdown | ||
502 | * overwriting a reopen. | ||
503 | */ | ||
504 | static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) | ||
505 | { | ||
506 | struct zfcp_port *port = rport->dd_data; | ||
507 | |||
508 | zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL); | ||
509 | } | ||
510 | |||
511 | static void zfcp_scsi_rport_register(struct zfcp_port *port) | ||
512 | { | ||
513 | struct fc_rport_identifiers ids; | ||
514 | struct fc_rport *rport; | ||
515 | |||
516 | ids.node_name = port->wwnn; | ||
517 | ids.port_name = port->wwpn; | ||
518 | ids.port_id = port->d_id; | ||
519 | ids.roles = FC_RPORT_ROLE_FCP_TARGET; | ||
520 | |||
521 | rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); | ||
522 | if (!rport) { | ||
523 | dev_err(&port->adapter->ccw_device->dev, | ||
524 | "Registering port 0x%016Lx failed\n", | ||
525 | (unsigned long long)port->wwpn); | ||
526 | return; | ||
527 | } | ||
528 | |||
529 | rport->dd_data = port; | ||
530 | rport->maxframe_size = port->maxframe_size; | ||
531 | rport->supported_classes = port->supported_classes; | ||
532 | port->rport = rport; | ||
533 | } | ||
534 | |||
535 | static void zfcp_scsi_rport_block(struct zfcp_port *port) | ||
536 | { | ||
537 | if (port->rport) | ||
538 | fc_remote_port_delete(port->rport); | ||
539 | } | ||
540 | |||
541 | void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) | ||
542 | { | ||
543 | zfcp_port_get(port); | ||
544 | port->rport_task = RPORT_ADD; | ||
545 | |||
546 | if (!queue_work(zfcp_data.work_queue, &port->rport_work)) | ||
547 | zfcp_port_put(port); | ||
548 | } | ||
549 | |||
550 | void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) | ||
551 | { | ||
552 | zfcp_port_get(port); | ||
553 | port->rport_task = RPORT_DEL; | ||
554 | |||
555 | if (!queue_work(zfcp_data.work_queue, &port->rport_work)) | ||
556 | zfcp_port_put(port); | ||
557 | } | ||
558 | |||
559 | void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) | ||
560 | { | ||
561 | struct zfcp_port *port; | ||
562 | |||
563 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
564 | zfcp_scsi_schedule_rport_block(port); | ||
565 | } | ||
566 | |||
567 | void zfcp_scsi_rport_work(struct work_struct *work) | ||
568 | { | ||
569 | struct zfcp_port *port = container_of(work, struct zfcp_port, | ||
570 | rport_work); | ||
571 | |||
572 | while (port->rport_task) { | ||
573 | if (port->rport_task == RPORT_ADD) { | ||
574 | port->rport_task = RPORT_NONE; | ||
575 | zfcp_scsi_rport_register(port); | ||
576 | } else { | ||
577 | port->rport_task = RPORT_NONE; | ||
578 | zfcp_scsi_rport_block(port); | ||
579 | } | ||
580 | } | ||
581 | |||
582 | zfcp_port_put(port); | ||
583 | } | ||
584 | |||
585 | |||
482 | struct fc_function_template zfcp_transport_functions = { | 586 | struct fc_function_template zfcp_transport_functions = { |
483 | .show_starget_port_id = 1, | 587 | .show_starget_port_id = 1, |
484 | .show_starget_port_name = 1, | 588 | .show_starget_port_name = 1, |
@@ -497,6 +601,8 @@ struct fc_function_template zfcp_transport_functions = { | |||
497 | .reset_fc_host_stats = zfcp_reset_fc_host_stats, | 601 | .reset_fc_host_stats = zfcp_reset_fc_host_stats, |
498 | .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, | 602 | .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, |
499 | .get_host_port_state = zfcp_get_host_port_state, | 603 | .get_host_port_state = zfcp_get_host_port_state, |
604 | .dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk, | ||
605 | .terminate_rport_io = zfcp_scsi_terminate_rport_io, | ||
500 | .show_host_port_state = 1, | 606 | .show_host_port_state = 1, |
501 | /* no functions registered for following dynamic attributes but | 607 | /* no functions registered for following dynamic attributes but |
502 | directly set by LLDD */ | 608 | directly set by LLDD */ |