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) | |||
| 936 | rct->reason_code = hdr->reason_code; | 936 | rct->reason_code = hdr->reason_code; |
| 937 | rct->expl = hdr->reason_code_expl; | 937 | rct->expl = hdr->reason_code_expl; |
| 938 | rct->vendor_unique = hdr->vendor_unique; | 938 | rct->vendor_unique = hdr->vendor_unique; |
| 939 | rct->max_res_size = hdr->max_res_size; | ||
| 939 | rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr), | 940 | rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr), |
| 940 | ZFCP_DBF_SAN_MAX_PAYLOAD); | 941 | ZFCP_DBF_SAN_MAX_PAYLOAD); |
| 941 | debug_event(adapter->san_dbf, level, r, sizeof(*r)); | 942 | 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, | |||
| 1043 | zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code); | 1044 | zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code); |
| 1044 | zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl); | 1045 | zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl); |
| 1045 | zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique); | 1046 | zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique); |
| 1047 | zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size); | ||
| 1046 | } else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 || | 1048 | } else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 || |
| 1047 | strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 || | 1049 | strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 || |
| 1048 | strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) { | 1050 | 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 { | |||
| 171 | u8 reason_code; | 171 | u8 reason_code; |
| 172 | u8 expl; | 172 | u8 expl; |
| 173 | u8 vendor_unique; | 173 | u8 vendor_unique; |
| 174 | u16 max_res_size; | ||
| 174 | u32 len; | 175 | u32 len; |
| 175 | } __attribute__ ((packed)); | 176 | } __attribute__ ((packed)); |
| 176 | 177 | ||
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 { | |||
| 197 | #define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09 | 197 | #define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09 |
| 198 | #define ZFCP_CT_GID_PN 0x0121 | 198 | #define ZFCP_CT_GID_PN 0x0121 |
| 199 | #define ZFCP_CT_GPN_FT 0x0172 | 199 | #define ZFCP_CT_GPN_FT 0x0172 |
| 200 | #define ZFCP_CT_MAX_SIZE 0x1020 | ||
| 201 | #define ZFCP_CT_ACCEPT 0x8002 | 200 | #define ZFCP_CT_ACCEPT 0x8002 |
| 202 | #define ZFCP_CT_REJECT 0x8001 | 201 | #define ZFCP_CT_REJECT 0x8001 |
| 203 | 202 | ||
| @@ -325,8 +324,6 @@ struct ct_iu_gid_pn_resp { | |||
| 325 | * @wka_port: port where the request is sent to | 324 | * @wka_port: port where the request is sent to |
| 326 | * @req: scatter-gather list for request | 325 | * @req: scatter-gather list for request |
| 327 | * @resp: scatter-gather list for response | 326 | * @resp: scatter-gather list for response |
| 328 | * @req_count: number of elements in request scatter-gather list | ||
| 329 | * @resp_count: number of elements in response scatter-gather list | ||
| 330 | * @handler: handler function (called for response to the request) | 327 | * @handler: handler function (called for response to the request) |
| 331 | * @handler_data: data passed to handler function | 328 | * @handler_data: data passed to handler function |
| 332 | * @timeout: FSF timeout for this request | 329 | * @timeout: FSF timeout for this request |
| @@ -337,8 +334,6 @@ struct zfcp_send_ct { | |||
| 337 | struct zfcp_wka_port *wka_port; | 334 | struct zfcp_wka_port *wka_port; |
| 338 | struct scatterlist *req; | 335 | struct scatterlist *req; |
| 339 | struct scatterlist *resp; | 336 | struct scatterlist *resp; |
| 340 | unsigned int req_count; | ||
| 341 | unsigned int resp_count; | ||
| 342 | void (*handler)(unsigned long); | 337 | void (*handler)(unsigned long); |
| 343 | unsigned long handler_data; | 338 | unsigned long handler_data; |
| 344 | int timeout; | 339 | int timeout; |
| @@ -363,8 +358,6 @@ struct zfcp_gid_pn_data { | |||
| 363 | * @d_id: destiniation id of port where request is sent to | 358 | * @d_id: destiniation id of port where request is sent to |
| 364 | * @req: scatter-gather list for request | 359 | * @req: scatter-gather list for request |
| 365 | * @resp: scatter-gather list for response | 360 | * @resp: scatter-gather list for response |
| 366 | * @req_count: number of elements in request scatter-gather list | ||
| 367 | * @resp_count: number of elements in response scatter-gather list | ||
| 368 | * @handler: handler function (called for response to the request) | 361 | * @handler: handler function (called for response to the request) |
| 369 | * @handler_data: data passed to handler function | 362 | * @handler_data: data passed to handler function |
| 370 | * @completion: completion for synchronization purposes | 363 | * @completion: completion for synchronization purposes |
| @@ -377,8 +370,6 @@ struct zfcp_send_els { | |||
| 377 | u32 d_id; | 370 | u32 d_id; |
| 378 | struct scatterlist *req; | 371 | struct scatterlist *req; |
| 379 | struct scatterlist *resp; | 372 | struct scatterlist *resp; |
| 380 | unsigned int req_count; | ||
| 381 | unsigned int resp_count; | ||
| 382 | void (*handler)(unsigned long); | 373 | void (*handler)(unsigned long); |
| 383 | unsigned long handler_data; | 374 | unsigned long handler_data; |
| 384 | struct completion *completion; | 375 | 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 { | |||
| 40 | u64 wwpn; | 40 | u64 wwpn; |
| 41 | } __attribute__ ((packed)); | 41 | } __attribute__ ((packed)); |
| 42 | 42 | ||
| 43 | #define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \ | 43 | #define ZFCP_CT_SIZE_ONE_PAGE (PAGE_SIZE - sizeof(struct ct_hdr)) |
| 44 | / sizeof(struct gpn_ft_resp_acc)) | 44 | #define ZFCP_GPN_FT_ENTRIES (ZFCP_CT_SIZE_ONE_PAGE \ |
| 45 | / sizeof(struct gpn_ft_resp_acc)) | ||
| 45 | #define ZFCP_GPN_FT_BUFFERS 4 | 46 | #define ZFCP_GPN_FT_BUFFERS 4 |
| 47 | #define ZFCP_GPN_FT_MAX_SIZE (ZFCP_GPN_FT_BUFFERS * PAGE_SIZE \ | ||
| 48 | - sizeof(struct ct_hdr)) | ||
| 46 | #define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1) | 49 | #define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1) |
| 47 | 50 | ||
| 48 | struct ct_iu_gpn_ft_resp { | 51 | struct ct_iu_gpn_ft_resp { |
| @@ -282,8 +285,6 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, | |||
| 282 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; | 285 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; |
| 283 | gid_pn->ct.req = &gid_pn->req; | 286 | gid_pn->ct.req = &gid_pn->req; |
| 284 | gid_pn->ct.resp = &gid_pn->resp; | 287 | gid_pn->ct.resp = &gid_pn->resp; |
| 285 | gid_pn->ct.req_count = 1; | ||
| 286 | gid_pn->ct.resp_count = 1; | ||
| 287 | sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, | 288 | sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, |
| 288 | sizeof(struct ct_iu_gid_pn_req)); | 289 | sizeof(struct ct_iu_gid_pn_req)); |
| 289 | sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp, | 290 | 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, | |||
| 295 | gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER; | 296 | gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER; |
| 296 | gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; | 297 | gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; |
| 297 | gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; | 298 | gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; |
| 298 | gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE; | 299 | gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_SIZE_ONE_PAGE / 4; |
| 299 | gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; | 300 | gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; |
| 300 | 301 | ||
| 301 | init_completion(&compl_rec.done); | 302 | init_completion(&compl_rec.done); |
| @@ -405,8 +406,6 @@ static int zfcp_fc_adisc(struct zfcp_port *port) | |||
| 405 | sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, | 406 | sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, |
| 406 | sizeof(struct zfcp_ls_adisc)); | 407 | sizeof(struct zfcp_ls_adisc)); |
| 407 | 408 | ||
| 408 | adisc->els.req_count = 1; | ||
| 409 | adisc->els.resp_count = 1; | ||
| 410 | adisc->els.adapter = adapter; | 409 | adisc->els.adapter = adapter; |
| 411 | adisc->els.port = port; | 410 | adisc->els.port = port; |
| 412 | adisc->els.d_id = port->d_id; | 411 | adisc->els.d_id = port->d_id; |
| @@ -446,17 +445,17 @@ void zfcp_test_link(struct zfcp_port *port) | |||
| 446 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); | 445 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); |
| 447 | } | 446 | } |
| 448 | 447 | ||
| 449 | static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft) | 448 | static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) |
| 450 | { | 449 | { |
| 451 | struct scatterlist *sg = &gpn_ft->sg_req; | 450 | struct scatterlist *sg = &gpn_ft->sg_req; |
| 452 | 451 | ||
| 453 | kfree(sg_virt(sg)); /* free request buffer */ | 452 | kfree(sg_virt(sg)); /* free request buffer */ |
| 454 | zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS); | 453 | zfcp_sg_free_table(gpn_ft->sg_resp, buf_num); |
| 455 | 454 | ||
| 456 | kfree(gpn_ft); | 455 | kfree(gpn_ft); |
| 457 | } | 456 | } |
| 458 | 457 | ||
| 459 | static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) | 458 | static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num) |
| 460 | { | 459 | { |
| 461 | struct zfcp_gpn_ft *gpn_ft; | 460 | struct zfcp_gpn_ft *gpn_ft; |
| 462 | struct ct_iu_gpn_ft_req *req; | 461 | struct ct_iu_gpn_ft_req *req; |
| @@ -473,8 +472,8 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) | |||
| 473 | } | 472 | } |
| 474 | sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); | 473 | sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); |
| 475 | 474 | ||
| 476 | if (zfcp_sg_setup_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS)) { | 475 | if (zfcp_sg_setup_table(gpn_ft->sg_resp, buf_num)) { |
| 477 | zfcp_free_sg_env(gpn_ft); | 476 | zfcp_free_sg_env(gpn_ft, buf_num); |
| 478 | gpn_ft = NULL; | 477 | gpn_ft = NULL; |
| 479 | } | 478 | } |
| 480 | out: | 479 | out: |
| @@ -483,7 +482,8 @@ out: | |||
| 483 | 482 | ||
| 484 | 483 | ||
| 485 | static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, | 484 | static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, |
| 486 | struct zfcp_adapter *adapter) | 485 | struct zfcp_adapter *adapter, |
| 486 | int max_bytes) | ||
| 487 | { | 487 | { |
| 488 | struct zfcp_send_ct *ct = &gpn_ft->ct; | 488 | struct zfcp_send_ct *ct = &gpn_ft->ct; |
| 489 | struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); | 489 | 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, | |||
| 496 | req->header.gs_subtype = ZFCP_CT_NAME_SERVER; | 496 | req->header.gs_subtype = ZFCP_CT_NAME_SERVER; |
| 497 | req->header.options = ZFCP_CT_SYNCHRONOUS; | 497 | req->header.options = ZFCP_CT_SYNCHRONOUS; |
| 498 | req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; | 498 | req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; |
| 499 | req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) * | 499 | req->header.max_res_size = max_bytes / 4; |
| 500 | (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2; | ||
| 501 | req->flags = 0; | 500 | req->flags = 0; |
| 502 | req->domain_id_scope = 0; | 501 | req->domain_id_scope = 0; |
| 503 | req->area_id_scope = 0; | 502 | req->area_id_scope = 0; |
| @@ -510,8 +509,6 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, | |||
| 510 | ct->timeout = 10; | 509 | ct->timeout = 10; |
| 511 | ct->req = &gpn_ft->sg_req; | 510 | ct->req = &gpn_ft->sg_req; |
| 512 | ct->resp = gpn_ft->sg_resp; | 511 | ct->resp = gpn_ft->sg_resp; |
| 513 | ct->req_count = 1; | ||
| 514 | ct->resp_count = ZFCP_GPN_FT_BUFFERS; | ||
| 515 | 512 | ||
| 516 | init_completion(&compl_rec.done); | 513 | init_completion(&compl_rec.done); |
| 517 | compl_rec.handler = NULL; | 514 | compl_rec.handler = NULL; |
| @@ -538,7 +535,7 @@ static void zfcp_validate_port(struct zfcp_port *port) | |||
| 538 | zfcp_port_dequeue(port); | 535 | zfcp_port_dequeue(port); |
| 539 | } | 536 | } |
| 540 | 537 | ||
| 541 | static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) | 538 | static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) |
| 542 | { | 539 | { |
| 543 | struct zfcp_send_ct *ct = &gpn_ft->ct; | 540 | struct zfcp_send_ct *ct = &gpn_ft->ct; |
| 544 | struct scatterlist *sg = gpn_ft->sg_resp; | 541 | struct scatterlist *sg = gpn_ft->sg_resp; |
| @@ -558,13 +555,17 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) | |||
| 558 | return -EIO; | 555 | return -EIO; |
| 559 | } | 556 | } |
| 560 | 557 | ||
| 561 | if (hdr->max_res_size) | 558 | if (hdr->max_res_size) { |
| 559 | dev_warn(&adapter->ccw_device->dev, | ||
| 560 | "The name server reported %d words residual data\n", | ||
| 561 | hdr->max_res_size); | ||
| 562 | return -E2BIG; | 562 | return -E2BIG; |
| 563 | } | ||
| 563 | 564 | ||
| 564 | down(&zfcp_data.config_sema); | 565 | down(&zfcp_data.config_sema); |
| 565 | 566 | ||
| 566 | /* first entry is the header */ | 567 | /* first entry is the header */ |
| 567 | for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES && !last; x++) { | 568 | for (x = 1; x < max_entries && !last; x++) { |
| 568 | if (x % (ZFCP_GPN_FT_ENTRIES + 1)) | 569 | if (x % (ZFCP_GPN_FT_ENTRIES + 1)) |
| 569 | acc++; | 570 | acc++; |
| 570 | else | 571 | else |
| @@ -609,6 +610,12 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) | |||
| 609 | { | 610 | { |
| 610 | int ret, i; | 611 | int ret, i; |
| 611 | struct zfcp_gpn_ft *gpn_ft; | 612 | struct zfcp_gpn_ft *gpn_ft; |
| 613 | int chain, max_entries, buf_num, max_bytes; | ||
| 614 | |||
| 615 | chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS; | ||
| 616 | buf_num = chain ? ZFCP_GPN_FT_BUFFERS : 1; | ||
| 617 | max_entries = chain ? ZFCP_GPN_FT_MAX_ENTRIES : ZFCP_GPN_FT_ENTRIES; | ||
| 618 | max_bytes = chain ? ZFCP_GPN_FT_MAX_SIZE : ZFCP_CT_SIZE_ONE_PAGE; | ||
| 612 | 619 | ||
| 613 | if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) | 620 | if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) |
| 614 | return 0; | 621 | return 0; |
| @@ -617,23 +624,23 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) | |||
| 617 | if (ret) | 624 | if (ret) |
| 618 | return ret; | 625 | return ret; |
| 619 | 626 | ||
| 620 | gpn_ft = zfcp_alloc_sg_env(); | 627 | gpn_ft = zfcp_alloc_sg_env(buf_num); |
| 621 | if (!gpn_ft) { | 628 | if (!gpn_ft) { |
| 622 | ret = -ENOMEM; | 629 | ret = -ENOMEM; |
| 623 | goto out; | 630 | goto out; |
| 624 | } | 631 | } |
| 625 | 632 | ||
| 626 | for (i = 0; i < 3; i++) { | 633 | for (i = 0; i < 3; i++) { |
| 627 | ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter); | 634 | ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter, max_bytes); |
| 628 | if (!ret) { | 635 | if (!ret) { |
| 629 | ret = zfcp_scan_eval_gpn_ft(gpn_ft); | 636 | ret = zfcp_scan_eval_gpn_ft(gpn_ft, max_entries); |
| 630 | if (ret == -EAGAIN) | 637 | if (ret == -EAGAIN) |
| 631 | ssleep(1); | 638 | ssleep(1); |
| 632 | else | 639 | else |
| 633 | break; | 640 | break; |
| 634 | } | 641 | } |
| 635 | } | 642 | } |
| 636 | zfcp_free_sg_env(gpn_ft); | 643 | zfcp_free_sg_env(gpn_ft, buf_num); |
| 637 | out: | 644 | out: |
| 638 | zfcp_wka_port_put(&adapter->nsp); | 645 | zfcp_wka_port_put(&adapter->nsp); |
| 639 | return ret; | 646 | 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: | |||
| 1013 | send_ct->handler(send_ct->handler_data); | 1013 | send_ct->handler(send_ct->handler_data); |
| 1014 | } | 1014 | } |
| 1015 | 1015 | ||
| 1016 | static int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req, | 1016 | static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, |
| 1017 | struct scatterlist *sg_req, | 1017 | struct scatterlist *sg_req, |
| 1018 | struct scatterlist *sg_resp, int max_sbals) | 1018 | struct scatterlist *sg_resp, |
| 1019 | int max_sbals) | ||
| 1019 | { | 1020 | { |
| 1021 | struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(req); | ||
| 1022 | u32 feat = req->adapter->adapter_features; | ||
| 1020 | int bytes; | 1023 | int bytes; |
| 1021 | 1024 | ||
| 1025 | if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { | ||
| 1026 | if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE || | ||
| 1027 | !sg_is_last(sg_req) || !sg_is_last(sg_resp)) | ||
| 1028 | return -EOPNOTSUPP; | ||
| 1029 | |||
| 1030 | sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; | ||
| 1031 | sbale[2].addr = sg_virt(sg_req); | ||
| 1032 | sbale[2].length = sg_req->length; | ||
| 1033 | sbale[3].addr = sg_virt(sg_resp); | ||
| 1034 | sbale[3].length = sg_resp->length; | ||
| 1035 | sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
| 1036 | return 0; | ||
| 1037 | } | ||
| 1038 | |||
| 1022 | bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, | 1039 | bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, |
| 1023 | sg_req, max_sbals); | 1040 | sg_req, max_sbals); |
| 1024 | if (bytes <= 0) | 1041 | if (bytes <= 0) |
| @@ -1060,8 +1077,8 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, | |||
| 1060 | goto out; | 1077 | goto out; |
| 1061 | } | 1078 | } |
| 1062 | 1079 | ||
| 1063 | ret = zfcp_fsf_setup_sbals(req, ct->req, ct->resp, | 1080 | ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp, |
| 1064 | FSF_MAX_SBALS_PER_REQ); | 1081 | FSF_MAX_SBALS_PER_REQ); |
| 1065 | if (ret) | 1082 | if (ret) |
| 1066 | goto failed_send; | 1083 | goto failed_send; |
| 1067 | 1084 | ||
| @@ -1171,7 +1188,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) | |||
| 1171 | goto out; | 1188 | goto out; |
| 1172 | } | 1189 | } |
| 1173 | 1190 | ||
| 1174 | ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, 2); | 1191 | ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2); |
| 1175 | 1192 | ||
| 1176 | if (ret) | 1193 | if (ret) |
| 1177 | goto failed_send; | 1194 | goto failed_send; |
| @@ -1440,7 +1457,8 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) | |||
| 1440 | * Alternately, an ADISC/PDISC ELS should suffice, as well. | 1457 | * Alternately, an ADISC/PDISC ELS should suffice, as well. |
| 1441 | */ | 1458 | */ |
| 1442 | plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els; | 1459 | plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els; |
| 1443 | if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) { | 1460 | if (req->qtcb->bottom.support.els1_length >= |
| 1461 | FSF_PLOGI_MIN_LEN) { | ||
| 1444 | if (plogi->serv_param.wwpn != port->wwpn) | 1462 | if (plogi->serv_param.wwpn != port->wwpn) |
| 1445 | port->d_id = 0; | 1463 | port->d_id = 0; |
| 1446 | else { | 1464 | 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 @@ | |||
| 164 | #define FSF_FEATURE_LUN_SHARING 0x00000004 | 164 | #define FSF_FEATURE_LUN_SHARING 0x00000004 |
| 165 | #define FSF_FEATURE_NOTIFICATION_LOST 0x00000008 | 165 | #define FSF_FEATURE_NOTIFICATION_LOST 0x00000008 |
| 166 | #define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010 | 166 | #define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010 |
| 167 | #define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 | ||
| 167 | #define FSF_FEATURE_UPDATE_ALERT 0x00000100 | 168 | #define FSF_FEATURE_UPDATE_ALERT 0x00000100 |
| 168 | #define FSF_FEATURE_MEASUREMENT_DATA 0x00000200 | 169 | #define FSF_FEATURE_MEASUREMENT_DATA 0x00000200 |
| 169 | 170 | ||
| @@ -322,6 +323,7 @@ struct fsf_nport_serv_param { | |||
| 322 | u8 vendor_version_level[16]; | 323 | u8 vendor_version_level[16]; |
| 323 | } __attribute__ ((packed)); | 324 | } __attribute__ ((packed)); |
| 324 | 325 | ||
| 326 | #define FSF_PLOGI_MIN_LEN 112 | ||
| 325 | struct fsf_plogi { | 327 | struct fsf_plogi { |
| 326 | u32 code; | 328 | u32 code; |
| 327 | struct fsf_nport_serv_param serv_param; | 329 | struct fsf_nport_serv_param serv_param; |
