diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_fc.c')
-rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 370 |
1 files changed, 354 insertions, 16 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index b03aa85108e5..38c215a78f69 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
@@ -32,6 +32,9 @@ | |||
32 | #include <scsi/scsi_transport.h> | 32 | #include <scsi/scsi_transport.h> |
33 | #include <scsi/scsi_transport_fc.h> | 33 | #include <scsi/scsi_transport_fc.h> |
34 | #include <scsi/scsi_cmnd.h> | 34 | #include <scsi/scsi_cmnd.h> |
35 | #include <linux/netlink.h> | ||
36 | #include <net/netlink.h> | ||
37 | #include <scsi/scsi_netlink_fc.h> | ||
35 | #include "scsi_priv.h" | 38 | #include "scsi_priv.h" |
36 | 39 | ||
37 | static int fc_queue_work(struct Scsi_Host *, struct work_struct *); | 40 | static int fc_queue_work(struct Scsi_Host *, struct work_struct *); |
@@ -93,6 +96,29 @@ fc_enum_name_search(port_type, fc_port_type, fc_port_type_names) | |||
93 | #define FC_PORTTYPE_MAX_NAMELEN 50 | 96 | #define FC_PORTTYPE_MAX_NAMELEN 50 |
94 | 97 | ||
95 | 98 | ||
99 | /* Convert fc_host_event_code values to ascii string name */ | ||
100 | static const struct { | ||
101 | enum fc_host_event_code value; | ||
102 | char *name; | ||
103 | } fc_host_event_code_names[] = { | ||
104 | { FCH_EVT_LIP, "lip" }, | ||
105 | { FCH_EVT_LINKUP, "link_up" }, | ||
106 | { FCH_EVT_LINKDOWN, "link_down" }, | ||
107 | { FCH_EVT_LIPRESET, "lip_reset" }, | ||
108 | { FCH_EVT_RSCN, "rscn" }, | ||
109 | { FCH_EVT_ADAPTER_CHANGE, "adapter_chg" }, | ||
110 | { FCH_EVT_PORT_UNKNOWN, "port_unknown" }, | ||
111 | { FCH_EVT_PORT_ONLINE, "port_online" }, | ||
112 | { FCH_EVT_PORT_OFFLINE, "port_offline" }, | ||
113 | { FCH_EVT_PORT_FABRIC, "port_fabric" }, | ||
114 | { FCH_EVT_LINK_UNKNOWN, "link_unknown" }, | ||
115 | { FCH_EVT_VENDOR_UNIQUE, "vendor_unique" }, | ||
116 | }; | ||
117 | fc_enum_name_search(host_event_code, fc_host_event_code, | ||
118 | fc_host_event_code_names) | ||
119 | #define FC_HOST_EVENT_CODE_MAX_NAMELEN 30 | ||
120 | |||
121 | |||
96 | /* Convert fc_port_state values to ascii string name */ | 122 | /* Convert fc_port_state values to ascii string name */ |
97 | static struct { | 123 | static struct { |
98 | enum fc_port_state value; | 124 | enum fc_port_state value; |
@@ -216,6 +242,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names) | |||
216 | 242 | ||
217 | 243 | ||
218 | static void fc_timeout_deleted_rport(void *data); | 244 | static void fc_timeout_deleted_rport(void *data); |
245 | static void fc_timeout_fail_rport_io(void *data); | ||
219 | static void fc_scsi_scan_rport(void *data); | 246 | static void fc_scsi_scan_rport(void *data); |
220 | 247 | ||
221 | /* | 248 | /* |
@@ -223,7 +250,7 @@ static void fc_scsi_scan_rport(void *data); | |||
223 | * Increase these values if you add attributes | 250 | * Increase these values if you add attributes |
224 | */ | 251 | */ |
225 | #define FC_STARGET_NUM_ATTRS 3 | 252 | #define FC_STARGET_NUM_ATTRS 3 |
226 | #define FC_RPORT_NUM_ATTRS 9 | 253 | #define FC_RPORT_NUM_ATTRS 10 |
227 | #define FC_HOST_NUM_ATTRS 17 | 254 | #define FC_HOST_NUM_ATTRS 17 |
228 | 255 | ||
229 | struct fc_internal { | 256 | struct fc_internal { |
@@ -301,8 +328,6 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, | |||
301 | fc_host->supported_classes = FC_COS_UNSPECIFIED; | 328 | fc_host->supported_classes = FC_COS_UNSPECIFIED; |
302 | memset(fc_host->supported_fc4s, 0, | 329 | memset(fc_host->supported_fc4s, 0, |
303 | sizeof(fc_host->supported_fc4s)); | 330 | sizeof(fc_host->supported_fc4s)); |
304 | memset(fc_host->symbolic_name, 0, | ||
305 | sizeof(fc_host->symbolic_name)); | ||
306 | fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN; | 331 | fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN; |
307 | fc_host->maxframe_size = -1; | 332 | fc_host->maxframe_size = -1; |
308 | memset(fc_host->serial_number, 0, | 333 | memset(fc_host->serial_number, 0, |
@@ -315,6 +340,8 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, | |||
315 | sizeof(fc_host->active_fc4s)); | 340 | sizeof(fc_host->active_fc4s)); |
316 | fc_host->speed = FC_PORTSPEED_UNKNOWN; | 341 | fc_host->speed = FC_PORTSPEED_UNKNOWN; |
317 | fc_host->fabric_name = -1; | 342 | fc_host->fabric_name = -1; |
343 | memset(fc_host->symbolic_name, 0, sizeof(fc_host->symbolic_name)); | ||
344 | memset(fc_host->system_hostname, 0, sizeof(fc_host->system_hostname)); | ||
318 | 345 | ||
319 | fc_host->tgtid_bind_type = FC_TGTID_BIND_BY_WWPN; | 346 | fc_host->tgtid_bind_type = FC_TGTID_BIND_BY_WWPN; |
320 | 347 | ||
@@ -377,10 +404,184 @@ MODULE_PARM_DESC(dev_loss_tmo, | |||
377 | " exceeded, the scsi target is removed. Value should be" | 404 | " exceeded, the scsi target is removed. Value should be" |
378 | " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT."); | 405 | " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT."); |
379 | 406 | ||
407 | /** | ||
408 | * Netlink Infrastructure | ||
409 | **/ | ||
410 | |||
411 | static atomic_t fc_event_seq; | ||
412 | |||
413 | /** | ||
414 | * fc_get_event_number - Obtain the next sequential FC event number | ||
415 | * | ||
416 | * Notes: | ||
417 | * We could have inline'd this, but it would have required fc_event_seq to | ||
418 | * be exposed. For now, live with the subroutine call. | ||
419 | * Atomic used to avoid lock/unlock... | ||
420 | **/ | ||
421 | u32 | ||
422 | fc_get_event_number(void) | ||
423 | { | ||
424 | return atomic_add_return(1, &fc_event_seq); | ||
425 | } | ||
426 | EXPORT_SYMBOL(fc_get_event_number); | ||
427 | |||
428 | |||
429 | /** | ||
430 | * fc_host_post_event - called to post an even on an fc_host. | ||
431 | * | ||
432 | * @shost: host the event occurred on | ||
433 | * @event_number: fc event number obtained from get_fc_event_number() | ||
434 | * @event_code: fc_host event being posted | ||
435 | * @event_data: 32bits of data for the event being posted | ||
436 | * | ||
437 | * Notes: | ||
438 | * This routine assumes no locks are held on entry. | ||
439 | **/ | ||
440 | void | ||
441 | fc_host_post_event(struct Scsi_Host *shost, u32 event_number, | ||
442 | enum fc_host_event_code event_code, u32 event_data) | ||
443 | { | ||
444 | struct sk_buff *skb; | ||
445 | struct nlmsghdr *nlh; | ||
446 | struct fc_nl_event *event; | ||
447 | const char *name; | ||
448 | u32 len, skblen; | ||
449 | int err; | ||
450 | |||
451 | if (!scsi_nl_sock) { | ||
452 | err = -ENOENT; | ||
453 | goto send_fail; | ||
454 | } | ||
455 | |||
456 | len = FC_NL_MSGALIGN(sizeof(*event)); | ||
457 | skblen = NLMSG_SPACE(len); | ||
458 | |||
459 | skb = alloc_skb(skblen, GFP_KERNEL); | ||
460 | if (!skb) { | ||
461 | err = -ENOBUFS; | ||
462 | goto send_fail; | ||
463 | } | ||
464 | |||
465 | nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, | ||
466 | skblen - sizeof(*nlh), 0); | ||
467 | if (!nlh) { | ||
468 | err = -ENOBUFS; | ||
469 | goto send_fail_skb; | ||
470 | } | ||
471 | event = NLMSG_DATA(nlh); | ||
472 | |||
473 | INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, | ||
474 | FC_NL_ASYNC_EVENT, len); | ||
475 | event->seconds = get_seconds(); | ||
476 | event->vendor_id = 0; | ||
477 | event->host_no = shost->host_no; | ||
478 | event->event_datalen = sizeof(u32); /* bytes */ | ||
479 | event->event_num = event_number; | ||
480 | event->event_code = event_code; | ||
481 | event->event_data = event_data; | ||
482 | |||
483 | err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, | ||
484 | GFP_KERNEL); | ||
485 | if (err && (err != -ESRCH)) /* filter no recipient errors */ | ||
486 | /* nlmsg_multicast already kfree_skb'd */ | ||
487 | goto send_fail; | ||
488 | |||
489 | return; | ||
490 | |||
491 | send_fail_skb: | ||
492 | kfree_skb(skb); | ||
493 | send_fail: | ||
494 | name = get_fc_host_event_code_name(event_code); | ||
495 | printk(KERN_WARNING | ||
496 | "%s: Dropped Event : host %d %s data 0x%08x - err %d\n", | ||
497 | __FUNCTION__, shost->host_no, | ||
498 | (name) ? name : "<unknown>", event_data, err); | ||
499 | return; | ||
500 | } | ||
501 | EXPORT_SYMBOL(fc_host_post_event); | ||
502 | |||
503 | |||
504 | /** | ||
505 | * fc_host_post_vendor_event - called to post a vendor unique event on | ||
506 | * a fc_host | ||
507 | * | ||
508 | * @shost: host the event occurred on | ||
509 | * @event_number: fc event number obtained from get_fc_event_number() | ||
510 | * @data_len: amount, in bytes, of vendor unique data | ||
511 | * @data_buf: pointer to vendor unique data | ||
512 | * | ||
513 | * Notes: | ||
514 | * This routine assumes no locks are held on entry. | ||
515 | **/ | ||
516 | void | ||
517 | fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, | ||
518 | u32 data_len, char * data_buf, u64 vendor_id) | ||
519 | { | ||
520 | struct sk_buff *skb; | ||
521 | struct nlmsghdr *nlh; | ||
522 | struct fc_nl_event *event; | ||
523 | u32 len, skblen; | ||
524 | int err; | ||
525 | |||
526 | if (!scsi_nl_sock) { | ||
527 | err = -ENOENT; | ||
528 | goto send_vendor_fail; | ||
529 | } | ||
530 | |||
531 | len = FC_NL_MSGALIGN(sizeof(*event) + data_len); | ||
532 | skblen = NLMSG_SPACE(len); | ||
533 | |||
534 | skb = alloc_skb(skblen, GFP_KERNEL); | ||
535 | if (!skb) { | ||
536 | err = -ENOBUFS; | ||
537 | goto send_vendor_fail; | ||
538 | } | ||
539 | |||
540 | nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, | ||
541 | skblen - sizeof(*nlh), 0); | ||
542 | if (!nlh) { | ||
543 | err = -ENOBUFS; | ||
544 | goto send_vendor_fail_skb; | ||
545 | } | ||
546 | event = NLMSG_DATA(nlh); | ||
547 | |||
548 | INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, | ||
549 | FC_NL_ASYNC_EVENT, len); | ||
550 | event->seconds = get_seconds(); | ||
551 | event->vendor_id = vendor_id; | ||
552 | event->host_no = shost->host_no; | ||
553 | event->event_datalen = data_len; /* bytes */ | ||
554 | event->event_num = event_number; | ||
555 | event->event_code = FCH_EVT_VENDOR_UNIQUE; | ||
556 | memcpy(&event->event_data, data_buf, data_len); | ||
557 | |||
558 | err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, | ||
559 | GFP_KERNEL); | ||
560 | if (err && (err != -ESRCH)) /* filter no recipient errors */ | ||
561 | /* nlmsg_multicast already kfree_skb'd */ | ||
562 | goto send_vendor_fail; | ||
563 | |||
564 | return; | ||
565 | |||
566 | send_vendor_fail_skb: | ||
567 | kfree_skb(skb); | ||
568 | send_vendor_fail: | ||
569 | printk(KERN_WARNING | ||
570 | "%s: Dropped Event : host %d vendor_unique - err %d\n", | ||
571 | __FUNCTION__, shost->host_no, err); | ||
572 | return; | ||
573 | } | ||
574 | EXPORT_SYMBOL(fc_host_post_vendor_event); | ||
575 | |||
576 | |||
380 | 577 | ||
381 | static __init int fc_transport_init(void) | 578 | static __init int fc_transport_init(void) |
382 | { | 579 | { |
383 | int error = transport_class_register(&fc_host_class); | 580 | int error; |
581 | |||
582 | atomic_set(&fc_event_seq, 0); | ||
583 | |||
584 | error = transport_class_register(&fc_host_class); | ||
384 | if (error) | 585 | if (error) |
385 | return error; | 586 | return error; |
386 | error = transport_class_register(&fc_rport_class); | 587 | error = transport_class_register(&fc_rport_class); |
@@ -424,11 +625,14 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \ | |||
424 | struct fc_rport *rport = transport_class_to_rport(cdev); \ | 625 | struct fc_rport *rport = transport_class_to_rport(cdev); \ |
425 | struct Scsi_Host *shost = rport_to_shost(rport); \ | 626 | struct Scsi_Host *shost = rport_to_shost(rport); \ |
426 | struct fc_internal *i = to_fc_internal(shost->transportt); \ | 627 | struct fc_internal *i = to_fc_internal(shost->transportt); \ |
628 | char *cp; \ | ||
427 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \ | 629 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \ |
428 | (rport->port_state == FC_PORTSTATE_DELETED) || \ | 630 | (rport->port_state == FC_PORTSTATE_DELETED) || \ |
429 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \ | 631 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \ |
430 | return -EBUSY; \ | 632 | return -EBUSY; \ |
431 | val = simple_strtoul(buf, NULL, 0); \ | 633 | val = simple_strtoul(buf, &cp, 0); \ |
634 | if (*cp && (*cp != '\n')) \ | ||
635 | return -EINVAL; \ | ||
432 | i->f->set_rport_##field(rport, val); \ | 636 | i->f->set_rport_##field(rport, val); \ |
433 | return count; \ | 637 | return count; \ |
434 | } | 638 | } |
@@ -510,6 +714,13 @@ static FC_CLASS_DEVICE_ATTR(rport, title, S_IRUGO, \ | |||
510 | if (i->f->show_rport_##field) \ | 714 | if (i->f->show_rport_##field) \ |
511 | count++ | 715 | count++ |
512 | 716 | ||
717 | #define SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(field) \ | ||
718 | { \ | ||
719 | i->private_rport_attrs[count] = class_device_attr_rport_##field; \ | ||
720 | i->rport_attrs[count] = &i->private_rport_attrs[count]; \ | ||
721 | count++; \ | ||
722 | } | ||
723 | |||
513 | 724 | ||
514 | /* The FC Transport Remote Port Attributes: */ | 725 | /* The FC Transport Remote Port Attributes: */ |
515 | 726 | ||
@@ -542,12 +753,14 @@ store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf, | |||
542 | struct fc_rport *rport = transport_class_to_rport(cdev); | 753 | struct fc_rport *rport = transport_class_to_rport(cdev); |
543 | struct Scsi_Host *shost = rport_to_shost(rport); | 754 | struct Scsi_Host *shost = rport_to_shost(rport); |
544 | struct fc_internal *i = to_fc_internal(shost->transportt); | 755 | struct fc_internal *i = to_fc_internal(shost->transportt); |
756 | char *cp; | ||
545 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || | 757 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || |
546 | (rport->port_state == FC_PORTSTATE_DELETED) || | 758 | (rport->port_state == FC_PORTSTATE_DELETED) || |
547 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) | 759 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) |
548 | return -EBUSY; | 760 | return -EBUSY; |
549 | val = simple_strtoul(buf, NULL, 0); | 761 | val = simple_strtoul(buf, &cp, 0); |
550 | if ((val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)) | 762 | if ((*cp && (*cp != '\n')) || |
763 | (val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)) | ||
551 | return -EINVAL; | 764 | return -EINVAL; |
552 | i->f->set_rport_dev_loss_tmo(rport, val); | 765 | i->f->set_rport_dev_loss_tmo(rport, val); |
553 | return count; | 766 | return count; |
@@ -597,6 +810,44 @@ static FC_CLASS_DEVICE_ATTR(rport, roles, S_IRUGO, | |||
597 | fc_private_rport_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN); | 810 | fc_private_rport_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN); |
598 | fc_private_rport_rd_attr(scsi_target_id, "%d\n", 20); | 811 | fc_private_rport_rd_attr(scsi_target_id, "%d\n", 20); |
599 | 812 | ||
813 | /* | ||
814 | * fast_io_fail_tmo attribute | ||
815 | */ | ||
816 | static ssize_t | ||
817 | show_fc_rport_fast_io_fail_tmo (struct class_device *cdev, char *buf) | ||
818 | { | ||
819 | struct fc_rport *rport = transport_class_to_rport(cdev); | ||
820 | |||
821 | if (rport->fast_io_fail_tmo == -1) | ||
822 | return snprintf(buf, 5, "off\n"); | ||
823 | return snprintf(buf, 20, "%d\n", rport->fast_io_fail_tmo); | ||
824 | } | ||
825 | |||
826 | static ssize_t | ||
827 | store_fc_rport_fast_io_fail_tmo(struct class_device *cdev, const char *buf, | ||
828 | size_t count) | ||
829 | { | ||
830 | int val; | ||
831 | char *cp; | ||
832 | struct fc_rport *rport = transport_class_to_rport(cdev); | ||
833 | |||
834 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || | ||
835 | (rport->port_state == FC_PORTSTATE_DELETED) || | ||
836 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) | ||
837 | return -EBUSY; | ||
838 | if (strncmp(buf, "off", 3) == 0) | ||
839 | rport->fast_io_fail_tmo = -1; | ||
840 | else { | ||
841 | val = simple_strtoul(buf, &cp, 0); | ||
842 | if ((*cp && (*cp != '\n')) || | ||
843 | (val < 0) || (val >= rport->dev_loss_tmo)) | ||
844 | return -EINVAL; | ||
845 | rport->fast_io_fail_tmo = val; | ||
846 | } | ||
847 | return count; | ||
848 | } | ||
849 | static FC_CLASS_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR, | ||
850 | show_fc_rport_fast_io_fail_tmo, store_fc_rport_fast_io_fail_tmo); | ||
600 | 851 | ||
601 | 852 | ||
602 | /* | 853 | /* |
@@ -682,12 +933,34 @@ store_fc_host_##field(struct class_device *cdev, const char *buf, \ | |||
682 | int val; \ | 933 | int val; \ |
683 | struct Scsi_Host *shost = transport_class_to_shost(cdev); \ | 934 | struct Scsi_Host *shost = transport_class_to_shost(cdev); \ |
684 | struct fc_internal *i = to_fc_internal(shost->transportt); \ | 935 | struct fc_internal *i = to_fc_internal(shost->transportt); \ |
936 | char *cp; \ | ||
685 | \ | 937 | \ |
686 | val = simple_strtoul(buf, NULL, 0); \ | 938 | val = simple_strtoul(buf, &cp, 0); \ |
939 | if (*cp && (*cp != '\n')) \ | ||
940 | return -EINVAL; \ | ||
687 | i->f->set_host_##field(shost, val); \ | 941 | i->f->set_host_##field(shost, val); \ |
688 | return count; \ | 942 | return count; \ |
689 | } | 943 | } |
690 | 944 | ||
945 | #define fc_host_store_str_function(field, slen) \ | ||
946 | static ssize_t \ | ||
947 | store_fc_host_##field(struct class_device *cdev, const char *buf, \ | ||
948 | size_t count) \ | ||
949 | { \ | ||
950 | struct Scsi_Host *shost = transport_class_to_shost(cdev); \ | ||
951 | struct fc_internal *i = to_fc_internal(shost->transportt); \ | ||
952 | unsigned int cnt=count; \ | ||
953 | \ | ||
954 | /* count may include a LF at end of string */ \ | ||
955 | if (buf[cnt-1] == '\n') \ | ||
956 | cnt--; \ | ||
957 | if (cnt > ((slen) - 1)) \ | ||
958 | return -EINVAL; \ | ||
959 | memcpy(fc_host_##field(shost), buf, cnt); \ | ||
960 | i->f->set_host_##field(shost); \ | ||
961 | return count; \ | ||
962 | } | ||
963 | |||
691 | #define fc_host_rd_attr(field, format_string, sz) \ | 964 | #define fc_host_rd_attr(field, format_string, sz) \ |
692 | fc_host_show_function(field, format_string, sz, ) \ | 965 | fc_host_show_function(field, format_string, sz, ) \ |
693 | static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO, \ | 966 | static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO, \ |
@@ -815,7 +1088,6 @@ fc_private_host_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long); | |||
815 | fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long); | 1088 | fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long); |
816 | fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20, | 1089 | fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20, |
817 | unsigned long long); | 1090 | unsigned long long); |
818 | fc_private_host_rd_attr(symbolic_name, "%s\n", (FC_SYMBOLIC_NAME_SIZE +1)); | ||
819 | fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20); | 1091 | fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20); |
820 | fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1)); | 1092 | fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1)); |
821 | 1093 | ||
@@ -858,6 +1130,13 @@ fc_host_rd_attr(port_id, "0x%06x\n", 20); | |||
858 | fc_host_rd_enum_attr(port_type, FC_PORTTYPE_MAX_NAMELEN); | 1130 | fc_host_rd_enum_attr(port_type, FC_PORTTYPE_MAX_NAMELEN); |
859 | fc_host_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN); | 1131 | fc_host_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN); |
860 | fc_host_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long); | 1132 | fc_host_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long); |
1133 | fc_host_rd_attr(symbolic_name, "%s\n", FC_SYMBOLIC_NAME_SIZE + 1); | ||
1134 | |||
1135 | fc_private_host_show_function(system_hostname, "%s\n", | ||
1136 | FC_SYMBOLIC_NAME_SIZE + 1, ) | ||
1137 | fc_host_store_str_function(system_hostname, FC_SYMBOLIC_NAME_SIZE) | ||
1138 | static FC_CLASS_DEVICE_ATTR(host, system_hostname, S_IRUGO | S_IWUSR, | ||
1139 | show_fc_host_system_hostname, store_fc_host_system_hostname); | ||
861 | 1140 | ||
862 | 1141 | ||
863 | /* Private Host Attributes */ | 1142 | /* Private Host Attributes */ |
@@ -1223,7 +1502,6 @@ fc_attach_transport(struct fc_function_template *ft) | |||
1223 | SETUP_HOST_ATTRIBUTE_RD(permanent_port_name); | 1502 | SETUP_HOST_ATTRIBUTE_RD(permanent_port_name); |
1224 | SETUP_HOST_ATTRIBUTE_RD(supported_classes); | 1503 | SETUP_HOST_ATTRIBUTE_RD(supported_classes); |
1225 | SETUP_HOST_ATTRIBUTE_RD(supported_fc4s); | 1504 | SETUP_HOST_ATTRIBUTE_RD(supported_fc4s); |
1226 | SETUP_HOST_ATTRIBUTE_RD(symbolic_name); | ||
1227 | SETUP_HOST_ATTRIBUTE_RD(supported_speeds); | 1505 | SETUP_HOST_ATTRIBUTE_RD(supported_speeds); |
1228 | SETUP_HOST_ATTRIBUTE_RD(maxframe_size); | 1506 | SETUP_HOST_ATTRIBUTE_RD(maxframe_size); |
1229 | SETUP_HOST_ATTRIBUTE_RD(serial_number); | 1507 | SETUP_HOST_ATTRIBUTE_RD(serial_number); |
@@ -1234,6 +1512,8 @@ fc_attach_transport(struct fc_function_template *ft) | |||
1234 | SETUP_HOST_ATTRIBUTE_RD(active_fc4s); | 1512 | SETUP_HOST_ATTRIBUTE_RD(active_fc4s); |
1235 | SETUP_HOST_ATTRIBUTE_RD(speed); | 1513 | SETUP_HOST_ATTRIBUTE_RD(speed); |
1236 | SETUP_HOST_ATTRIBUTE_RD(fabric_name); | 1514 | SETUP_HOST_ATTRIBUTE_RD(fabric_name); |
1515 | SETUP_HOST_ATTRIBUTE_RD(symbolic_name); | ||
1516 | SETUP_HOST_ATTRIBUTE_RW(system_hostname); | ||
1237 | 1517 | ||
1238 | /* Transport-managed attributes */ | 1518 | /* Transport-managed attributes */ |
1239 | SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type); | 1519 | SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type); |
@@ -1257,6 +1537,8 @@ fc_attach_transport(struct fc_function_template *ft) | |||
1257 | SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles); | 1537 | SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles); |
1258 | SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state); | 1538 | SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state); |
1259 | SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id); | 1539 | SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id); |
1540 | if (ft->terminate_rport_io) | ||
1541 | SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo); | ||
1260 | 1542 | ||
1261 | BUG_ON(count > FC_RPORT_NUM_ATTRS); | 1543 | BUG_ON(count > FC_RPORT_NUM_ATTRS); |
1262 | 1544 | ||
@@ -1328,7 +1610,7 @@ fc_flush_work(struct Scsi_Host *shost) | |||
1328 | * @delay: jiffies to delay the work queuing | 1610 | * @delay: jiffies to delay the work queuing |
1329 | * | 1611 | * |
1330 | * Return value: | 1612 | * Return value: |
1331 | * 0 on success / != 0 for error | 1613 | * 1 on success / 0 already queued / < 0 for error |
1332 | **/ | 1614 | **/ |
1333 | static int | 1615 | static int |
1334 | fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work, | 1616 | fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work, |
@@ -1343,6 +1625,9 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work, | |||
1343 | return -EINVAL; | 1625 | return -EINVAL; |
1344 | } | 1626 | } |
1345 | 1627 | ||
1628 | if (delay == 0) | ||
1629 | return queue_work(fc_host_devloss_work_q(shost), work); | ||
1630 | |||
1346 | return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay); | 1631 | return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay); |
1347 | } | 1632 | } |
1348 | 1633 | ||
@@ -1435,10 +1720,23 @@ fc_starget_delete(void *data) | |||
1435 | struct fc_rport *rport = (struct fc_rport *)data; | 1720 | struct fc_rport *rport = (struct fc_rport *)data; |
1436 | struct Scsi_Host *shost = rport_to_shost(rport); | 1721 | struct Scsi_Host *shost = rport_to_shost(rport); |
1437 | unsigned long flags; | 1722 | unsigned long flags; |
1723 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
1724 | |||
1725 | /* | ||
1726 | * Involve the LLDD if possible. All io on the rport is to | ||
1727 | * be terminated, either as part of the dev_loss_tmo callback | ||
1728 | * processing, or via the terminate_rport_io function. | ||
1729 | */ | ||
1730 | if (i->f->dev_loss_tmo_callbk) | ||
1731 | i->f->dev_loss_tmo_callbk(rport); | ||
1732 | else if (i->f->terminate_rport_io) | ||
1733 | i->f->terminate_rport_io(rport); | ||
1438 | 1734 | ||
1439 | spin_lock_irqsave(shost->host_lock, flags); | 1735 | spin_lock_irqsave(shost->host_lock, flags); |
1440 | if (rport->flags & FC_RPORT_DEVLOSS_PENDING) { | 1736 | if (rport->flags & FC_RPORT_DEVLOSS_PENDING) { |
1441 | spin_unlock_irqrestore(shost->host_lock, flags); | 1737 | spin_unlock_irqrestore(shost->host_lock, flags); |
1738 | if (!cancel_delayed_work(&rport->fail_io_work)) | ||
1739 | fc_flush_devloss(shost); | ||
1442 | if (!cancel_delayed_work(&rport->dev_loss_work)) | 1740 | if (!cancel_delayed_work(&rport->dev_loss_work)) |
1443 | fc_flush_devloss(shost); | 1741 | fc_flush_devloss(shost); |
1444 | spin_lock_irqsave(shost->host_lock, flags); | 1742 | spin_lock_irqsave(shost->host_lock, flags); |
@@ -1461,10 +1759,7 @@ fc_rport_final_delete(void *data) | |||
1461 | struct fc_rport *rport = (struct fc_rport *)data; | 1759 | struct fc_rport *rport = (struct fc_rport *)data; |
1462 | struct device *dev = &rport->dev; | 1760 | struct device *dev = &rport->dev; |
1463 | struct Scsi_Host *shost = rport_to_shost(rport); | 1761 | struct Scsi_Host *shost = rport_to_shost(rport); |
1464 | 1762 | struct fc_internal *i = to_fc_internal(shost->transportt); | |
1465 | /* Delete SCSI target and sdevs */ | ||
1466 | if (rport->scsi_target_id != -1) | ||
1467 | fc_starget_delete(data); | ||
1468 | 1763 | ||
1469 | /* | 1764 | /* |
1470 | * if a scan is pending, flush the SCSI Host work_q so that | 1765 | * if a scan is pending, flush the SCSI Host work_q so that |
@@ -1473,6 +1768,14 @@ fc_rport_final_delete(void *data) | |||
1473 | if (rport->flags & FC_RPORT_SCAN_PENDING) | 1768 | if (rport->flags & FC_RPORT_SCAN_PENDING) |
1474 | scsi_flush_work(shost); | 1769 | scsi_flush_work(shost); |
1475 | 1770 | ||
1771 | /* Delete SCSI target and sdevs */ | ||
1772 | if (rport->scsi_target_id != -1) | ||
1773 | fc_starget_delete(data); | ||
1774 | else if (i->f->dev_loss_tmo_callbk) | ||
1775 | i->f->dev_loss_tmo_callbk(rport); | ||
1776 | else if (i->f->terminate_rport_io) | ||
1777 | i->f->terminate_rport_io(rport); | ||
1778 | |||
1476 | transport_remove_device(dev); | 1779 | transport_remove_device(dev); |
1477 | device_del(dev); | 1780 | device_del(dev); |
1478 | transport_destroy_device(dev); | 1781 | transport_destroy_device(dev); |
@@ -1524,8 +1827,10 @@ fc_rport_create(struct Scsi_Host *shost, int channel, | |||
1524 | if (fci->f->dd_fcrport_size) | 1827 | if (fci->f->dd_fcrport_size) |
1525 | rport->dd_data = &rport[1]; | 1828 | rport->dd_data = &rport[1]; |
1526 | rport->channel = channel; | 1829 | rport->channel = channel; |
1830 | rport->fast_io_fail_tmo = -1; | ||
1527 | 1831 | ||
1528 | INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport); | 1832 | INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport); |
1833 | INIT_WORK(&rport->fail_io_work, fc_timeout_fail_rport_io, rport); | ||
1529 | INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport); | 1834 | INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport); |
1530 | INIT_WORK(&rport->stgt_delete_work, fc_starget_delete, rport); | 1835 | INIT_WORK(&rport->stgt_delete_work, fc_starget_delete, rport); |
1531 | INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete, rport); | 1836 | INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete, rport); |
@@ -1689,11 +1994,13 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, | |||
1689 | /* restart the target */ | 1994 | /* restart the target */ |
1690 | 1995 | ||
1691 | /* | 1996 | /* |
1692 | * Stop the target timer first. Take no action | 1997 | * Stop the target timers first. Take no action |
1693 | * on the del_timer failure as the state | 1998 | * on the del_timer failure as the state |
1694 | * machine state change will validate the | 1999 | * machine state change will validate the |
1695 | * transaction. | 2000 | * transaction. |
1696 | */ | 2001 | */ |
2002 | if (!cancel_delayed_work(&rport->fail_io_work)) | ||
2003 | fc_flush_devloss(shost); | ||
1697 | if (!cancel_delayed_work(work)) | 2004 | if (!cancel_delayed_work(work)) |
1698 | fc_flush_devloss(shost); | 2005 | fc_flush_devloss(shost); |
1699 | 2006 | ||
@@ -1837,6 +2144,7 @@ void | |||
1837 | fc_remote_port_delete(struct fc_rport *rport) | 2144 | fc_remote_port_delete(struct fc_rport *rport) |
1838 | { | 2145 | { |
1839 | struct Scsi_Host *shost = rport_to_shost(rport); | 2146 | struct Scsi_Host *shost = rport_to_shost(rport); |
2147 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
1840 | int timeout = rport->dev_loss_tmo; | 2148 | int timeout = rport->dev_loss_tmo; |
1841 | unsigned long flags; | 2149 | unsigned long flags; |
1842 | 2150 | ||
@@ -1867,6 +2175,12 @@ fc_remote_port_delete(struct fc_rport *rport) | |||
1867 | 2175 | ||
1868 | scsi_target_block(&rport->dev); | 2176 | scsi_target_block(&rport->dev); |
1869 | 2177 | ||
2178 | /* see if we need to kill io faster than waiting for device loss */ | ||
2179 | if ((rport->fast_io_fail_tmo != -1) && | ||
2180 | (rport->fast_io_fail_tmo < timeout) && (i->f->terminate_rport_io)) | ||
2181 | fc_queue_devloss_work(shost, &rport->fail_io_work, | ||
2182 | rport->fast_io_fail_tmo * HZ); | ||
2183 | |||
1870 | /* cap the length the devices can be blocked until they are deleted */ | 2184 | /* cap the length the devices can be blocked until they are deleted */ |
1871 | fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ); | 2185 | fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ); |
1872 | } | 2186 | } |
@@ -1926,6 +2240,8 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) | |||
1926 | * machine state change will validate the | 2240 | * machine state change will validate the |
1927 | * transaction. | 2241 | * transaction. |
1928 | */ | 2242 | */ |
2243 | if (!cancel_delayed_work(&rport->fail_io_work)) | ||
2244 | fc_flush_devloss(shost); | ||
1929 | if (!cancel_delayed_work(&rport->dev_loss_work)) | 2245 | if (!cancel_delayed_work(&rport->dev_loss_work)) |
1930 | fc_flush_devloss(shost); | 2246 | fc_flush_devloss(shost); |
1931 | 2247 | ||
@@ -2047,6 +2363,28 @@ fc_timeout_deleted_rport(void *data) | |||
2047 | } | 2363 | } |
2048 | 2364 | ||
2049 | /** | 2365 | /** |
2366 | * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a | ||
2367 | * disconnected SCSI target. | ||
2368 | * | ||
2369 | * @data: rport to terminate io on. | ||
2370 | * | ||
2371 | * Notes: Only requests the failure of the io, not that all are flushed | ||
2372 | * prior to returning. | ||
2373 | **/ | ||
2374 | static void | ||
2375 | fc_timeout_fail_rport_io(void *data) | ||
2376 | { | ||
2377 | struct fc_rport *rport = (struct fc_rport *)data; | ||
2378 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
2379 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
2380 | |||
2381 | if (rport->port_state != FC_PORTSTATE_BLOCKED) | ||
2382 | return; | ||
2383 | |||
2384 | i->f->terminate_rport_io(rport); | ||
2385 | } | ||
2386 | |||
2387 | /** | ||
2050 | * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. | 2388 | * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. |
2051 | * | 2389 | * |
2052 | * @data: remote port to be scanned. | 2390 | * @data: remote port to be scanned. |