From f09d5454576b9aabd4ce454937cd86263428090b Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 13 Jan 2010 17:52:36 +0100 Subject: [SCSI] zfcp: Issue zfcp_fc_wka_port_put after FC CT BSG request The patch "zfcp: Simplify handling of ct and els requests" accidentally removed the call to zfcp_fc_wka_port_put for FC CT BSG requests, thus not issuing a "close" request for the WKA ports. Introduce a CT specific handler to first call zfcp_fc_wka_port_put and then continue with the generic handler when returning from FC CT BSG requests. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fc.c | 65 ++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 22 deletions(-) (limited to 'drivers/s390/scsi') diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index ac5e3b7a3576..81d4375aa50e 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -677,6 +677,44 @@ static void zfcp_fc_ct_els_job_handler(void *data) job->job_done(job); } +static struct zfcp_fc_wka_port *zfcp_fc_job_wka_port(struct fc_bsg_job *job) +{ + u32 preamble_word1; + u8 gs_type; + struct zfcp_adapter *adapter; + + preamble_word1 = job->request->rqst_data.r_ct.preamble_word1; + gs_type = (preamble_word1 & 0xff000000) >> 24; + + adapter = (struct zfcp_adapter *) job->shost->hostdata[0]; + + switch (gs_type) { + case FC_FST_ALIAS: + return &adapter->gs->as; + case FC_FST_MGMT: + return &adapter->gs->ms; + case FC_FST_TIME: + return &adapter->gs->ts; + break; + case FC_FST_DIR: + return &adapter->gs->ds; + break; + default: + return NULL; + } +} + +static void zfcp_fc_ct_job_handler(void *data) +{ + struct fc_bsg_job *job = data; + struct zfcp_fc_wka_port *wka_port; + + wka_port = zfcp_fc_job_wka_port(job); + zfcp_fc_wka_port_put(wka_port); + + zfcp_fc_ct_els_job_handler(data); +} + static int zfcp_fc_exec_els_job(struct fc_bsg_job *job, struct zfcp_adapter *adapter) { @@ -695,6 +733,7 @@ static int zfcp_fc_exec_els_job(struct fc_bsg_job *job, } else d_id = ntoh24(job->request->rqst_data.h_els.port_id); + els->handler = zfcp_fc_ct_els_job_handler; return zfcp_fsf_send_els(adapter, d_id, els); } @@ -702,35 +741,18 @@ static int zfcp_fc_exec_ct_job(struct fc_bsg_job *job, struct zfcp_adapter *adapter) { int ret; - u8 gs_type; struct zfcp_fsf_ct_els *ct = job->dd_data; struct zfcp_fc_wka_port *wka_port; - u32 preamble_word1; - preamble_word1 = job->request->rqst_data.r_ct.preamble_word1; - gs_type = (preamble_word1 & 0xff000000) >> 24; - - switch (gs_type) { - case FC_FST_ALIAS: - wka_port = &adapter->gs->as; - break; - case FC_FST_MGMT: - wka_port = &adapter->gs->ms; - break; - case FC_FST_TIME: - wka_port = &adapter->gs->ts; - break; - case FC_FST_DIR: - wka_port = &adapter->gs->ds; - break; - default: - return -EINVAL; /* no such service */ - } + wka_port = zfcp_fc_job_wka_port(job); + if (!wka_port) + return -EINVAL; ret = zfcp_fc_wka_port_get(wka_port); if (ret) return ret; + ct->handler = zfcp_fc_ct_job_handler; ret = zfcp_fsf_send_ct(wka_port, ct, NULL); if (ret) zfcp_fc_wka_port_put(wka_port); @@ -752,7 +774,6 @@ int zfcp_fc_exec_bsg_job(struct fc_bsg_job *job) ct_els->req = job->request_payload.sg_list; ct_els->resp = job->reply_payload.sg_list; - ct_els->handler = zfcp_fc_ct_els_job_handler; ct_els->handler_data = job; switch (job->request->msgcode) { -- cgit v1.2.2 From 5a3fb3081a0166cdc5df0d9200234d09ad8d6083 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 13 Jan 2010 17:52:37 +0100 Subject: [SCSI] zfcp: Fix linebreak in hba trace Advance the correct pointer when inserting the linebreak for the HBA trace. It was missing in the output since the pointer to the output buffer was never advanced, and the linebreak character was overwritten later. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390/scsi') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 84450955ae11..7369c8911bcf 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -327,7 +327,7 @@ static void zfcp_dbf_hba_view_response(char **p, break; zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd); zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial); - p += sprintf(*p, "\n"); + *p += sprintf(*p, "\n"); break; case FSF_QTCB_OPEN_PORT_WITH_DID: -- cgit v1.2.2 From 9e2ab1fabdbd88669fdebd368fb5cda32ad5438d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 13 Jan 2010 17:52:38 +0100 Subject: [SCSI] zfcp: add missing compat ptr conversion Signed-off-by: Heiko Carstens Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_cfdc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/s390/scsi') diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index f932400e980a..0eb6eefd2c1a 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -12,6 +12,7 @@ #include #include +#include #include #include "zfcp_def.h" #include "zfcp_ext.h" @@ -163,7 +164,7 @@ static void zfcp_cfdc_req_to_sense(struct zfcp_cfdc_data *data, } static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, - unsigned long buffer) + unsigned long arg) { struct zfcp_cfdc_data *data; struct zfcp_cfdc_data __user *data_user; @@ -175,7 +176,11 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, if (command != ZFCP_CFDC_IOC) return -ENOTTY; - data_user = (void __user *) buffer; + if (is_compat_task()) + data_user = compat_ptr(arg); + else + data_user = (void __user *)arg; + if (!data_user) return -EINVAL; -- cgit v1.2.2 From 491ca4426ba153f79e72d1ca2a30c926484282b7 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Thu, 14 Jan 2010 17:19:01 +0100 Subject: [SCSI] zfcp: Introduce bsg_timeout callback. Introduce a zfcp callback for timeouts triggered from FC BSG. With zfcp, the underlying hardware cannot abort CT or ELS requests, so there is nothing to do when the block layer timeout expires. To avoid interference with the block layer timeout, simply indicate that the block layer timer should be reset. The timer running in the hardware for the pending CT or ELS request will return the request when it expires. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_ext.h | 1 + drivers/s390/scsi/zfcp_fc.c | 6 ++++++ drivers/s390/scsi/zfcp_scsi.c | 1 + 3 files changed, 8 insertions(+) (limited to 'drivers/s390/scsi') diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 03dec832b465..1406a65a6205 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -108,6 +108,7 @@ extern void zfcp_fc_wka_ports_force_offline(struct zfcp_fc_wka_ports *); extern int zfcp_fc_gs_setup(struct zfcp_adapter *); extern void zfcp_fc_gs_destroy(struct zfcp_adapter *); extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *); +extern int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *); /* zfcp_fsf.c */ extern int zfcp_fsf_open_port(struct zfcp_erp_action *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 81d4375aa50e..37a0ca200a32 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -788,6 +788,12 @@ int zfcp_fc_exec_bsg_job(struct fc_bsg_job *job) } } +int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *job) +{ + /* hardware tracks timeout, reset bsg timeout to not interfere */ + return -EAGAIN; +} + int zfcp_fc_gs_setup(struct zfcp_adapter *adapter) { struct zfcp_fc_wka_ports *wka_ports; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 771cc536a989..8e6fc68d6bd4 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -652,6 +652,7 @@ struct fc_function_template zfcp_transport_functions = { .show_host_port_state = 1, .show_host_active_fc4s = 1, .bsg_request = zfcp_fc_exec_bsg_job, + .bsg_timeout = zfcp_fc_timeout_bsg_job, /* no functions registered for following dynamic attributes but directly set by LLDD */ .show_host_port_type = 1, -- cgit v1.2.2 From 51375ee8374dd7fa574e1a14ebac406c6d28543b Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Thu, 14 Jan 2010 17:19:02 +0100 Subject: [SCSI] zfcp: Set hardware timeout as requested by BSG request. The hardware used with zfcp provides a timer for CT and ELS requests instead of an abort capability for these commands. To correctly handle the FC BSG timeouts, pass the timeout from the BSG requests to the hardware. Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_ext.h | 4 ++-- drivers/s390/scsi/zfcp_fc.c | 13 ++++++++----- drivers/s390/scsi/zfcp_fc.h | 2 ++ drivers/s390/scsi/zfcp_fsf.c | 19 ++++++++++--------- 4 files changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers/s390/scsi') diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 1406a65a6205..66bdb34143cb 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -130,9 +130,9 @@ extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); extern int zfcp_fsf_status_read(struct zfcp_qdio *); extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); extern int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *, struct zfcp_fsf_ct_els *, - mempool_t *); + mempool_t *, unsigned int); extern int zfcp_fsf_send_els(struct zfcp_adapter *, u32, - struct zfcp_fsf_ct_els *); + struct zfcp_fsf_ct_els *, unsigned int); extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *, struct scsi_cmnd *); extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 37a0ca200a32..0f7b493fb105 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -258,7 +258,8 @@ static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port, gid_pn->gid_pn_req.gid_pn.fn_wwpn = port->wwpn; ret = zfcp_fsf_send_ct(&adapter->gs->ds, &gid_pn->ct, - adapter->pool.gid_pn_req); + adapter->pool.gid_pn_req, + ZFCP_FC_CTELS_TMO); if (!ret) { wait_for_completion(&completion); zfcp_fc_ns_gid_pn_eval(gid_pn); @@ -421,7 +422,8 @@ static int zfcp_fc_adisc(struct zfcp_port *port) hton24(adisc->adisc_req.adisc_port_id, fc_host_port_id(adapter->scsi_host)); - ret = zfcp_fsf_send_els(adapter, port->d_id, &adisc->els); + ret = zfcp_fsf_send_els(adapter, port->d_id, &adisc->els, + ZFCP_FC_CTELS_TMO); if (ret) kmem_cache_free(zfcp_data.adisc_cache, adisc); @@ -532,7 +534,8 @@ static int zfcp_fc_send_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft, ct->req = &gpn_ft->sg_req; ct->resp = gpn_ft->sg_resp; - ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct, NULL); + ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct, NULL, + ZFCP_FC_CTELS_TMO); if (!ret) wait_for_completion(&completion); return ret; @@ -734,7 +737,7 @@ static int zfcp_fc_exec_els_job(struct fc_bsg_job *job, d_id = ntoh24(job->request->rqst_data.h_els.port_id); els->handler = zfcp_fc_ct_els_job_handler; - return zfcp_fsf_send_els(adapter, d_id, els); + return zfcp_fsf_send_els(adapter, d_id, els, job->req->timeout / HZ); } static int zfcp_fc_exec_ct_job(struct fc_bsg_job *job, @@ -753,7 +756,7 @@ static int zfcp_fc_exec_ct_job(struct fc_bsg_job *job, return ret; ct->handler = zfcp_fc_ct_job_handler; - ret = zfcp_fsf_send_ct(wka_port, ct, NULL); + ret = zfcp_fsf_send_ct(wka_port, ct, NULL, job->req->timeout / HZ); if (ret) zfcp_fc_wka_port_put(wka_port); diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index cb2a3669a384..0747b087390d 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h @@ -27,6 +27,8 @@ #define ZFCP_FC_GPN_FT_MAX_ENT (ZFCP_FC_GPN_FT_NUM_BUFS * \ (ZFCP_FC_GPN_FT_ENT_PAGE + 1)) +#define ZFCP_FC_CTELS_TMO (2 * FC_DEF_R_A_TOV / 1000) + /** * struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request * @ct_hdr: FC GS common transport header diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 482dcd97aa5d..e8fb4d9baa8b 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1068,20 +1068,20 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req, struct scatterlist *sg_req, struct scatterlist *sg_resp, - int max_sbals) + int max_sbals, unsigned int timeout) { int ret; - unsigned int fcp_chan_timeout; ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals); if (ret) return ret; /* common settings for ct/gs and els requests */ - fcp_chan_timeout = 2 * FC_DEF_R_A_TOV / 1000; + if (timeout > 255) + timeout = 255; /* max value accepted by hardware */ req->qtcb->bottom.support.service_class = FSF_CLASS_3; - req->qtcb->bottom.support.timeout = fcp_chan_timeout; - zfcp_fsf_start_timer(req, (fcp_chan_timeout + 10) * HZ); + req->qtcb->bottom.support.timeout = timeout; + zfcp_fsf_start_timer(req, (timeout + 10) * HZ); return 0; } @@ -1092,7 +1092,8 @@ static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req, * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req */ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, - struct zfcp_fsf_ct_els *ct, mempool_t *pool) + struct zfcp_fsf_ct_els *ct, mempool_t *pool, + unsigned int timeout) { struct zfcp_qdio *qdio = wka_port->adapter->qdio; struct zfcp_fsf_req *req; @@ -1111,7 +1112,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, - FSF_MAX_SBALS_PER_REQ); + FSF_MAX_SBALS_PER_REQ, timeout); if (ret) goto failed_send; @@ -1188,7 +1189,7 @@ skip_fsfstatus: * @els: pointer to struct zfcp_send_els with data for the command */ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, - struct zfcp_fsf_ct_els *els) + struct zfcp_fsf_ct_els *els, unsigned int timeout) { struct zfcp_fsf_req *req; struct zfcp_qdio *qdio = adapter->qdio; @@ -1206,7 +1207,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2); + ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2, timeout); if (ret) goto failed_send; -- cgit v1.2.2 From 7dec9cf1dfa283feca4b761160112ea4838a6a8c Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 26 Jan 2010 17:49:19 +0100 Subject: [SCSI] zfcp: Report FC BSG errors in correct field The status FC_CTELS_STATUS_REJECT for all FC BSG errors is not appropriate. Instead, report -EIO in the result field if there was a problem in zfcp with the FC BSG request. If the request is good from our point of view, report result 0, status FC_CTELS_STATUS_OK and let userspace read the Accept or Reject from the payload (as documented in scsi_bsg_fc.h). Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/s390/scsi') diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 0f7b493fb105..271399f62f1b 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -671,12 +671,11 @@ static void zfcp_fc_ct_els_job_handler(void *data) { struct fc_bsg_job *job = data; struct zfcp_fsf_ct_els *zfcp_ct_els = job->dd_data; - int status = zfcp_ct_els->status; - int reply_status; + struct fc_bsg_reply *jr = job->reply; - reply_status = status ? FC_CTELS_STATUS_REJECT : FC_CTELS_STATUS_OK; - job->reply->reply_data.ctels_reply.status = reply_status; - job->reply->reply_payload_rcv_len = job->reply_payload.payload_len; + jr->reply_payload_rcv_len = job->reply_payload.payload_len; + jr->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; + jr->result = zfcp_ct_els->status ? -EIO : 0; job->job_done(job); } -- cgit v1.2.2