diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_scsi.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 119 |
1 files changed, 116 insertions, 3 deletions
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 2af8cfbc3890..7141f9a675df 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" |
@@ -57,8 +57,8 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | |||
57 | { | 57 | { |
58 | struct zfcp_unit *unit; | 58 | struct zfcp_unit *unit; |
59 | struct zfcp_adapter *adapter; | 59 | struct zfcp_adapter *adapter; |
60 | int status; | 60 | int status, scsi_result, ret; |
61 | int ret; | 61 | struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device)); |
62 | 62 | ||
63 | /* reset the status for this request */ | 63 | /* reset the status for this request */ |
64 | scpnt->result = 0; | 64 | scpnt->result = 0; |
@@ -80,6 +80,14 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | |||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | scsi_result = fc_remote_port_chkready(rport); | ||
84 | if (unlikely(scsi_result)) { | ||
85 | scpnt->result = scsi_result; | ||
86 | zfcp_scsi_dbf_event_result("fail", 4, adapter, scpnt, NULL); | ||
87 | scpnt->scsi_done(scpnt); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
83 | status = atomic_read(&unit->status); | 91 | status = atomic_read(&unit->status); |
84 | if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || | 92 | if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || |
85 | !(status & ZFCP_STATUS_COMMON_RUNNING))) { | 93 | !(status & ZFCP_STATUS_COMMON_RUNNING))) { |
@@ -473,6 +481,109 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) | |||
473 | rport->dev_loss_tmo = timeout; | 481 | rport->dev_loss_tmo = timeout; |
474 | } | 482 | } |
475 | 483 | ||
484 | /** | ||
485 | * zfcp_scsi_dev_loss_tmo_callbk - Free any reference to rport | ||
486 | * @rport: The rport that is about to be deleted. | ||
487 | */ | ||
488 | static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport) | ||
489 | { | ||
490 | struct zfcp_port *port = rport->dd_data; | ||
491 | |||
492 | write_lock_irq(&zfcp_data.config_lock); | ||
493 | port->rport = NULL; | ||
494 | write_unlock_irq(&zfcp_data.config_lock); | ||
495 | } | ||
496 | |||
497 | /** | ||
498 | * zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport | ||
499 | * @rport: The FC rport where to teminate I/O | ||
500 | * | ||
501 | * Abort all pending SCSI commands for a port by closing the | ||
502 | * port. Using a reopen for avoids a conflict with a shutdown | ||
503 | * overwriting a reopen. | ||
504 | */ | ||
505 | static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) | ||
506 | { | ||
507 | struct zfcp_port *port = rport->dd_data; | ||
508 | |||
509 | zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL); | ||
510 | } | ||
511 | |||
512 | static void zfcp_scsi_rport_register(struct zfcp_port *port) | ||
513 | { | ||
514 | struct fc_rport_identifiers ids; | ||
515 | struct fc_rport *rport; | ||
516 | |||
517 | ids.node_name = port->wwnn; | ||
518 | ids.port_name = port->wwpn; | ||
519 | ids.port_id = port->d_id; | ||
520 | ids.roles = FC_RPORT_ROLE_FCP_TARGET; | ||
521 | |||
522 | rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); | ||
523 | if (!rport) { | ||
524 | dev_err(&port->adapter->ccw_device->dev, | ||
525 | "Registering port 0x%016Lx failed\n", | ||
526 | (unsigned long long)port->wwpn); | ||
527 | return; | ||
528 | } | ||
529 | |||
530 | rport->dd_data = port; | ||
531 | rport->maxframe_size = port->maxframe_size; | ||
532 | rport->supported_classes = port->supported_classes; | ||
533 | port->rport = rport; | ||
534 | } | ||
535 | |||
536 | static void zfcp_scsi_rport_block(struct zfcp_port *port) | ||
537 | { | ||
538 | if (port->rport) | ||
539 | fc_remote_port_delete(port->rport); | ||
540 | } | ||
541 | |||
542 | void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) | ||
543 | { | ||
544 | zfcp_port_get(port); | ||
545 | port->rport_task = RPORT_ADD; | ||
546 | |||
547 | if (!queue_work(zfcp_data.work_queue, &port->rport_work)) | ||
548 | zfcp_port_put(port); | ||
549 | } | ||
550 | |||
551 | void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) | ||
552 | { | ||
553 | zfcp_port_get(port); | ||
554 | port->rport_task = RPORT_DEL; | ||
555 | |||
556 | if (!queue_work(zfcp_data.work_queue, &port->rport_work)) | ||
557 | zfcp_port_put(port); | ||
558 | } | ||
559 | |||
560 | void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) | ||
561 | { | ||
562 | struct zfcp_port *port; | ||
563 | |||
564 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
565 | zfcp_scsi_schedule_rport_block(port); | ||
566 | } | ||
567 | |||
568 | void zfcp_scsi_rport_work(struct work_struct *work) | ||
569 | { | ||
570 | struct zfcp_port *port = container_of(work, struct zfcp_port, | ||
571 | rport_work); | ||
572 | |||
573 | while (port->rport_task) { | ||
574 | if (port->rport_task == RPORT_ADD) { | ||
575 | port->rport_task = RPORT_NONE; | ||
576 | zfcp_scsi_rport_register(port); | ||
577 | } else { | ||
578 | port->rport_task = RPORT_NONE; | ||
579 | zfcp_scsi_rport_block(port); | ||
580 | } | ||
581 | } | ||
582 | |||
583 | zfcp_port_put(port); | ||
584 | } | ||
585 | |||
586 | |||
476 | struct fc_function_template zfcp_transport_functions = { | 587 | struct fc_function_template zfcp_transport_functions = { |
477 | .show_starget_port_id = 1, | 588 | .show_starget_port_id = 1, |
478 | .show_starget_port_name = 1, | 589 | .show_starget_port_name = 1, |
@@ -491,6 +602,8 @@ struct fc_function_template zfcp_transport_functions = { | |||
491 | .reset_fc_host_stats = zfcp_reset_fc_host_stats, | 602 | .reset_fc_host_stats = zfcp_reset_fc_host_stats, |
492 | .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, | 603 | .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, |
493 | .get_host_port_state = zfcp_get_host_port_state, | 604 | .get_host_port_state = zfcp_get_host_port_state, |
605 | .dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk, | ||
606 | .terminate_rport_io = zfcp_scsi_terminate_rport_io, | ||
494 | .show_host_port_state = 1, | 607 | .show_host_port_state = 1, |
495 | /* no functions registered for following dynamic attributes but | 608 | /* no functions registered for following dynamic attributes but |
496 | directly set by LLDD */ | 609 | directly set by LLDD */ |