aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/scsi/zfcp_fc.c
diff options
context:
space:
mode:
authorSwen Schillig <swen@vnet.ibm.com>2008-06-10 12:21:00 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-07-12 09:22:26 -0400
commitcc8c282963bd258a5bf49d3aa52675a4ae6d31f6 (patch)
treed0f353c918158b203c71603d9afdf4b71c126f63 /drivers/s390/scsi/zfcp_fc.c
parent85a82392fe6fe7620d8fe0eb694f926cefe62e1f (diff)
[SCSI] zfcp: Automatically attach remote ports
Automatically attach the remote ports in zfcp when the adapter is set online. This is done by querying all available ports from the FC namesever. The scan for remote ports is also triggered by RSCNs and can be triggered manually with the sysfs attribute 'port_rescan'. Signed-off-by: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/s390/scsi/zfcp_fc.c')
-rw-r--r--drivers/s390/scsi/zfcp_fc.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index bb07c3bf2258..aa2d9a668d17 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -8,6 +8,37 @@
8 8
9#include "zfcp_ext.h" 9#include "zfcp_ext.h"
10 10
11struct ct_iu_gpn_ft_req {
12 struct ct_hdr header;
13 u8 flags;
14 u8 domain_id_scope;
15 u8 area_id_scope;
16 u8 fc4_type;
17} __attribute__ ((packed));
18
19struct gpn_ft_resp_acc {
20 u8 control;
21 u8 port_id[3];
22 u8 reserved[4];
23 u64 wwpn;
24} __attribute__ ((packed));
25
26#define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \
27 / sizeof(struct gpn_ft_resp_acc))
28#define ZFCP_GPN_FT_BUFFERS 4
29#define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1)
30
31struct ct_iu_gpn_ft_resp {
32 struct ct_hdr header;
33 struct gpn_ft_resp_acc accept[ZFCP_GPN_FT_ENTRIES];
34} __attribute__ ((packed));
35
36struct zfcp_gpn_ft {
37 struct zfcp_send_ct ct;
38 struct scatterlist sg_req;
39 struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS];
40};
41
11static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, 42static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
12 struct fcp_rscn_element *elem) 43 struct fcp_rscn_element *elem)
13{ 44{
@@ -68,6 +99,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
68 } 99 }
69 _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); 100 _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element);
70 } 101 }
102 schedule_work(&fsf_req->adapter->scan_work);
71} 103}
72 104
73static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn) 105static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn)
@@ -303,3 +335,219 @@ void zfcp_test_link(struct zfcp_port *port)
303 zfcp_port_put(port); 335 zfcp_port_put(port);
304 zfcp_erp_port_forced_reopen(port, 0, 65, NULL); 336 zfcp_erp_port_forced_reopen(port, 0, 65, NULL);
305} 337}
338
339static int zfcp_scan_get_nameserver(struct zfcp_adapter *adapter)
340{
341 int ret;
342
343 if (!adapter->nameserver_port)
344 return -EINTR;
345
346 if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
347 &adapter->nameserver_port->status)) {
348 ret = zfcp_erp_port_reopen(adapter->nameserver_port, 0, 148,
349 NULL);
350 if (ret)
351 return ret;
352 zfcp_erp_wait(adapter);
353 zfcp_port_put(adapter->nameserver_port);
354 }
355 return !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
356 &adapter->nameserver_port->status);
357}
358
359static void zfcp_gpn_ft_handler(unsigned long _done)
360{
361 complete((struct completion *)_done);
362}
363
364static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft)
365{
366 struct scatterlist *sg = &gpn_ft->sg_req;
367
368 kfree(sg_virt(sg)); /* free request buffer */
369 zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS);
370
371 kfree(gpn_ft);
372}
373
374static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void)
375{
376 struct zfcp_gpn_ft *gpn_ft;
377 struct ct_iu_gpn_ft_req *req;
378
379 gpn_ft = kzalloc(sizeof(*gpn_ft), GFP_KERNEL);
380 if (!gpn_ft)
381 return NULL;
382
383 req = kzalloc(sizeof(struct ct_iu_gpn_ft_req), GFP_KERNEL);
384 if (!req) {
385 kfree(gpn_ft);
386 gpn_ft = NULL;
387 goto out;
388 }
389 sg_init_one(&gpn_ft->sg_req, req, sizeof(*req));
390
391 if (zfcp_sg_setup_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS)) {
392 zfcp_free_sg_env(gpn_ft);
393 gpn_ft = NULL;
394 }
395out:
396 return gpn_ft;
397}
398
399
400static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
401 struct zfcp_adapter *adapter)
402{
403 struct zfcp_send_ct *ct = &gpn_ft->ct;
404 struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req);
405 struct completion done;
406 int ret;
407
408 /* prepare CT IU for GPN_FT */
409 req->header.revision = ZFCP_CT_REVISION;
410 req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE;
411 req->header.gs_subtype = ZFCP_CT_NAME_SERVER;
412 req->header.options = ZFCP_CT_SYNCHRONOUS;
413 req->header.cmd_rsp_code = ZFCP_CT_GPN_FT;
414 req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) *
415 (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2;
416 req->flags = 0;
417 req->domain_id_scope = 0;
418 req->area_id_scope = 0;
419 req->fc4_type = ZFCP_CT_SCSI_FCP;
420
421 /* prepare zfcp_send_ct */
422 ct->port = adapter->nameserver_port;
423 ct->handler = zfcp_gpn_ft_handler;
424 ct->handler_data = (unsigned long)&done;
425 ct->timeout = 10;
426 ct->req = &gpn_ft->sg_req;
427 ct->resp = gpn_ft->sg_resp;
428 ct->req_count = 1;
429 ct->resp_count = ZFCP_GPN_FT_BUFFERS;
430
431 init_completion(&done);
432 ret = zfcp_fsf_send_ct(ct, NULL, NULL);
433 if (!ret)
434 wait_for_completion(&done);
435 return ret;
436}
437
438static void zfcp_validate_port(struct zfcp_port *port)
439{
440 struct zfcp_adapter *adapter = port->adapter;
441
442 atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status);
443
444 if (port == adapter->nameserver_port)
445 return;
446 if ((port->supported_classes != 0) || (port->units != 0)) {
447 zfcp_port_put(port);
448 return;
449 }
450 zfcp_erp_port_shutdown(port, 0, 151, NULL);
451 zfcp_erp_wait(adapter);
452 zfcp_port_put(port);
453 zfcp_port_dequeue(port);
454}
455
456static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft)
457{
458 struct zfcp_send_ct *ct = &gpn_ft->ct;
459 struct scatterlist *sg = gpn_ft->sg_resp;
460 struct ct_hdr *hdr = sg_virt(sg);
461 struct gpn_ft_resp_acc *acc = sg_virt(sg);
462 struct zfcp_adapter *adapter = ct->port->adapter;
463 struct zfcp_port *port, *tmp;
464 u32 d_id;
465 int ret = 0, x;
466
467 if (ct->status)
468 return -EIO;
469
470 if (hdr->cmd_rsp_code != ZFCP_CT_ACCEPT) {
471 if (hdr->reason_code == ZFCP_CT_UNABLE_TO_PERFORM_CMD)
472 return -EAGAIN; /* might be a temporary condition */
473 return -EIO;
474 }
475
476 if (hdr->max_res_size)
477 return -E2BIG;
478
479 down(&zfcp_data.config_sema);
480
481 /* first entry is the header */
482 for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES; x++) {
483 if (x % (ZFCP_GPN_FT_ENTRIES + 1))
484 acc++;
485 else
486 acc = sg_virt(++sg);
487
488 d_id = acc->port_id[0] << 16 | acc->port_id[1] << 8 |
489 acc->port_id[2];
490
491 /* skip the adapter's port and known remote ports */
492 if (acc->wwpn == fc_host_port_name(adapter->scsi_host) ||
493 zfcp_get_port_by_did(adapter, d_id))
494 continue;
495
496 port = zfcp_port_enqueue(adapter, acc->wwpn,
497 ZFCP_STATUS_PORT_DID_DID |
498 ZFCP_STATUS_COMMON_NOESC, d_id);
499 if (port)
500 zfcp_erp_port_reopen(port, 0, 149, NULL);
501 else
502 ret = -ENOMEM;
503 if (acc->control & 0x80) /* last entry */
504 break;
505 }
506
507 zfcp_erp_wait(adapter);
508 list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list)
509 zfcp_validate_port(port);
510 up(&zfcp_data.config_sema);
511 return ret;
512}
513
514/**
515 * zfcp_scan_ports - scan remote ports and attach new ports
516 * @adapter: pointer to struct zfcp_adapter
517 */
518int zfcp_scan_ports(struct zfcp_adapter *adapter)
519{
520 int ret, i;
521 struct zfcp_gpn_ft *gpn_ft;
522
523 if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT)
524 return 0;
525
526 ret = zfcp_scan_get_nameserver(adapter);
527 if (ret)
528 return ret;
529
530 gpn_ft = zfcp_alloc_sg_env();
531 if (!gpn_ft)
532 return -ENOMEM;
533
534 for (i = 0; i < 3; i++) {
535 ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter);
536 if (!ret) {
537 ret = zfcp_scan_eval_gpn_ft(gpn_ft);
538 if (ret == -EAGAIN)
539 ssleep(1);
540 else
541 break;
542 }
543 }
544 zfcp_free_sg_env(gpn_ft);
545
546 return ret;
547}
548
549
550void _zfcp_scan_ports_later(struct work_struct *work)
551{
552 zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work));
553}