zfcp bug fixes for 2.6.35-rc4
Subsystems (3)
cover zfcp bug fixes for 2.6.35-rc4
James,
here is a series of zfcp bug fixes for the 2.6.35 cycle. I sent the first three patches before. Since they have not been picked up yet, i included them again:
http://marc.info/?l=linux-scsi&m=127710797409112&w=2
http://marc.info/?l=linux-scsi&m=127710797409115&w=2
http://marc.info/?l=linux-scsi&m=127710797609129&w=2
The other patches address problems with recovering remote port problems.
The patch series applies cleanly on top of the current linux-2.6 git tree (2.6.35-rc4).
--
Christof
PATCH 1/9 zfcp: Fix check whether unchained ct_els is possible
From: Swen Schillig <[email protected]>
A false check was performed whether an unchained ct_els is possible or not.
---
drivers/s390/scsi/zfcp_fsf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/s390/scsi/zfcp_fsf.c +1 -1
@@ -981,7 +981,7 @@ static int zfcp_fsf_setup_ct_els_sbals(s }/* use single, unchained SBAL if it can hold the request */ -if (zfcp_qdio_sg_one_sbale (sg_req) ||zfcp_qdio_sg_one_sbale (sg_resp)) { +if (zfcp_qdio_sg_one_sbale (sg_req) &&zfcp_qdio_sg_one_sbale (sg_resp)) {zfcp_fsf_setup_ct_els_unchained (adapter->qdio, &req->qdio_req, sg_req, sg_resp);return 0 ;
PATCH 2/9 zfcp: Do not wait for SBALs on stopped queue
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
Trying to read the FC host statistics on an offline adapter results in a 5 seconds wait. Reading the statistics tries to issue an exchange port data request which first waits up to 5 seconds for an entry in the request queue.
Change the strategy for getting a free SBAL to exit when the queue is stopped. Reading the statistics will then fail without the wait.
---
drivers/s390/scsi/zfcp_fsf.c | 5 ----- drivers/s390/scsi/zfcp_qdio.c | 10 +++++++++- 2 files changed, 9 insertions(+), 6 deletions(-)
drivers/s390/scsi/zfcp_fsf.c +0 -5
@@ -719,11 +719,6 @@ static struct zfcp_fsf_req *zfcp_fsf_reqzfcp_qdio_req_init (adapter->qdio, &req->qdio_req, req->req_id, sbtype, req->qtcb,sizeof (struct fsf_qtcb )); -if (!(atomic_read (&adapter->status) &ZFCP_STATUS_ADAPTER_QDIOUP )) { -zfcp_fsf_req_free (req); -return ERR_PTR (-EIO ); - } -return req; }
drivers/s390/scsi/zfcp_qdio.c +9 -1
@@ -251,7 +251,8 @@ static int zfcp_qdio_sbal_check(struct zstruct zfcp_qdio_queue *req_q = &qdio->req_q;spin_lock_bh (&qdio->req_q_lock); -if (atomic_read (&req_q->count)) +if (atomic_read (&req_q->count) || + !(atomic_read (&qdio->adapter->status) &ZFCP_STATUS_ADAPTER_QDIOUP ))return 1 ;spin_unlock_bh (&qdio->req_q_lock);return 0 ;
@@ -274,8 +275,13 @@ int zfcp_qdio_sbal_get(struct zfcp_qdiospin_unlock_bh (&qdio->req_q_lock); ret =wait_event_interruptible_timeout (qdio->req_q_wq,zfcp_qdio_sbal_check (qdio),5 *HZ ); + +if (!(atomic_read (&qdio->adapter->status) &ZFCP_STATUS_ADAPTER_QDIOUP )) +return -EIO ; +if (ret >0 )return 0 ; +if (!ret) {atomic_inc (&qdio->req_q_full);/* assume hanging outbound queue, try queue recovery */
@@ -375,6 +381,8 @@ void zfcp_qdio_close(struct zfcp_qdio *qatomic_clear_mask (ZFCP_STATUS_ADAPTER_QDIOUP , &qdio->adapter->status);spin_unlock_bh (&qdio->req_q_lock); +wake_up (&qdio->req_q_wq); +qdio_shutdown (qdio->adapter->ccw_device,QDIO_FLAG_CLEANUP_USING_CLEAR );
PATCH 3/9 zfcp: Update status read mempool
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
Commit 64deb6efdc5504ce97b5c1c6f281fffbc150bd93 changed the way status read buffers are handled but forgot to adjust the mempool to the new size. Add the call to resize the mempool after the exchange config data. Also use the define instead of the hard coded number in the fsf callback for consistency.
---
drivers/s390/scsi/zfcp_erp.c | 8 ++++++++ drivers/s390/scsi/zfcp_fsf.c | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-)
drivers/s390/scsi/zfcp_erp.c +8 -0
@@ -714,6 +714,14 @@ static int zfcp_erp_adapter_strategy_opeif (zfcp_erp_adapter_strategy_open_fsf_xport (act) ==ZFCP_ERP_FAILED )return ZFCP_ERP_FAILED ; +if (mempool_resize (act->adapter->pool.status_read_data, + act->adapter->stat_read_buf_num,GFP_KERNEL )) +return ZFCP_ERP_FAILED ; + +if (mempool_resize (act->adapter->pool.status_read_req, + act->adapter->stat_read_buf_num,GFP_KERNEL )) +return ZFCP_ERP_FAILED ; +atomic_set (&act->adapter->stat_miss, act->adapter->stat_read_buf_num);if (zfcp_status_read_refill (act->adapter))return ZFCP_ERP_FAILED ;
drivers/s390/scsi/zfcp_fsf.c +2 -1
@@ -496,7 +496,8 @@ static int zfcp_fsf_exchange_config_eval adapter->hydra_version = bottom->adapter_type; adapter->timer_ticks = bottom->timer_interval; - adapter->stat_read_buf_num =max (bottom->status_read_buf_num, (u16 )16 ); + adapter->stat_read_buf_num =max (bottom->status_read_buf_num, + (u16 )FSF_STATUS_READS_RECOM );if (fc_host_permanent_port_name (shost) ==-1 )fc_host_permanent_port_name (shost) =fc_host_port_name (shost);
PATCH 4/9 zfcp: Do not unblock rport from REOPEN_PORT_FORCED
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
When the REOPEN_PORT_FORCED erp action succeeds, the port has been closed. A REOPEN_PORT will try to open the port after the REPORT_PORT_FORCED. The rport should only be unblocked after the successful completion of the reopen port.
---
drivers/s390/scsi/zfcp_erp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/s390/scsi/zfcp_erp.c +2 -1
@@ -1197,10 +1197,11 @@ static void zfcp_erp_action_cleanup(struput_device (&unit->dev);break ; -case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :case ZFCP_ERP_ACTION_REOPEN_PORT :if (result ==ZFCP_ERP_SUCCEEDED )zfcp_scsi_schedule_rport_register (port); +/* fall through */ +case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :put_device (&port->dev);break ;
PATCH 5/9 zfcp: Do not try "forced close" when port is already closed
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
When the port is already "physically closed" try the reopen instead. There is no way to send a "physically close" to an already closed port.
---
drivers/s390/scsi/zfcp_erp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/s390/scsi/zfcp_erp.c +5 -1
@@ -141,9 +141,13 @@ static int zfcp_erp_required_act(int wanif (!(p_status &ZFCP_STATUS_COMMON_UNBLOCKED )) need =ZFCP_ERP_ACTION_REOPEN_PORT ;/* fall through */ -case ZFCP_ERP_ACTION_REOPEN_PORT :case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED : p_status =atomic_read (&port->status); +if (!(p_status &ZFCP_STATUS_COMMON_OPEN )) + need =ZFCP_ERP_ACTION_REOPEN_PORT ; +/* fall through */ +case ZFCP_ERP_ACTION_REOPEN_PORT : + p_status =atomic_read (&port->status);if (p_status &ZFCP_STATUS_COMMON_ERP_INUSE )return 0 ; a_status =atomic_read (&adapter->status);
PATCH 6/9 zfcp: Register SCSI devices after successful fc_remote_port_add
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
When the successful return of an adisc is the final step to set the port online, the registration of SCSI devices might be omitted. SCSI devices that have been removed before (due to a short dev_loss_tmo setting) might not be attached again.
The problem is that the registration of SCSI devices is done only after erp has finished. The correct place would be after the call to fc_remote_port_add to mimick the scan in the FC transport class.
Change the registration of SCSI devices to be triggered after the fc_remote_port_add call. For the initial inquiry command to succeed, the unit must also be open. If the unit reopen is still pending, the inquiry command to the LUN will be deferred with DID_IMM_RETRY, so there is no harm from this approach.
---
drivers/s390/scsi/zfcp_aux.c | 2 +- drivers/s390/scsi/zfcp_erp.c | 6 ------ drivers/s390/scsi/zfcp_ext.h | 3 ++- drivers/s390/scsi/zfcp_scsi.c | 37 +++++++++++++++++++++++++++++-------- drivers/s390/scsi/zfcp_sysfs.c | 2 +- 5 files changed, 33 insertions(+), 17 deletions(-)
drivers/s390/scsi/zfcp_aux.c +1 -1
@@ -314,7 +314,7 @@ struct zfcp_unit *zfcp_unit_enqueue(stru } retval = -EINVAL ; -INIT_WORK (&unit->scsi_work, zfcp_scsi_scan); +INIT_WORK (&unit->scsi_work, zfcp_scsi_scan_work);spin_lock_init (&unit->latencies.lock); unit->latencies.write.channel.min =0xFFFFFFFF ;
drivers/s390/scsi/zfcp_erp.c +0 -6
@@ -1192,12 +1192,6 @@ static void zfcp_erp_action_cleanup(struswitch (act->action) {case ZFCP_ERP_ACTION_REOPEN_UNIT : -if ((result ==ZFCP_ERP_SUCCEEDED ) && !unit->device) { -get_device (&unit->dev); -if (scsi_queue_work (unit->port->adapter->scsi_host, - &unit->scsi_work) <=0 ) -put_device (&unit->dev); - }put_device (&unit->dev);break ;
drivers/s390/scsi/zfcp_ext.h +2 -1
@@ -159,7 +159,8 @@ extern void zfcp_scsi_rport_work(structextern void zfcp_scsi_schedule_rport_register (struct zfcp_port *);extern void zfcp_scsi_schedule_rport_block (struct zfcp_port *);extern void zfcp_scsi_schedule_rports_block (struct zfcp_adapter *); -extern void zfcp_scsi_scan (struct work_struct *); +extern void zfcp_scsi_scan (struct zfcp_unit *); +extern void zfcp_scsi_scan_work (struct work_struct *);/* zfcp_sysfs.c */ extern struct attribute_group zfcp_sysfs_unit_attrs;
drivers/s390/scsi/zfcp_scsi.c +29 -8
@@ -524,6 +524,20 @@ static void zfcp_scsi_terminate_rport_io } } +static void zfcp_scsi_queue_unit_register (struct zfcp_port *port) +{ +struct zfcp_unit *unit; + +read_lock_irq (&port->unit_list_lock); +list_for_each_entry (unit, &port->unit_list, list) { +get_device (&unit->dev); +if (scsi_queue_work (port->adapter->scsi_host, + &unit->scsi_work) <=0 ) +put_device (&unit->dev); + } +read_unlock_irq (&port->unit_list_lock); +} +static void zfcp_scsi_rport_register (struct zfcp_port *port) {struct fc_rport_identifiers ids;
@@ -548,6 +562,8 @@ static void zfcp_scsi_rport_register(str rport->maxframe_size = port->maxframe_size; rport->supported_classes = port->supported_classes; port->rport = rport; + +zfcp_scsi_queue_unit_register (port); }static void zfcp_scsi_rport_block (struct zfcp_port *port)
@@ -610,21 +626,26 @@ void zfcp_scsi_rport_work(struct work_stput_device (&port->dev); } - -void zfcp_scsi_scan (struct work_struct *work) +/** +* zfcp_scsi_scan - Register LUN with SCSI midlayer +* @unit: The LUN/unit to register +*/ +void zfcp_scsi_scan (struct zfcp_unit *unit) { - struct zfcp_unit *unit = container_of(work, struct zfcp_unit, - scsi_work); -struct fc_rport *rport; - -flush_work (&unit->port->rport_work); - rport = unit->port->rport; +struct fc_rport *rport = unit->port->rport;if (rport && rport->port_state ==FC_PORTSTATE_ONLINE )scsi_scan_target (&rport->dev,0 , rport->scsi_target_id,scsilun_to_int ((struct scsi_lun *) &unit->fcp_lun),0 ); +} + +void zfcp_scsi_scan_work (struct work_struct *work) +{ + struct zfcp_unit *unit = container_of(work, struct zfcp_unit, + scsi_work); +zfcp_scsi_scan (unit);put_device (&unit->dev); }
drivers/s390/scsi/zfcp_sysfs.c +1 -1
@@ -275,7 +275,7 @@ static ssize_t zfcp_sysfs_unit_add_storezfcp_erp_unit_reopen (unit,0 ,"syuas_1" ,NULL );zfcp_erp_wait (unit->port->adapter); -flush_work (&unit->scsi_work); +zfcp_scsi_scan (unit); out:put_device (&port->dev);return retval ? retval : (ssize_t ) count;
PATCH 7/9 zfcp: Use forced_reopen in terminate_rport_io callback
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
When running in non-NPIV mode, the port_reopen in terminate_rport_io might succeed even though the remote port is not available. If the same port connection is held open from another operating system, the reopen is only a virtual operation and might not hit the SAN. Fix this by changing the call to forced_reopen that forces a logout/login operation in the SAN.
---
drivers/s390/scsi/zfcp_scsi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/s390/scsi/zfcp_scsi.c +5 -3
@@ -506,8 +506,10 @@ static void zfcp_set_rport_dev_loss_tmo(* @rport: The FC rport where to teminate I/O * * Abort all pending SCSI commands for a port by closing the -* port. Using a reopen avoiding a conflict with a shutdown -* overwriting a reopen. +* port. Using a reopen avoids a conflict with a shutdown +* overwriting a reopen. The "forced" ensures that a disappeared port +* is not opened again as valid due to the cached plogi data in +* non-NPIV mode. */ static void zfcp_scsi_terminate_rport_io (struct fc_rport *rport) {
@@ -519,7 +521,7 @@ static void zfcp_scsi_terminate_rport_io port =zfcp_get_port_by_wwpn (adapter, rport->port_name);if (port) { -zfcp_erp_port_reopen (port,0 ,"sctrpi1" ,NULL ); +zfcp_erp_port_forced_reopen (port,0 ,"sctrpi1" ,NULL );put_device (&port->dev); } }
PATCH 8/9 zfcp: Fail erp after timeout
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
After a timeout notification, do not try to run the erp strategy. Return from the erp with "failed" to possibly trigger a retry.
---
drivers/s390/scsi/zfcp_erp.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/s390/scsi/zfcp_erp.c +6 -0
@@ -1246,6 +1246,11 @@ static int zfcp_erp_strategy(struct zfcp goto unlock; } +if (erp_action->status &ZFCP_STATUS_ERP_TIMEDOUT ) { + retval =ZFCP_ERP_FAILED ; + goto check_target; + } +zfcp_erp_action_to_running (erp_action);/* no lock to allow for blocking operations */
@@ -1278,6 +1283,7 @@ static int zfcp_erp_strategy(struct zfcp goto unlock; } +check_target: retval =zfcp_erp_strategy_check_target (erp_action, retval);zfcp_erp_action_dequeue (erp_action); retval =zfcp_erp_strategy_statechange (erp_action, retval);
PATCH 9/9 zfcp: Fix retry after failed "open port" erp action
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
Trying to enqueue a port erp action from the port erp strategy will fail in zfcp_erp_required_act. To try the same action again, return ZFCP_ERP_FAILED.
---
drivers/s390/scsi/zfcp_erp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/s390/scsi/zfcp_erp.c +1 -2
@@ -897,8 +897,7 @@ static int zfcp_erp_port_strategy_open_c }if (port->d_id && !(p_status &ZFCP_STATUS_COMMON_NOESC )) { port->d_id =0 ; -_zfcp_erp_port_reopen (port,0 ,"erpsoc1" ,NULL ); -return ZFCP_ERP_EXIT ; +return ZFCP_ERP_FAILED ; }/* fall through otherwise */ }