diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_fc.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 88 |
1 files changed, 46 insertions, 42 deletions
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index f009f2a7ec3e..eabdfe24456e 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -11,6 +11,20 @@ | |||
11 | 11 | ||
12 | #include "zfcp_ext.h" | 12 | #include "zfcp_ext.h" |
13 | 13 | ||
14 | enum rscn_address_format { | ||
15 | RSCN_PORT_ADDRESS = 0x0, | ||
16 | RSCN_AREA_ADDRESS = 0x1, | ||
17 | RSCN_DOMAIN_ADDRESS = 0x2, | ||
18 | RSCN_FABRIC_ADDRESS = 0x3, | ||
19 | }; | ||
20 | |||
21 | static u32 rscn_range_mask[] = { | ||
22 | [RSCN_PORT_ADDRESS] = 0xFFFFFF, | ||
23 | [RSCN_AREA_ADDRESS] = 0xFFFF00, | ||
24 | [RSCN_DOMAIN_ADDRESS] = 0xFF0000, | ||
25 | [RSCN_FABRIC_ADDRESS] = 0x000000, | ||
26 | }; | ||
27 | |||
14 | struct ct_iu_gpn_ft_req { | 28 | struct ct_iu_gpn_ft_req { |
15 | struct ct_hdr header; | 29 | struct ct_hdr header; |
16 | u8 flags; | 30 | u8 flags; |
@@ -26,9 +40,12 @@ struct gpn_ft_resp_acc { | |||
26 | u64 wwpn; | 40 | u64 wwpn; |
27 | } __attribute__ ((packed)); | 41 | } __attribute__ ((packed)); |
28 | 42 | ||
29 | #define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \ | 43 | #define ZFCP_CT_SIZE_ONE_PAGE (PAGE_SIZE - sizeof(struct ct_hdr)) |
30 | / sizeof(struct gpn_ft_resp_acc)) | 44 | #define ZFCP_GPN_FT_ENTRIES (ZFCP_CT_SIZE_ONE_PAGE \ |
45 | / sizeof(struct gpn_ft_resp_acc)) | ||
31 | #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)) | ||
32 | #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) |
33 | 50 | ||
34 | struct ct_iu_gpn_ft_resp { | 51 | struct ct_iu_gpn_ft_resp { |
@@ -160,22 +177,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) | |||
160 | for (i = 1; i < no_entries; i++) { | 177 | for (i = 1; i < no_entries; i++) { |
161 | /* skip head and start with 1st element */ | 178 | /* skip head and start with 1st element */ |
162 | fcp_rscn_element++; | 179 | fcp_rscn_element++; |
163 | switch (fcp_rscn_element->addr_format) { | 180 | range_mask = rscn_range_mask[fcp_rscn_element->addr_format]; |
164 | case ZFCP_PORT_ADDRESS: | ||
165 | range_mask = ZFCP_PORTS_RANGE_PORT; | ||
166 | break; | ||
167 | case ZFCP_AREA_ADDRESS: | ||
168 | range_mask = ZFCP_PORTS_RANGE_AREA; | ||
169 | break; | ||
170 | case ZFCP_DOMAIN_ADDRESS: | ||
171 | range_mask = ZFCP_PORTS_RANGE_DOMAIN; | ||
172 | break; | ||
173 | case ZFCP_FABRIC_ADDRESS: | ||
174 | range_mask = ZFCP_PORTS_RANGE_FABRIC; | ||
175 | break; | ||
176 | default: | ||
177 | continue; | ||
178 | } | ||
179 | _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); | 181 | _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); |
180 | } | 182 | } |
181 | schedule_work(&fsf_req->adapter->scan_work); | 183 | schedule_work(&fsf_req->adapter->scan_work); |
@@ -266,7 +268,6 @@ static void zfcp_fc_ns_gid_pn_eval(unsigned long data) | |||
266 | return; | 268 | return; |
267 | /* looks like a valid d_id */ | 269 | /* looks like a valid d_id */ |
268 | port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; | 270 | port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; |
269 | atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); | ||
270 | } | 271 | } |
271 | 272 | ||
272 | int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, | 273 | int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, |
@@ -284,8 +285,6 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, | |||
284 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; | 285 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; |
285 | gid_pn->ct.req = &gid_pn->req; | 286 | gid_pn->ct.req = &gid_pn->req; |
286 | gid_pn->ct.resp = &gid_pn->resp; | 287 | gid_pn->ct.resp = &gid_pn->resp; |
287 | gid_pn->ct.req_count = 1; | ||
288 | gid_pn->ct.resp_count = 1; | ||
289 | sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, | 288 | sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, |
290 | sizeof(struct ct_iu_gid_pn_req)); | 289 | sizeof(struct ct_iu_gid_pn_req)); |
291 | sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp, | 290 | sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp, |
@@ -297,7 +296,7 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, | |||
297 | 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; |
298 | gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; | 297 | gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; |
299 | 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; |
300 | 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; |
301 | gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; | 300 | gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; |
302 | 301 | ||
303 | init_completion(&compl_rec.done); | 302 | init_completion(&compl_rec.done); |
@@ -407,8 +406,6 @@ static int zfcp_fc_adisc(struct zfcp_port *port) | |||
407 | sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, | 406 | sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, |
408 | sizeof(struct zfcp_ls_adisc)); | 407 | sizeof(struct zfcp_ls_adisc)); |
409 | 408 | ||
410 | adisc->els.req_count = 1; | ||
411 | adisc->els.resp_count = 1; | ||
412 | adisc->els.adapter = adapter; | 409 | adisc->els.adapter = adapter; |
413 | adisc->els.port = port; | 410 | adisc->els.port = port; |
414 | adisc->els.d_id = port->d_id; | 411 | adisc->els.d_id = port->d_id; |
@@ -448,17 +445,17 @@ void zfcp_test_link(struct zfcp_port *port) | |||
448 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); | 445 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); |
449 | } | 446 | } |
450 | 447 | ||
451 | 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) |
452 | { | 449 | { |
453 | struct scatterlist *sg = &gpn_ft->sg_req; | 450 | struct scatterlist *sg = &gpn_ft->sg_req; |
454 | 451 | ||
455 | kfree(sg_virt(sg)); /* free request buffer */ | 452 | kfree(sg_virt(sg)); /* free request buffer */ |
456 | zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS); | 453 | zfcp_sg_free_table(gpn_ft->sg_resp, buf_num); |
457 | 454 | ||
458 | kfree(gpn_ft); | 455 | kfree(gpn_ft); |
459 | } | 456 | } |
460 | 457 | ||
461 | static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) | 458 | static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num) |
462 | { | 459 | { |
463 | struct zfcp_gpn_ft *gpn_ft; | 460 | struct zfcp_gpn_ft *gpn_ft; |
464 | struct ct_iu_gpn_ft_req *req; | 461 | struct ct_iu_gpn_ft_req *req; |
@@ -475,8 +472,8 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) | |||
475 | } | 472 | } |
476 | sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); | 473 | sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); |
477 | 474 | ||
478 | 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)) { |
479 | zfcp_free_sg_env(gpn_ft); | 476 | zfcp_free_sg_env(gpn_ft, buf_num); |
480 | gpn_ft = NULL; | 477 | gpn_ft = NULL; |
481 | } | 478 | } |
482 | out: | 479 | out: |
@@ -485,7 +482,8 @@ out: | |||
485 | 482 | ||
486 | 483 | ||
487 | 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, |
488 | struct zfcp_adapter *adapter) | 485 | struct zfcp_adapter *adapter, |
486 | int max_bytes) | ||
489 | { | 487 | { |
490 | struct zfcp_send_ct *ct = &gpn_ft->ct; | 488 | struct zfcp_send_ct *ct = &gpn_ft->ct; |
491 | 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); |
@@ -498,8 +496,7 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, | |||
498 | req->header.gs_subtype = ZFCP_CT_NAME_SERVER; | 496 | req->header.gs_subtype = ZFCP_CT_NAME_SERVER; |
499 | req->header.options = ZFCP_CT_SYNCHRONOUS; | 497 | req->header.options = ZFCP_CT_SYNCHRONOUS; |
500 | req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; | 498 | req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; |
501 | req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) * | 499 | req->header.max_res_size = max_bytes / 4; |
502 | (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2; | ||
503 | req->flags = 0; | 500 | req->flags = 0; |
504 | req->domain_id_scope = 0; | 501 | req->domain_id_scope = 0; |
505 | req->area_id_scope = 0; | 502 | req->area_id_scope = 0; |
@@ -512,8 +509,6 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, | |||
512 | ct->timeout = 10; | 509 | ct->timeout = 10; |
513 | ct->req = &gpn_ft->sg_req; | 510 | ct->req = &gpn_ft->sg_req; |
514 | ct->resp = gpn_ft->sg_resp; | 511 | ct->resp = gpn_ft->sg_resp; |
515 | ct->req_count = 1; | ||
516 | ct->resp_count = ZFCP_GPN_FT_BUFFERS; | ||
517 | 512 | ||
518 | init_completion(&compl_rec.done); | 513 | init_completion(&compl_rec.done); |
519 | compl_rec.handler = NULL; | 514 | compl_rec.handler = NULL; |
@@ -540,7 +535,7 @@ static void zfcp_validate_port(struct zfcp_port *port) | |||
540 | zfcp_port_dequeue(port); | 535 | zfcp_port_dequeue(port); |
541 | } | 536 | } |
542 | 537 | ||
543 | 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) |
544 | { | 539 | { |
545 | struct zfcp_send_ct *ct = &gpn_ft->ct; | 540 | struct zfcp_send_ct *ct = &gpn_ft->ct; |
546 | struct scatterlist *sg = gpn_ft->sg_resp; | 541 | struct scatterlist *sg = gpn_ft->sg_resp; |
@@ -560,13 +555,17 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) | |||
560 | return -EIO; | 555 | return -EIO; |
561 | } | 556 | } |
562 | 557 | ||
563 | 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); | ||
564 | return -E2BIG; | 562 | return -E2BIG; |
563 | } | ||
565 | 564 | ||
566 | down(&zfcp_data.config_sema); | 565 | down(&zfcp_data.config_sema); |
567 | 566 | ||
568 | /* first entry is the header */ | 567 | /* first entry is the header */ |
569 | for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES && !last; x++) { | 568 | for (x = 1; x < max_entries && !last; x++) { |
570 | if (x % (ZFCP_GPN_FT_ENTRIES + 1)) | 569 | if (x % (ZFCP_GPN_FT_ENTRIES + 1)) |
571 | acc++; | 570 | acc++; |
572 | else | 571 | else |
@@ -589,7 +588,6 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) | |||
589 | } | 588 | } |
590 | 589 | ||
591 | port = zfcp_port_enqueue(adapter, acc->wwpn, | 590 | port = zfcp_port_enqueue(adapter, acc->wwpn, |
592 | ZFCP_STATUS_PORT_DID_DID | | ||
593 | ZFCP_STATUS_COMMON_NOESC, d_id); | 591 | ZFCP_STATUS_COMMON_NOESC, d_id); |
594 | if (IS_ERR(port)) | 592 | if (IS_ERR(port)) |
595 | ret = PTR_ERR(port); | 593 | ret = PTR_ERR(port); |
@@ -612,6 +610,12 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) | |||
612 | { | 610 | { |
613 | int ret, i; | 611 | int ret, i; |
614 | 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; | ||
615 | 619 | ||
616 | if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) | 620 | if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) |
617 | return 0; | 621 | return 0; |
@@ -620,23 +624,23 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) | |||
620 | if (ret) | 624 | if (ret) |
621 | return ret; | 625 | return ret; |
622 | 626 | ||
623 | gpn_ft = zfcp_alloc_sg_env(); | 627 | gpn_ft = zfcp_alloc_sg_env(buf_num); |
624 | if (!gpn_ft) { | 628 | if (!gpn_ft) { |
625 | ret = -ENOMEM; | 629 | ret = -ENOMEM; |
626 | goto out; | 630 | goto out; |
627 | } | 631 | } |
628 | 632 | ||
629 | for (i = 0; i < 3; i++) { | 633 | for (i = 0; i < 3; i++) { |
630 | ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter); | 634 | ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter, max_bytes); |
631 | if (!ret) { | 635 | if (!ret) { |
632 | ret = zfcp_scan_eval_gpn_ft(gpn_ft); | 636 | ret = zfcp_scan_eval_gpn_ft(gpn_ft, max_entries); |
633 | if (ret == -EAGAIN) | 637 | if (ret == -EAGAIN) |
634 | ssleep(1); | 638 | ssleep(1); |
635 | else | 639 | else |
636 | break; | 640 | break; |
637 | } | 641 | } |
638 | } | 642 | } |
639 | zfcp_free_sg_env(gpn_ft); | 643 | zfcp_free_sg_env(gpn_ft, buf_num); |
640 | out: | 644 | out: |
641 | zfcp_wka_port_put(&adapter->nsp); | 645 | zfcp_wka_port_put(&adapter->nsp); |
642 | return ret; | 646 | return ret; |