diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/Kconfig | 6 | ||||
-rw-r--r-- | drivers/scsi/Makefile | 1 | ||||
-rw-r--r-- | drivers/scsi/scsi.c | 3 | ||||
-rw-r--r-- | drivers/scsi/scsi_netlink.c | 199 | ||||
-rw-r--r-- | drivers/scsi/scsi_priv.h | 11 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 200 |
6 files changed, 419 insertions, 1 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index c8c606589ea6..4d1998d23f0f 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
@@ -27,6 +27,11 @@ config SCSI | |||
27 | However, do not compile this as a module if your root file system | 27 | However, do not compile this as a module if your root file system |
28 | (the one containing the directory /) is located on a SCSI device. | 28 | (the one containing the directory /) is located on a SCSI device. |
29 | 29 | ||
30 | config SCSI_NETLINK | ||
31 | tristate | ||
32 | default n | ||
33 | select NET | ||
34 | |||
30 | config SCSI_PROC_FS | 35 | config SCSI_PROC_FS |
31 | bool "legacy /proc/scsi/ support" | 36 | bool "legacy /proc/scsi/ support" |
32 | depends on SCSI && PROC_FS | 37 | depends on SCSI && PROC_FS |
@@ -222,6 +227,7 @@ config SCSI_SPI_ATTRS | |||
222 | config SCSI_FC_ATTRS | 227 | config SCSI_FC_ATTRS |
223 | tristate "FiberChannel Transport Attributes" | 228 | tristate "FiberChannel Transport Attributes" |
224 | depends on SCSI | 229 | depends on SCSI |
230 | select SCSI_NETLINK | ||
225 | help | 231 | help |
226 | If you wish to export transport-specific information about | 232 | If you wish to export transport-specific information about |
227 | each attached FiberChannel device to sysfs, say Y. | 233 | each attached FiberChannel device to sysfs, say Y. |
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index fd9aeb1ba07f..8fc2c594b537 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile | |||
@@ -159,6 +159,7 @@ scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ | |||
159 | scsicam.o scsi_error.o scsi_lib.o \ | 159 | scsicam.o scsi_error.o scsi_lib.o \ |
160 | scsi_scan.o scsi_sysfs.o \ | 160 | scsi_scan.o scsi_sysfs.o \ |
161 | scsi_devinfo.o | 161 | scsi_devinfo.o |
162 | scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o | ||
162 | scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o | 163 | scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o |
163 | scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o | 164 | scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o |
164 | 165 | ||
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 37843927e47f..eedfd059b82b 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
@@ -1118,6 +1118,8 @@ static int __init init_scsi(void) | |||
1118 | for_each_possible_cpu(i) | 1118 | for_each_possible_cpu(i) |
1119 | INIT_LIST_HEAD(&per_cpu(scsi_done_q, i)); | 1119 | INIT_LIST_HEAD(&per_cpu(scsi_done_q, i)); |
1120 | 1120 | ||
1121 | scsi_netlink_init(); | ||
1122 | |||
1121 | printk(KERN_NOTICE "SCSI subsystem initialized\n"); | 1123 | printk(KERN_NOTICE "SCSI subsystem initialized\n"); |
1122 | return 0; | 1124 | return 0; |
1123 | 1125 | ||
@@ -1138,6 +1140,7 @@ cleanup_queue: | |||
1138 | 1140 | ||
1139 | static void __exit exit_scsi(void) | 1141 | static void __exit exit_scsi(void) |
1140 | { | 1142 | { |
1143 | scsi_netlink_exit(); | ||
1141 | scsi_sysfs_unregister(); | 1144 | scsi_sysfs_unregister(); |
1142 | scsi_exit_sysctl(); | 1145 | scsi_exit_sysctl(); |
1143 | scsi_exit_hosts(); | 1146 | scsi_exit_hosts(); |
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c new file mode 100644 index 000000000000..1b59b27e887f --- /dev/null +++ b/drivers/scsi/scsi_netlink.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * scsi_netlink.c - SCSI Transport Netlink Interface | ||
3 | * | ||
4 | * Copyright (C) 2006 James Smart, Emulex Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/time.h> | ||
22 | #include <linux/jiffies.h> | ||
23 | #include <linux/security.h> | ||
24 | #include <net/sock.h> | ||
25 | #include <net/netlink.h> | ||
26 | |||
27 | #include <scsi/scsi_netlink.h> | ||
28 | #include "scsi_priv.h" | ||
29 | |||
30 | struct sock *scsi_nl_sock = NULL; | ||
31 | EXPORT_SYMBOL_GPL(scsi_nl_sock); | ||
32 | |||
33 | |||
34 | /** | ||
35 | * scsi_nl_rcv_msg - | ||
36 | * Receive message handler. Extracts message from a receive buffer. | ||
37 | * Validates message header and calls appropriate transport message handler | ||
38 | * | ||
39 | * @skb: socket receive buffer | ||
40 | * | ||
41 | **/ | ||
42 | static void | ||
43 | scsi_nl_rcv_msg(struct sk_buff *skb) | ||
44 | { | ||
45 | struct nlmsghdr *nlh; | ||
46 | struct scsi_nl_hdr *hdr; | ||
47 | uint32_t rlen; | ||
48 | int err; | ||
49 | |||
50 | while (skb->len >= NLMSG_SPACE(0)) { | ||
51 | err = 0; | ||
52 | |||
53 | nlh = (struct nlmsghdr *) skb->data; | ||
54 | if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) || | ||
55 | (skb->len < nlh->nlmsg_len)) { | ||
56 | printk(KERN_WARNING "%s: discarding partial skb\n", | ||
57 | __FUNCTION__); | ||
58 | return; | ||
59 | } | ||
60 | |||
61 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | ||
62 | if (rlen > skb->len) | ||
63 | rlen = skb->len; | ||
64 | |||
65 | if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) { | ||
66 | err = -EBADMSG; | ||
67 | goto next_msg; | ||
68 | } | ||
69 | |||
70 | hdr = NLMSG_DATA(nlh); | ||
71 | if ((hdr->version != SCSI_NL_VERSION) || | ||
72 | (hdr->magic != SCSI_NL_MAGIC)) { | ||
73 | err = -EPROTOTYPE; | ||
74 | goto next_msg; | ||
75 | } | ||
76 | |||
77 | if (security_netlink_recv(skb, CAP_SYS_ADMIN)) { | ||
78 | err = -EPERM; | ||
79 | goto next_msg; | ||
80 | } | ||
81 | |||
82 | if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) { | ||
83 | printk(KERN_WARNING "%s: discarding partial message\n", | ||
84 | __FUNCTION__); | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * We currently don't support anyone sending us a message | ||
90 | */ | ||
91 | |||
92 | next_msg: | ||
93 | if ((err) || (nlh->nlmsg_flags & NLM_F_ACK)) | ||
94 | netlink_ack(skb, nlh, err); | ||
95 | |||
96 | skb_pull(skb, rlen); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | |||
101 | /** | ||
102 | * scsi_nl_rcv_msg - | ||
103 | * Receive handler for a socket. Extracts a received message buffer from | ||
104 | * the socket, and starts message processing. | ||
105 | * | ||
106 | * @sk: socket | ||
107 | * @len: unused | ||
108 | * | ||
109 | **/ | ||
110 | static void | ||
111 | scsi_nl_rcv(struct sock *sk, int len) | ||
112 | { | ||
113 | struct sk_buff *skb; | ||
114 | |||
115 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { | ||
116 | scsi_nl_rcv_msg(skb); | ||
117 | kfree_skb(skb); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | |||
122 | /** | ||
123 | * scsi_nl_rcv_event - | ||
124 | * Event handler for a netlink socket. | ||
125 | * | ||
126 | * @this: event notifier block | ||
127 | * @event: event type | ||
128 | * @ptr: event payload | ||
129 | * | ||
130 | **/ | ||
131 | static int | ||
132 | scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr) | ||
133 | { | ||
134 | struct netlink_notify *n = ptr; | ||
135 | |||
136 | if (n->protocol != NETLINK_SCSITRANSPORT) | ||
137 | return NOTIFY_DONE; | ||
138 | |||
139 | /* | ||
140 | * Currently, we are not tracking PID's, etc. There is nothing | ||
141 | * to handle. | ||
142 | */ | ||
143 | |||
144 | return NOTIFY_DONE; | ||
145 | } | ||
146 | |||
147 | static struct notifier_block scsi_netlink_notifier = { | ||
148 | .notifier_call = scsi_nl_rcv_event, | ||
149 | }; | ||
150 | |||
151 | |||
152 | /** | ||
153 | * scsi_netlink_init - | ||
154 | * Called by SCSI subsystem to intialize the SCSI transport netlink | ||
155 | * interface | ||
156 | * | ||
157 | **/ | ||
158 | void | ||
159 | scsi_netlink_init(void) | ||
160 | { | ||
161 | int error; | ||
162 | |||
163 | error = netlink_register_notifier(&scsi_netlink_notifier); | ||
164 | if (error) { | ||
165 | printk(KERN_ERR "%s: register of event handler failed - %d\n", | ||
166 | __FUNCTION__, error); | ||
167 | return; | ||
168 | } | ||
169 | |||
170 | scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT, | ||
171 | SCSI_NL_GRP_CNT, scsi_nl_rcv, THIS_MODULE); | ||
172 | if (!scsi_nl_sock) { | ||
173 | printk(KERN_ERR "%s: register of recieve handler failed\n", | ||
174 | __FUNCTION__); | ||
175 | netlink_unregister_notifier(&scsi_netlink_notifier); | ||
176 | } | ||
177 | |||
178 | return; | ||
179 | } | ||
180 | |||
181 | |||
182 | /** | ||
183 | * scsi_netlink_exit - | ||
184 | * Called by SCSI subsystem to disable the SCSI transport netlink | ||
185 | * interface | ||
186 | * | ||
187 | **/ | ||
188 | void | ||
189 | scsi_netlink_exit(void) | ||
190 | { | ||
191 | if (scsi_nl_sock) { | ||
192 | sock_release(scsi_nl_sock->sk_socket); | ||
193 | netlink_unregister_notifier(&scsi_netlink_notifier); | ||
194 | } | ||
195 | |||
196 | return; | ||
197 | } | ||
198 | |||
199 | |||
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index ae24c85aaeea..5d023d44e5e7 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h | |||
@@ -8,6 +8,7 @@ struct scsi_cmnd; | |||
8 | struct scsi_device; | 8 | struct scsi_device; |
9 | struct scsi_host_template; | 9 | struct scsi_host_template; |
10 | struct Scsi_Host; | 10 | struct Scsi_Host; |
11 | struct scsi_nl_hdr; | ||
11 | 12 | ||
12 | 13 | ||
13 | /* | 14 | /* |
@@ -110,6 +111,16 @@ extern void __scsi_remove_device(struct scsi_device *); | |||
110 | 111 | ||
111 | extern struct bus_type scsi_bus_type; | 112 | extern struct bus_type scsi_bus_type; |
112 | 113 | ||
114 | /* scsi_netlink.c */ | ||
115 | #ifdef CONFIG_SCSI_NETLINK | ||
116 | extern void scsi_netlink_init(void); | ||
117 | extern void scsi_netlink_exit(void); | ||
118 | extern struct sock *scsi_nl_sock; | ||
119 | #else | ||
120 | static inline void scsi_netlink_init(void) {} | ||
121 | static inline void scsi_netlink_exit(void) {} | ||
122 | #endif | ||
123 | |||
113 | /* | 124 | /* |
114 | * internal scsi timeout functions: for use by mid-layer and transport | 125 | * internal scsi timeout functions: for use by mid-layer and transport |
115 | * classes. | 126 | * classes. |
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 79d31ca2b741..05989f130554 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; |
@@ -377,10 +403,182 @@ MODULE_PARM_DESC(dev_loss_tmo, | |||
377 | " exceeded, the scsi target is removed. Value should be" | 403 | " exceeded, the scsi target is removed. Value should be" |
378 | " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT."); | 404 | " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT."); |
379 | 405 | ||
406 | /** | ||
407 | * Netlink Infrastructure | ||
408 | **/ | ||
409 | |||
410 | static atomic_t fc_event_seq; | ||
411 | |||
412 | /** | ||
413 | * fc_get_event_number - Obtain the next sequential FC event number | ||
414 | * | ||
415 | * Notes: | ||
416 | * We could have inline'd this, but it would have required fc_event_seq to | ||
417 | * be exposed. For now, live with the subroutine call. | ||
418 | * Atomic used to avoid lock/unlock... | ||
419 | **/ | ||
420 | u32 | ||
421 | fc_get_event_number(void) | ||
422 | { | ||
423 | return atomic_add_return(1, &fc_event_seq); | ||
424 | } | ||
425 | EXPORT_SYMBOL(fc_get_event_number); | ||
426 | |||
427 | |||
428 | /** | ||
429 | * fc_host_post_event - called to post an even on an fc_host. | ||
430 | * | ||
431 | * @shost: host the event occurred on | ||
432 | * @event_number: fc event number obtained from get_fc_event_number() | ||
433 | * @event_code: fc_host event being posted | ||
434 | * @event_data: 32bits of data for the event being posted | ||
435 | * | ||
436 | * Notes: | ||
437 | * This routine assumes no locks are held on entry. | ||
438 | **/ | ||
439 | void | ||
440 | fc_host_post_event(struct Scsi_Host *shost, u32 event_number, | ||
441 | enum fc_host_event_code event_code, u32 event_data) | ||
442 | { | ||
443 | struct sk_buff *skb; | ||
444 | struct nlmsghdr *nlh; | ||
445 | struct fc_nl_event *event; | ||
446 | const char *name; | ||
447 | u32 len, skblen; | ||
448 | int err; | ||
449 | |||
450 | if (!scsi_nl_sock) { | ||
451 | err = -ENOENT; | ||
452 | goto send_fail; | ||
453 | } | ||
454 | |||
455 | len = FC_NL_MSGALIGN(sizeof(*event)); | ||
456 | skblen = NLMSG_SPACE(len); | ||
457 | |||
458 | skb = alloc_skb(skblen, GFP_KERNEL); | ||
459 | if (!skb) { | ||
460 | err = -ENOBUFS; | ||
461 | goto send_fail; | ||
462 | } | ||
463 | |||
464 | nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, | ||
465 | skblen - sizeof(*nlh), 0); | ||
466 | if (!nlh) { | ||
467 | err = -ENOBUFS; | ||
468 | goto send_fail_skb; | ||
469 | } | ||
470 | event = NLMSG_DATA(nlh); | ||
471 | |||
472 | INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, | ||
473 | FC_NL_ASYNC_EVENT, len); | ||
474 | event->seconds = get_seconds(); | ||
475 | event->vendor_id = 0; | ||
476 | event->host_no = shost->host_no; | ||
477 | event->event_datalen = sizeof(u32); /* bytes */ | ||
478 | event->event_num = event_number; | ||
479 | event->event_code = event_code; | ||
480 | event->event_data = event_data; | ||
481 | |||
482 | err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS); | ||
483 | if (err && (err != -ESRCH)) /* filter no recipient errors */ | ||
484 | /* nlmsg_multicast already kfree_skb'd */ | ||
485 | goto send_fail; | ||
486 | |||
487 | return; | ||
488 | |||
489 | send_fail_skb: | ||
490 | kfree_skb(skb); | ||
491 | send_fail: | ||
492 | name = get_fc_host_event_code_name(event_code); | ||
493 | printk(KERN_WARNING | ||
494 | "%s: Dropped Event : host %d %s data 0x%08x - err %d\n", | ||
495 | __FUNCTION__, shost->host_no, | ||
496 | (name) ? name : "<unknown>", event_data, err); | ||
497 | return; | ||
498 | } | ||
499 | EXPORT_SYMBOL(fc_host_post_event); | ||
500 | |||
501 | |||
502 | /** | ||
503 | * fc_host_post_vendor_event - called to post a vendor unique event on | ||
504 | * a fc_host | ||
505 | * | ||
506 | * @shost: host the event occurred on | ||
507 | * @event_number: fc event number obtained from get_fc_event_number() | ||
508 | * @data_len: amount, in bytes, of vendor unique data | ||
509 | * @data_buf: pointer to vendor unique data | ||
510 | * | ||
511 | * Notes: | ||
512 | * This routine assumes no locks are held on entry. | ||
513 | **/ | ||
514 | void | ||
515 | fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, | ||
516 | u32 data_len, char * data_buf, u32 vendor_id) | ||
517 | { | ||
518 | struct sk_buff *skb; | ||
519 | struct nlmsghdr *nlh; | ||
520 | struct fc_nl_event *event; | ||
521 | u32 len, skblen; | ||
522 | int err; | ||
523 | |||
524 | if (!scsi_nl_sock) { | ||
525 | err = -ENOENT; | ||
526 | goto send_vendor_fail; | ||
527 | } | ||
528 | |||
529 | len = FC_NL_MSGALIGN(sizeof(*event) + data_len); | ||
530 | skblen = NLMSG_SPACE(len); | ||
531 | |||
532 | skb = alloc_skb(skblen, GFP_KERNEL); | ||
533 | if (!skb) { | ||
534 | err = -ENOBUFS; | ||
535 | goto send_vendor_fail; | ||
536 | } | ||
537 | |||
538 | nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, | ||
539 | skblen - sizeof(*nlh), 0); | ||
540 | if (!nlh) { | ||
541 | err = -ENOBUFS; | ||
542 | goto send_vendor_fail_skb; | ||
543 | } | ||
544 | event = NLMSG_DATA(nlh); | ||
545 | |||
546 | INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, | ||
547 | FC_NL_ASYNC_EVENT, len); | ||
548 | event->seconds = get_seconds(); | ||
549 | event->vendor_id = vendor_id; | ||
550 | event->host_no = shost->host_no; | ||
551 | event->event_datalen = data_len; /* bytes */ | ||
552 | event->event_num = event_number; | ||
553 | event->event_code = FCH_EVT_VENDOR_UNIQUE; | ||
554 | memcpy(&event->event_data, data_buf, data_len); | ||
555 | |||
556 | err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS); | ||
557 | if (err && (err != -ESRCH)) /* filter no recipient errors */ | ||
558 | /* nlmsg_multicast already kfree_skb'd */ | ||
559 | goto send_vendor_fail; | ||
560 | |||
561 | return; | ||
562 | |||
563 | send_vendor_fail_skb: | ||
564 | kfree_skb(skb); | ||
565 | send_vendor_fail: | ||
566 | printk(KERN_WARNING | ||
567 | "%s: Dropped Event : host %d vendor_unique - err %d\n", | ||
568 | __FUNCTION__, shost->host_no, err); | ||
569 | return; | ||
570 | } | ||
571 | EXPORT_SYMBOL(fc_host_post_vendor_event); | ||
572 | |||
573 | |||
380 | 574 | ||
381 | static __init int fc_transport_init(void) | 575 | static __init int fc_transport_init(void) |
382 | { | 576 | { |
383 | int error = transport_class_register(&fc_host_class); | 577 | int error; |
578 | |||
579 | atomic_set(&fc_event_seq, 0); | ||
580 | |||
581 | error = transport_class_register(&fc_host_class); | ||
384 | if (error) | 582 | if (error) |
385 | return error; | 583 | return error; |
386 | error = transport_class_register(&fc_rport_class); | 584 | error = transport_class_register(&fc_rport_class); |