diff options
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.c | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 9 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 55 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 32 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.h | 2 |
6 files changed, 61 insertions, 40 deletions
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index bf691fbc4d29..150bd5390b1d 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -936,6 +936,7 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) rct->reason_code = hdr->reason_code; rct->expl = hdr->reason_code_expl; rct->vendor_unique = hdr->vendor_unique; + rct->max_res_size = hdr->max_res_size; rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr), ZFCP_DBF_SAN_MAX_PAYLOAD); debug_event(adapter->san_dbf, level, r, sizeof(*r)); @@ -1043,6 +1044,7 @@ static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code); zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl); zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique); + zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size); } else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 || strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 || strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) { diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 5d6b2dff855b..74998ff88e57 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -171,6 +171,7 @@ struct zfcp_san_dbf_record_ct_response { u8 reason_code; u8 expl; u8 vendor_unique; + u16 max_res_size; u32 len; } __attribute__ ((packed)); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index ce4094966236..510662783a6f 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -197,7 +197,6 @@ struct zfcp_ls_adisc { #define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09 #define ZFCP_CT_GID_PN 0x0121 #define ZFCP_CT_GPN_FT 0x0172 -#define ZFCP_CT_MAX_SIZE 0x1020 #define ZFCP_CT_ACCEPT 0x8002 #define ZFCP_CT_REJECT 0x8001 @@ -325,8 +324,6 @@ struct ct_iu_gid_pn_resp { * @wka_port: port where the request is sent to * @req: scatter-gather list for request * @resp: scatter-gather list for response - * @req_count: number of elements in request scatter-gather list - * @resp_count: number of elements in response scatter-gather list * @handler: handler function (called for response to the request) * @handler_data: data passed to handler function * @timeout: FSF timeout for this request @@ -337,8 +334,6 @@ struct zfcp_send_ct { struct zfcp_wka_port *wka_port; struct scatterlist *req; struct scatterlist *resp; - unsigned int req_count; - unsigned int resp_count; void (*handler)(unsigned long); unsigned long handler_data; int timeout; @@ -363,8 +358,6 @@ struct zfcp_gid_pn_data { * @d_id: destiniation id of port where request is sent to * @req: scatter-gather list for request * @resp: scatter-gather list for response - * @req_count: number of elements in request scatter-gather list - * @resp_count: number of elements in response scatter-gather list * @handler: handler function (called for response to the request) * @handler_data: data passed to handler function * @completion: completion for synchronization purposes @@ -377,8 +370,6 @@ struct zfcp_send_els { u32 d_id; struct scatterlist *req; struct scatterlist *resp; - unsigned int req_count; - unsigned int resp_count; void (*handler)(unsigned long); unsigned long handler_data; struct completion *completion; diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 217c3b04fd01..eabdfe24456e 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -40,9 +40,12 @@ struct gpn_ft_resp_acc { u64 wwpn; } __attribute__ ((packed)); -#define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \ - / sizeof(struct gpn_ft_resp_acc)) +#define ZFCP_CT_SIZE_ONE_PAGE (PAGE_SIZE - sizeof(struct ct_hdr)) +#define ZFCP_GPN_FT_ENTRIES (ZFCP_CT_SIZE_ONE_PAGE \ + / sizeof(struct gpn_ft_resp_acc)) #define ZFCP_GPN_FT_BUFFERS 4 +#define ZFCP_GPN_FT_MAX_SIZE (ZFCP_GPN_FT_BUFFERS * PAGE_SIZE \ + - sizeof(struct ct_hdr)) #define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1) struct ct_iu_gpn_ft_resp { @@ -282,8 +285,6 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; gid_pn->ct.req = &gid_pn->req; gid_pn->ct.resp = &gid_pn->resp; - gid_pn->ct.req_count = 1; - gid_pn->ct.resp_count = 1; sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, sizeof(struct ct_iu_gid_pn_req)); sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp, @@ -295,7 +296,7 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER; gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; - gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE; + gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_SIZE_ONE_PAGE / 4; gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; init_completion(&compl_rec.done); @@ -405,8 +406,6 @@ static int zfcp_fc_adisc(struct zfcp_port *port) sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, sizeof(struct zfcp_ls_adisc)); - adisc->els.req_count = 1; - adisc->els.resp_count = 1; adisc->els.adapter = adapter; adisc->els.port = port; adisc->els.d_id = port->d_id; @@ -446,17 +445,17 @@ void zfcp_test_link(struct zfcp_port *port) zfcp_erp_port_forced_reopen(port, 0, 65, NULL); } -static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft) +static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) { struct scatterlist *sg = &gpn_ft->sg_req; kfree(sg_virt(sg)); /* free request buffer */ - zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS); + zfcp_sg_free_table(gpn_ft->sg_resp, buf_num); kfree(gpn_ft); } -static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) +static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num) { struct zfcp_gpn_ft *gpn_ft; struct ct_iu_gpn_ft_req *req; @@ -473,8 +472,8 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) } sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); - if (zfcp_sg_setup_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS)) { - zfcp_free_sg_env(gpn_ft); + if (zfcp_sg_setup_table(gpn_ft->sg_resp, buf_num)) { + zfcp_free_sg_env(gpn_ft, buf_num); gpn_ft = NULL; } out: @@ -483,7 +482,8 @@ out: static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, - struct zfcp_adapter *adapter) + struct zfcp_adapter *adapter, + int max_bytes) { struct zfcp_send_ct *ct = &gpn_ft->ct; struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); @@ -496,8 +496,7 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, req->header.gs_subtype = ZFCP_CT_NAME_SERVER; req->header.options = ZFCP_CT_SYNCHRONOUS; req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; - req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) * - (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2; + req->header.max_res_size = max_bytes / 4; req->flags = 0; req->domain_id_scope = 0; req->area_id_scope = 0; @@ -510,8 +509,6 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, ct->timeout = 10; ct->req = &gpn_ft->sg_req; ct->resp = gpn_ft->sg_resp; - ct->req_count = 1; - ct->resp_count = ZFCP_GPN_FT_BUFFERS; init_completion(&compl_rec.done); compl_rec.handler = NULL; @@ -538,7 +535,7 @@ static void zfcp_validate_port(struct zfcp_port *port) zfcp_port_dequeue(port); } -static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) +static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) { struct zfcp_send_ct *ct = &gpn_ft->ct; struct scatterlist *sg = gpn_ft->sg_resp; @@ -558,13 +555,17 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) return -EIO; } - if (hdr->max_res_size) + if (hdr->max_res_size) { + dev_warn(&adapter->ccw_device->dev, + "The name server reported %d words residual data\n", + hdr->max_res_size); return -E2BIG; + } down(&zfcp_data.config_sema); /* first entry is the header */ - for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES && !last; x++) { + for (x = 1; x < max_entries && !last; x++) { if (x % (ZFCP_GPN_FT_ENTRIES + 1)) acc++; else @@ -609,6 +610,12 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) { int ret, i; struct zfcp_gpn_ft *gpn_ft; + int chain, max_entries, buf_num, max_bytes; + + chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS; + buf_num = chain ? ZFCP_GPN_FT_BUFFERS : 1; + max_entries = chain ? ZFCP_GPN_FT_MAX_ENTRIES : ZFCP_GPN_FT_ENTRIES; + max_bytes = chain ? ZFCP_GPN_FT_MAX_SIZE : ZFCP_CT_SIZE_ONE_PAGE; if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) return 0; @@ -617,23 +624,23 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) if (ret) return ret; - gpn_ft = zfcp_alloc_sg_env(); + gpn_ft = zfcp_alloc_sg_env(buf_num); if (!gpn_ft) { ret = -ENOMEM; goto out; } for (i = 0; i < 3; i++) { - ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter); + ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter, max_bytes); if (!ret) { - ret = zfcp_scan_eval_gpn_ft(gpn_ft); + ret = zfcp_scan_eval_gpn_ft(gpn_ft, max_entries); if (ret == -EAGAIN) ssleep(1); else break; } } - zfcp_free_sg_env(gpn_ft); + zfcp_free_sg_env(gpn_ft, buf_num); out: zfcp_wka_port_put(&adapter->nsp); return ret; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 17620ecda335..9bba56b16831 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1013,12 +1013,29 @@ skip_fsfstatus: send_ct->handler(send_ct->handler_data); } -static int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req, - struct scatterlist *sg_req, - struct scatterlist *sg_resp, int max_sbals) +static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, + struct scatterlist *sg_req, + struct scatterlist *sg_resp, + int max_sbals) { + struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(req); + u32 feat = req->adapter->adapter_features; int bytes; + if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { + if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE || + !sg_is_last(sg_req) || !sg_is_last(sg_resp)) + return -EOPNOTSUPP; + + sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; + sbale[2].addr = sg_virt(sg_req); + sbale[2].length = sg_req->length; + sbale[3].addr = sg_virt(sg_resp); + sbale[3].length = sg_resp->length; + sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; + return 0; + } + bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, sg_req, max_sbals); if (bytes <= 0) @@ -1060,8 +1077,8 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, goto out; } - ret = zfcp_fsf_setup_sbals(req, ct->req, ct->resp, - FSF_MAX_SBALS_PER_REQ); + ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp, + FSF_MAX_SBALS_PER_REQ); if (ret) goto failed_send; @@ -1171,7 +1188,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) goto out; } - ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, 2); + ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2); if (ret) goto failed_send; @@ -1440,7 +1457,8 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) * Alternately, an ADISC/PDISC ELS should suffice, as well. */ plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els; - if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) { + if (req->qtcb->bottom.support.els1_length >= + FSF_PLOGI_MIN_LEN) { if (plogi->serv_param.wwpn != port->wwpn) port->d_id = 0; else { diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index fa2a31780611..8bb200252347 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -164,6 +164,7 @@ #define FSF_FEATURE_LUN_SHARING 0x00000004 #define FSF_FEATURE_NOTIFICATION_LOST 0x00000008 #define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010 +#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 #define FSF_FEATURE_UPDATE_ALERT 0x00000100 #define FSF_FEATURE_MEASUREMENT_DATA 0x00000200 @@ -322,6 +323,7 @@ struct fsf_nport_serv_param { u8 vendor_version_level[16]; } __attribute__ ((packed)); +#define FSF_PLOGI_MIN_LEN 112 struct fsf_plogi { u32 code; struct fsf_nport_serv_param serv_param; |