scsi_netlink.c revision 25985edcedea6396277003854657b5f3cb31a628
184314fd4740ad73550c76dee4a9578979d84af48James Smart/* 284314fd4740ad73550c76dee4a9578979d84af48James Smart * scsi_netlink.c - SCSI Transport Netlink Interface 384314fd4740ad73550c76dee4a9578979d84af48James Smart * 484314fd4740ad73550c76dee4a9578979d84af48James Smart * Copyright (C) 2006 James Smart, Emulex Corporation 584314fd4740ad73550c76dee4a9578979d84af48James Smart * 684314fd4740ad73550c76dee4a9578979d84af48James Smart * This program is free software; you can redistribute it and/or modify 784314fd4740ad73550c76dee4a9578979d84af48James Smart * it under the terms of the GNU General Public License as published by 884314fd4740ad73550c76dee4a9578979d84af48James Smart * the Free Software Foundation; either version 2 of the License, or 984314fd4740ad73550c76dee4a9578979d84af48James Smart * (at your option) any later version. 1084314fd4740ad73550c76dee4a9578979d84af48James Smart * 1184314fd4740ad73550c76dee4a9578979d84af48James Smart * This program is distributed in the hope that it will be useful, 1284314fd4740ad73550c76dee4a9578979d84af48James Smart * but WITHOUT ANY WARRANTY; without even the implied warranty of 1384314fd4740ad73550c76dee4a9578979d84af48James Smart * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1484314fd4740ad73550c76dee4a9578979d84af48James Smart * GNU General Public License for more details. 1584314fd4740ad73550c76dee4a9578979d84af48James Smart * 1684314fd4740ad73550c76dee4a9578979d84af48James Smart * You should have received a copy of the GNU General Public License 1784314fd4740ad73550c76dee4a9578979d84af48James Smart * along with this program; if not, write to the Free Software 1884314fd4740ad73550c76dee4a9578979d84af48James Smart * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1984314fd4740ad73550c76dee4a9578979d84af48James Smart * 2084314fd4740ad73550c76dee4a9578979d84af48James Smart */ 2184314fd4740ad73550c76dee4a9578979d84af48James Smart#include <linux/time.h> 2284314fd4740ad73550c76dee4a9578979d84af48James Smart#include <linux/jiffies.h> 2384314fd4740ad73550c76dee4a9578979d84af48James Smart#include <linux/security.h> 2422447be7d15aefcfab84e9bec4859a28198b0c62James Smart#include <linux/delay.h> 255a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 2684314fd4740ad73550c76dee4a9578979d84af48James Smart#include <net/sock.h> 2784314fd4740ad73550c76dee4a9578979d84af48James Smart#include <net/netlink.h> 2884314fd4740ad73550c76dee4a9578979d84af48James Smart 2984314fd4740ad73550c76dee4a9578979d84af48James Smart#include <scsi/scsi_netlink.h> 3084314fd4740ad73550c76dee4a9578979d84af48James Smart#include "scsi_priv.h" 3184314fd4740ad73550c76dee4a9578979d84af48James Smart 3284314fd4740ad73550c76dee4a9578979d84af48James Smartstruct sock *scsi_nl_sock = NULL; 3384314fd4740ad73550c76dee4a9578979d84af48James SmartEXPORT_SYMBOL_GPL(scsi_nl_sock); 3484314fd4740ad73550c76dee4a9578979d84af48James Smart 3522447be7d15aefcfab84e9bec4859a28198b0c62James Smartstatic DEFINE_SPINLOCK(scsi_nl_lock); 3622447be7d15aefcfab84e9bec4859a28198b0c62James Smartstatic struct list_head scsi_nl_drivers; 3722447be7d15aefcfab84e9bec4859a28198b0c62James Smart 3822447be7d15aefcfab84e9bec4859a28198b0c62James Smartstatic u32 scsi_nl_state; 3922447be7d15aefcfab84e9bec4859a28198b0c62James Smart#define STATE_EHANDLER_BSY 0x00000001 4022447be7d15aefcfab84e9bec4859a28198b0c62James Smart 4122447be7d15aefcfab84e9bec4859a28198b0c62James Smartstruct scsi_nl_transport { 4222447be7d15aefcfab84e9bec4859a28198b0c62James Smart int (*msg_handler)(struct sk_buff *); 4322447be7d15aefcfab84e9bec4859a28198b0c62James Smart void (*event_handler)(struct notifier_block *, unsigned long, void *); 4422447be7d15aefcfab84e9bec4859a28198b0c62James Smart unsigned int refcnt; 4522447be7d15aefcfab84e9bec4859a28198b0c62James Smart int flags; 4622447be7d15aefcfab84e9bec4859a28198b0c62James Smart}; 4722447be7d15aefcfab84e9bec4859a28198b0c62James Smart 4822447be7d15aefcfab84e9bec4859a28198b0c62James Smart/* flags values (bit flags) */ 4922447be7d15aefcfab84e9bec4859a28198b0c62James Smart#define HANDLER_DELETING 0x1 5022447be7d15aefcfab84e9bec4859a28198b0c62James Smart 5122447be7d15aefcfab84e9bec4859a28198b0c62James Smartstatic struct scsi_nl_transport transports[SCSI_NL_MAX_TRANSPORTS] = 5222447be7d15aefcfab84e9bec4859a28198b0c62James Smart { {NULL, }, }; 5322447be7d15aefcfab84e9bec4859a28198b0c62James Smart 5422447be7d15aefcfab84e9bec4859a28198b0c62James Smart 5522447be7d15aefcfab84e9bec4859a28198b0c62James Smartstruct scsi_nl_drvr { 5622447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct list_head next; 5722447be7d15aefcfab84e9bec4859a28198b0c62James Smart int (*dmsg_handler)(struct Scsi_Host *shost, void *payload, 5822447be7d15aefcfab84e9bec4859a28198b0c62James Smart u32 len, u32 pid); 5922447be7d15aefcfab84e9bec4859a28198b0c62James Smart void (*devt_handler)(struct notifier_block *nb, 6022447be7d15aefcfab84e9bec4859a28198b0c62James Smart unsigned long event, void *notify_ptr); 6122447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct scsi_host_template *hostt; 6222447be7d15aefcfab84e9bec4859a28198b0c62James Smart u64 vendor_id; 6322447be7d15aefcfab84e9bec4859a28198b0c62James Smart unsigned int refcnt; 6422447be7d15aefcfab84e9bec4859a28198b0c62James Smart int flags; 6522447be7d15aefcfab84e9bec4859a28198b0c62James Smart}; 6622447be7d15aefcfab84e9bec4859a28198b0c62James Smart 6722447be7d15aefcfab84e9bec4859a28198b0c62James Smart 6884314fd4740ad73550c76dee4a9578979d84af48James Smart 6984314fd4740ad73550c76dee4a9578979d84af48James Smart/** 70eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * scsi_nl_rcv_msg - Receive message handler. 71eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * @skb: socket receive buffer 72eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * 73eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * Description: Extracts message from a receive buffer. 7484314fd4740ad73550c76dee4a9578979d84af48James Smart * Validates message header and calls appropriate transport message handler 7584314fd4740ad73550c76dee4a9578979d84af48James Smart * 7684314fd4740ad73550c76dee4a9578979d84af48James Smart * 7784314fd4740ad73550c76dee4a9578979d84af48James Smart **/ 7884314fd4740ad73550c76dee4a9578979d84af48James Smartstatic void 7984314fd4740ad73550c76dee4a9578979d84af48James Smartscsi_nl_rcv_msg(struct sk_buff *skb) 8084314fd4740ad73550c76dee4a9578979d84af48James Smart{ 8184314fd4740ad73550c76dee4a9578979d84af48James Smart struct nlmsghdr *nlh; 8284314fd4740ad73550c76dee4a9578979d84af48James Smart struct scsi_nl_hdr *hdr; 8322447be7d15aefcfab84e9bec4859a28198b0c62James Smart unsigned long flags; 8422447be7d15aefcfab84e9bec4859a28198b0c62James Smart u32 rlen; 8522447be7d15aefcfab84e9bec4859a28198b0c62James Smart int err, tport; 8684314fd4740ad73550c76dee4a9578979d84af48James Smart 8784314fd4740ad73550c76dee4a9578979d84af48James Smart while (skb->len >= NLMSG_SPACE(0)) { 8884314fd4740ad73550c76dee4a9578979d84af48James Smart err = 0; 8984314fd4740ad73550c76dee4a9578979d84af48James Smart 90b529ccf2799c14346d1518e9bdf1f88f03643e99Arnaldo Carvalho de Melo nlh = nlmsg_hdr(skb); 9184314fd4740ad73550c76dee4a9578979d84af48James Smart if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) || 9284314fd4740ad73550c76dee4a9578979d84af48James Smart (skb->len < nlh->nlmsg_len)) { 9384314fd4740ad73550c76dee4a9578979d84af48James Smart printk(KERN_WARNING "%s: discarding partial skb\n", 94cadbd4a5e36dde7e6c49b587b2c419103c0b7218Harvey Harrison __func__); 9584314fd4740ad73550c76dee4a9578979d84af48James Smart return; 9684314fd4740ad73550c76dee4a9578979d84af48James Smart } 9784314fd4740ad73550c76dee4a9578979d84af48James Smart 9884314fd4740ad73550c76dee4a9578979d84af48James Smart rlen = NLMSG_ALIGN(nlh->nlmsg_len); 9984314fd4740ad73550c76dee4a9578979d84af48James Smart if (rlen > skb->len) 10084314fd4740ad73550c76dee4a9578979d84af48James Smart rlen = skb->len; 10184314fd4740ad73550c76dee4a9578979d84af48James Smart 10284314fd4740ad73550c76dee4a9578979d84af48James Smart if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) { 10384314fd4740ad73550c76dee4a9578979d84af48James Smart err = -EBADMSG; 10422447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto next_msg; 10584314fd4740ad73550c76dee4a9578979d84af48James Smart } 10684314fd4740ad73550c76dee4a9578979d84af48James Smart 10784314fd4740ad73550c76dee4a9578979d84af48James Smart hdr = NLMSG_DATA(nlh); 10884314fd4740ad73550c76dee4a9578979d84af48James Smart if ((hdr->version != SCSI_NL_VERSION) || 10984314fd4740ad73550c76dee4a9578979d84af48James Smart (hdr->magic != SCSI_NL_MAGIC)) { 11084314fd4740ad73550c76dee4a9578979d84af48James Smart err = -EPROTOTYPE; 11184314fd4740ad73550c76dee4a9578979d84af48James Smart goto next_msg; 11284314fd4740ad73550c76dee4a9578979d84af48James Smart } 11384314fd4740ad73550c76dee4a9578979d84af48James Smart 11484314fd4740ad73550c76dee4a9578979d84af48James Smart if (security_netlink_recv(skb, CAP_SYS_ADMIN)) { 11584314fd4740ad73550c76dee4a9578979d84af48James Smart err = -EPERM; 11684314fd4740ad73550c76dee4a9578979d84af48James Smart goto next_msg; 11784314fd4740ad73550c76dee4a9578979d84af48James Smart } 11884314fd4740ad73550c76dee4a9578979d84af48James Smart 11984314fd4740ad73550c76dee4a9578979d84af48James Smart if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) { 12084314fd4740ad73550c76dee4a9578979d84af48James Smart printk(KERN_WARNING "%s: discarding partial message\n", 121cadbd4a5e36dde7e6c49b587b2c419103c0b7218Harvey Harrison __func__); 12222447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto next_msg; 12384314fd4740ad73550c76dee4a9578979d84af48James Smart } 12484314fd4740ad73550c76dee4a9578979d84af48James Smart 12584314fd4740ad73550c76dee4a9578979d84af48James Smart /* 12622447be7d15aefcfab84e9bec4859a28198b0c62James Smart * Deliver message to the appropriate transport 12784314fd4740ad73550c76dee4a9578979d84af48James Smart */ 12822447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 12922447be7d15aefcfab84e9bec4859a28198b0c62James Smart 13022447be7d15aefcfab84e9bec4859a28198b0c62James Smart tport = hdr->transport; 13122447be7d15aefcfab84e9bec4859a28198b0c62James Smart if ((tport < SCSI_NL_MAX_TRANSPORTS) && 13222447be7d15aefcfab84e9bec4859a28198b0c62James Smart !(transports[tport].flags & HANDLER_DELETING) && 13322447be7d15aefcfab84e9bec4859a28198b0c62James Smart (transports[tport].msg_handler)) { 13422447be7d15aefcfab84e9bec4859a28198b0c62James Smart transports[tport].refcnt++; 13522447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 13622447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = transports[tport].msg_handler(skb); 13722447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 13822447be7d15aefcfab84e9bec4859a28198b0c62James Smart transports[tport].refcnt--; 13922447be7d15aefcfab84e9bec4859a28198b0c62James Smart } else 14022447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -ENOENT; 14122447be7d15aefcfab84e9bec4859a28198b0c62James Smart 14222447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 14384314fd4740ad73550c76dee4a9578979d84af48James Smart 14484314fd4740ad73550c76dee4a9578979d84af48James Smartnext_msg: 14584314fd4740ad73550c76dee4a9578979d84af48James Smart if ((err) || (nlh->nlmsg_flags & NLM_F_ACK)) 14684314fd4740ad73550c76dee4a9578979d84af48James Smart netlink_ack(skb, nlh, err); 14784314fd4740ad73550c76dee4a9578979d84af48James Smart 14884314fd4740ad73550c76dee4a9578979d84af48James Smart skb_pull(skb, rlen); 14984314fd4740ad73550c76dee4a9578979d84af48James Smart } 15084314fd4740ad73550c76dee4a9578979d84af48James Smart} 15184314fd4740ad73550c76dee4a9578979d84af48James Smart 15284314fd4740ad73550c76dee4a9578979d84af48James Smart 15384314fd4740ad73550c76dee4a9578979d84af48James Smart/** 154eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * scsi_nl_rcv_event - Event handler for a netlink socket. 15584314fd4740ad73550c76dee4a9578979d84af48James Smart * @this: event notifier block 15684314fd4740ad73550c76dee4a9578979d84af48James Smart * @event: event type 15784314fd4740ad73550c76dee4a9578979d84af48James Smart * @ptr: event payload 15884314fd4740ad73550c76dee4a9578979d84af48James Smart * 15984314fd4740ad73550c76dee4a9578979d84af48James Smart **/ 16084314fd4740ad73550c76dee4a9578979d84af48James Smartstatic int 16184314fd4740ad73550c76dee4a9578979d84af48James Smartscsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr) 16284314fd4740ad73550c76dee4a9578979d84af48James Smart{ 16384314fd4740ad73550c76dee4a9578979d84af48James Smart struct netlink_notify *n = ptr; 16422447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct scsi_nl_drvr *driver; 16522447be7d15aefcfab84e9bec4859a28198b0c62James Smart unsigned long flags; 16622447be7d15aefcfab84e9bec4859a28198b0c62James Smart int tport; 16784314fd4740ad73550c76dee4a9578979d84af48James Smart 16884314fd4740ad73550c76dee4a9578979d84af48James Smart if (n->protocol != NETLINK_SCSITRANSPORT) 16984314fd4740ad73550c76dee4a9578979d84af48James Smart return NOTIFY_DONE; 17084314fd4740ad73550c76dee4a9578979d84af48James Smart 17122447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 17222447be7d15aefcfab84e9bec4859a28198b0c62James Smart scsi_nl_state |= STATE_EHANDLER_BSY; 17322447be7d15aefcfab84e9bec4859a28198b0c62James Smart 17484314fd4740ad73550c76dee4a9578979d84af48James Smart /* 17522447be7d15aefcfab84e9bec4859a28198b0c62James Smart * Pass event on to any transports that may be listening 17684314fd4740ad73550c76dee4a9578979d84af48James Smart */ 17722447be7d15aefcfab84e9bec4859a28198b0c62James Smart for (tport = 0; tport < SCSI_NL_MAX_TRANSPORTS; tport++) { 17822447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (!(transports[tport].flags & HANDLER_DELETING) && 17922447be7d15aefcfab84e9bec4859a28198b0c62James Smart (transports[tport].event_handler)) { 18022447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 18122447be7d15aefcfab84e9bec4859a28198b0c62James Smart transports[tport].event_handler(this, event, ptr); 18222447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 18322447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 18422447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 18522447be7d15aefcfab84e9bec4859a28198b0c62James Smart 18622447be7d15aefcfab84e9bec4859a28198b0c62James Smart /* 18722447be7d15aefcfab84e9bec4859a28198b0c62James Smart * Pass event on to any drivers that may be listening 18822447be7d15aefcfab84e9bec4859a28198b0c62James Smart */ 18922447be7d15aefcfab84e9bec4859a28198b0c62James Smart list_for_each_entry(driver, &scsi_nl_drivers, next) { 19022447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (!(driver->flags & HANDLER_DELETING) && 19122447be7d15aefcfab84e9bec4859a28198b0c62James Smart (driver->devt_handler)) { 19222447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 19322447be7d15aefcfab84e9bec4859a28198b0c62James Smart driver->devt_handler(this, event, ptr); 19422447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 19522447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 19622447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 19722447be7d15aefcfab84e9bec4859a28198b0c62James Smart 19822447be7d15aefcfab84e9bec4859a28198b0c62James Smart scsi_nl_state &= ~STATE_EHANDLER_BSY; 19922447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 20084314fd4740ad73550c76dee4a9578979d84af48James Smart 20184314fd4740ad73550c76dee4a9578979d84af48James Smart return NOTIFY_DONE; 20284314fd4740ad73550c76dee4a9578979d84af48James Smart} 20384314fd4740ad73550c76dee4a9578979d84af48James Smart 20484314fd4740ad73550c76dee4a9578979d84af48James Smartstatic struct notifier_block scsi_netlink_notifier = { 20584314fd4740ad73550c76dee4a9578979d84af48James Smart .notifier_call = scsi_nl_rcv_event, 20684314fd4740ad73550c76dee4a9578979d84af48James Smart}; 20784314fd4740ad73550c76dee4a9578979d84af48James Smart 20884314fd4740ad73550c76dee4a9578979d84af48James Smart 209aa198bf1dadefaefeb2c4a32444dfc6c7f93938dRandy Dunlap/* 21022447be7d15aefcfab84e9bec4859a28198b0c62James Smart * GENERIC SCSI transport receive and event handlers 211aa198bf1dadefaefeb2c4a32444dfc6c7f93938dRandy Dunlap */ 21222447be7d15aefcfab84e9bec4859a28198b0c62James Smart 21322447be7d15aefcfab84e9bec4859a28198b0c62James Smart/** 214aa198bf1dadefaefeb2c4a32444dfc6c7f93938dRandy Dunlap * scsi_generic_msg_handler - receive message handler for GENERIC transport messages 21522447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @skb: socket receive buffer 21622447be7d15aefcfab84e9bec4859a28198b0c62James Smart **/ 21722447be7d15aefcfab84e9bec4859a28198b0c62James Smartstatic int 21822447be7d15aefcfab84e9bec4859a28198b0c62James Smartscsi_generic_msg_handler(struct sk_buff *skb) 21922447be7d15aefcfab84e9bec4859a28198b0c62James Smart{ 22022447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct nlmsghdr *nlh = nlmsg_hdr(skb); 22122447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct scsi_nl_hdr *snlh = NLMSG_DATA(nlh); 22222447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct scsi_nl_drvr *driver; 22322447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct Scsi_Host *shost; 22422447be7d15aefcfab84e9bec4859a28198b0c62James Smart unsigned long flags; 22522447be7d15aefcfab84e9bec4859a28198b0c62James Smart int err = 0, match, pid; 22622447be7d15aefcfab84e9bec4859a28198b0c62James Smart 22722447be7d15aefcfab84e9bec4859a28198b0c62James Smart pid = NETLINK_CREDS(skb)->pid; 22822447be7d15aefcfab84e9bec4859a28198b0c62James Smart 22922447be7d15aefcfab84e9bec4859a28198b0c62James Smart switch (snlh->msgtype) { 23022447be7d15aefcfab84e9bec4859a28198b0c62James Smart case SCSI_NL_SHOST_VENDOR: 23122447be7d15aefcfab84e9bec4859a28198b0c62James Smart { 23222447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct scsi_nl_host_vendor_msg *msg = NLMSG_DATA(nlh); 23322447be7d15aefcfab84e9bec4859a28198b0c62James Smart 23422447be7d15aefcfab84e9bec4859a28198b0c62James Smart /* Locate the driver that corresponds to the message */ 23522447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 23622447be7d15aefcfab84e9bec4859a28198b0c62James Smart match = 0; 23722447be7d15aefcfab84e9bec4859a28198b0c62James Smart list_for_each_entry(driver, &scsi_nl_drivers, next) { 23822447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (driver->vendor_id == msg->vendor_id) { 23922447be7d15aefcfab84e9bec4859a28198b0c62James Smart match = 1; 24022447be7d15aefcfab84e9bec4859a28198b0c62James Smart break; 24122447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 24222447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 24322447be7d15aefcfab84e9bec4859a28198b0c62James Smart 24422447be7d15aefcfab84e9bec4859a28198b0c62James Smart if ((!match) || (!driver->dmsg_handler)) { 24522447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 24622447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -ESRCH; 24722447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto rcv_exit; 24822447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 24922447be7d15aefcfab84e9bec4859a28198b0c62James Smart 25022447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (driver->flags & HANDLER_DELETING) { 25122447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 25222447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -ESHUTDOWN; 25322447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto rcv_exit; 25422447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 25522447be7d15aefcfab84e9bec4859a28198b0c62James Smart 25622447be7d15aefcfab84e9bec4859a28198b0c62James Smart driver->refcnt++; 25722447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 25822447be7d15aefcfab84e9bec4859a28198b0c62James Smart 25922447be7d15aefcfab84e9bec4859a28198b0c62James Smart 26022447be7d15aefcfab84e9bec4859a28198b0c62James Smart /* if successful, scsi_host_lookup takes a shost reference */ 26122447be7d15aefcfab84e9bec4859a28198b0c62James Smart shost = scsi_host_lookup(msg->host_no); 26222447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (!shost) { 26322447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -ENODEV; 26422447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto driver_exit; 26522447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 26622447be7d15aefcfab84e9bec4859a28198b0c62James Smart 26722447be7d15aefcfab84e9bec4859a28198b0c62James Smart /* is this host owned by the vendor ? */ 26822447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (shost->hostt != driver->hostt) { 26922447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -EINVAL; 27022447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto vendormsg_put; 27122447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 27222447be7d15aefcfab84e9bec4859a28198b0c62James Smart 27322447be7d15aefcfab84e9bec4859a28198b0c62James Smart /* pass message on to the driver */ 27422447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = driver->dmsg_handler(shost, (void *)&msg[1], 27522447be7d15aefcfab84e9bec4859a28198b0c62James Smart msg->vmsg_datalen, pid); 27622447be7d15aefcfab84e9bec4859a28198b0c62James Smart 27722447be7d15aefcfab84e9bec4859a28198b0c62James Smartvendormsg_put: 27822447be7d15aefcfab84e9bec4859a28198b0c62James Smart /* release reference by scsi_host_lookup */ 27922447be7d15aefcfab84e9bec4859a28198b0c62James Smart scsi_host_put(shost); 28022447be7d15aefcfab84e9bec4859a28198b0c62James Smart 28122447be7d15aefcfab84e9bec4859a28198b0c62James Smartdriver_exit: 28222447be7d15aefcfab84e9bec4859a28198b0c62James Smart /* release our own reference on the registration object */ 28322447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 28422447be7d15aefcfab84e9bec4859a28198b0c62James Smart driver->refcnt--; 28522447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 28622447be7d15aefcfab84e9bec4859a28198b0c62James Smart break; 28722447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 28822447be7d15aefcfab84e9bec4859a28198b0c62James Smart 28922447be7d15aefcfab84e9bec4859a28198b0c62James Smart default: 29022447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -EBADR; 29122447be7d15aefcfab84e9bec4859a28198b0c62James Smart break; 29222447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 29322447be7d15aefcfab84e9bec4859a28198b0c62James Smart 29422447be7d15aefcfab84e9bec4859a28198b0c62James Smartrcv_exit: 29522447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (err) 29622447be7d15aefcfab84e9bec4859a28198b0c62James Smart printk(KERN_WARNING "%s: Msgtype %d failed - err %d\n", 29722447be7d15aefcfab84e9bec4859a28198b0c62James Smart __func__, snlh->msgtype, err); 29822447be7d15aefcfab84e9bec4859a28198b0c62James Smart return err; 29922447be7d15aefcfab84e9bec4859a28198b0c62James Smart} 30022447be7d15aefcfab84e9bec4859a28198b0c62James Smart 30122447be7d15aefcfab84e9bec4859a28198b0c62James Smart 30222447be7d15aefcfab84e9bec4859a28198b0c62James Smart/** 30322447be7d15aefcfab84e9bec4859a28198b0c62James Smart * scsi_nl_add_transport - 30422447be7d15aefcfab84e9bec4859a28198b0c62James Smart * Registers message and event handlers for a transport. Enables 30522447be7d15aefcfab84e9bec4859a28198b0c62James Smart * receipt of netlink messages and events to a transport. 30622447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 30722447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @tport: transport registering handlers 30822447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @msg_handler: receive message handler callback 30922447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @event_handler: receive event handler callback 31022447be7d15aefcfab84e9bec4859a28198b0c62James Smart **/ 31122447be7d15aefcfab84e9bec4859a28198b0c62James Smartint 31222447be7d15aefcfab84e9bec4859a28198b0c62James Smartscsi_nl_add_transport(u8 tport, 31322447be7d15aefcfab84e9bec4859a28198b0c62James Smart int (*msg_handler)(struct sk_buff *), 31422447be7d15aefcfab84e9bec4859a28198b0c62James Smart void (*event_handler)(struct notifier_block *, unsigned long, void *)) 31522447be7d15aefcfab84e9bec4859a28198b0c62James Smart{ 31622447be7d15aefcfab84e9bec4859a28198b0c62James Smart unsigned long flags; 31722447be7d15aefcfab84e9bec4859a28198b0c62James Smart int err = 0; 31822447be7d15aefcfab84e9bec4859a28198b0c62James Smart 31922447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (tport >= SCSI_NL_MAX_TRANSPORTS) 32022447be7d15aefcfab84e9bec4859a28198b0c62James Smart return -EINVAL; 32122447be7d15aefcfab84e9bec4859a28198b0c62James Smart 32222447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 32322447be7d15aefcfab84e9bec4859a28198b0c62James Smart 32422447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (scsi_nl_state & STATE_EHANDLER_BSY) { 32522447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 32622447be7d15aefcfab84e9bec4859a28198b0c62James Smart msleep(1); 32722447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 32822447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 32922447be7d15aefcfab84e9bec4859a28198b0c62James Smart 33022447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (transports[tport].msg_handler || transports[tport].event_handler) { 33122447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -EALREADY; 33222447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto register_out; 33322447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 33422447be7d15aefcfab84e9bec4859a28198b0c62James Smart 33522447be7d15aefcfab84e9bec4859a28198b0c62James Smart transports[tport].msg_handler = msg_handler; 33622447be7d15aefcfab84e9bec4859a28198b0c62James Smart transports[tport].event_handler = event_handler; 33722447be7d15aefcfab84e9bec4859a28198b0c62James Smart transports[tport].flags = 0; 33822447be7d15aefcfab84e9bec4859a28198b0c62James Smart transports[tport].refcnt = 0; 33922447be7d15aefcfab84e9bec4859a28198b0c62James Smart 34022447be7d15aefcfab84e9bec4859a28198b0c62James Smartregister_out: 34122447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 34222447be7d15aefcfab84e9bec4859a28198b0c62James Smart 34322447be7d15aefcfab84e9bec4859a28198b0c62James Smart return err; 34422447be7d15aefcfab84e9bec4859a28198b0c62James Smart} 34522447be7d15aefcfab84e9bec4859a28198b0c62James SmartEXPORT_SYMBOL_GPL(scsi_nl_add_transport); 34622447be7d15aefcfab84e9bec4859a28198b0c62James Smart 34722447be7d15aefcfab84e9bec4859a28198b0c62James Smart 34822447be7d15aefcfab84e9bec4859a28198b0c62James Smart/** 34922447be7d15aefcfab84e9bec4859a28198b0c62James Smart * scsi_nl_remove_transport - 35022447be7d15aefcfab84e9bec4859a28198b0c62James Smart * Disable transport receiption of messages and events 35122447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 35222447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @tport: transport deregistering handlers 35322447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 35422447be7d15aefcfab84e9bec4859a28198b0c62James Smart **/ 35522447be7d15aefcfab84e9bec4859a28198b0c62James Smartvoid 35622447be7d15aefcfab84e9bec4859a28198b0c62James Smartscsi_nl_remove_transport(u8 tport) 35722447be7d15aefcfab84e9bec4859a28198b0c62James Smart{ 35822447be7d15aefcfab84e9bec4859a28198b0c62James Smart unsigned long flags; 35922447be7d15aefcfab84e9bec4859a28198b0c62James Smart 36022447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 36122447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (scsi_nl_state & STATE_EHANDLER_BSY) { 36222447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 36322447be7d15aefcfab84e9bec4859a28198b0c62James Smart msleep(1); 36422447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 36522447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 36622447be7d15aefcfab84e9bec4859a28198b0c62James Smart 36722447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (tport < SCSI_NL_MAX_TRANSPORTS) { 36822447be7d15aefcfab84e9bec4859a28198b0c62James Smart transports[tport].flags |= HANDLER_DELETING; 36922447be7d15aefcfab84e9bec4859a28198b0c62James Smart 37022447be7d15aefcfab84e9bec4859a28198b0c62James Smart while (transports[tport].refcnt != 0) { 37122447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 37222447be7d15aefcfab84e9bec4859a28198b0c62James Smart schedule_timeout_uninterruptible(HZ/4); 37322447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 37422447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 37522447be7d15aefcfab84e9bec4859a28198b0c62James Smart transports[tport].msg_handler = NULL; 37622447be7d15aefcfab84e9bec4859a28198b0c62James Smart transports[tport].event_handler = NULL; 37722447be7d15aefcfab84e9bec4859a28198b0c62James Smart transports[tport].flags = 0; 37822447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 37922447be7d15aefcfab84e9bec4859a28198b0c62James Smart 38022447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 38122447be7d15aefcfab84e9bec4859a28198b0c62James Smart 38222447be7d15aefcfab84e9bec4859a28198b0c62James Smart return; 38322447be7d15aefcfab84e9bec4859a28198b0c62James Smart} 38422447be7d15aefcfab84e9bec4859a28198b0c62James SmartEXPORT_SYMBOL_GPL(scsi_nl_remove_transport); 38522447be7d15aefcfab84e9bec4859a28198b0c62James Smart 38622447be7d15aefcfab84e9bec4859a28198b0c62James Smart 38722447be7d15aefcfab84e9bec4859a28198b0c62James Smart/** 38822447be7d15aefcfab84e9bec4859a28198b0c62James Smart * scsi_nl_add_driver - 38922447be7d15aefcfab84e9bec4859a28198b0c62James Smart * A driver is registering its interfaces for SCSI netlink messages 39022447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 39122447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @vendor_id: A unique identification value for the driver. 39222447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @hostt: address of the driver's host template. Used 39322447be7d15aefcfab84e9bec4859a28198b0c62James Smart * to verify an shost is bound to the driver 39422447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @nlmsg_handler: receive message handler callback 39522447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @nlevt_handler: receive event handler callback 39622447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 39722447be7d15aefcfab84e9bec4859a28198b0c62James Smart * Returns: 39822447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 0 on Success 39922447be7d15aefcfab84e9bec4859a28198b0c62James Smart * error result otherwise 40022447be7d15aefcfab84e9bec4859a28198b0c62James Smart **/ 40122447be7d15aefcfab84e9bec4859a28198b0c62James Smartint 40222447be7d15aefcfab84e9bec4859a28198b0c62James Smartscsi_nl_add_driver(u64 vendor_id, struct scsi_host_template *hostt, 40322447be7d15aefcfab84e9bec4859a28198b0c62James Smart int (*nlmsg_handler)(struct Scsi_Host *shost, void *payload, 40422447be7d15aefcfab84e9bec4859a28198b0c62James Smart u32 len, u32 pid), 40522447be7d15aefcfab84e9bec4859a28198b0c62James Smart void (*nlevt_handler)(struct notifier_block *nb, 40622447be7d15aefcfab84e9bec4859a28198b0c62James Smart unsigned long event, void *notify_ptr)) 40722447be7d15aefcfab84e9bec4859a28198b0c62James Smart{ 40822447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct scsi_nl_drvr *driver; 40922447be7d15aefcfab84e9bec4859a28198b0c62James Smart unsigned long flags; 41022447be7d15aefcfab84e9bec4859a28198b0c62James Smart 41122447be7d15aefcfab84e9bec4859a28198b0c62James Smart driver = kzalloc(sizeof(*driver), GFP_KERNEL); 41222447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (unlikely(!driver)) { 41322447be7d15aefcfab84e9bec4859a28198b0c62James Smart printk(KERN_ERR "%s: allocation failure\n", __func__); 41422447be7d15aefcfab84e9bec4859a28198b0c62James Smart return -ENOMEM; 41522447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 41622447be7d15aefcfab84e9bec4859a28198b0c62James Smart 41722447be7d15aefcfab84e9bec4859a28198b0c62James Smart driver->dmsg_handler = nlmsg_handler; 41822447be7d15aefcfab84e9bec4859a28198b0c62James Smart driver->devt_handler = nlevt_handler; 41922447be7d15aefcfab84e9bec4859a28198b0c62James Smart driver->hostt = hostt; 42022447be7d15aefcfab84e9bec4859a28198b0c62James Smart driver->vendor_id = vendor_id; 42122447be7d15aefcfab84e9bec4859a28198b0c62James Smart 42222447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 42322447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (scsi_nl_state & STATE_EHANDLER_BSY) { 42422447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 42522447be7d15aefcfab84e9bec4859a28198b0c62James Smart msleep(1); 42622447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 42722447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 42822447be7d15aefcfab84e9bec4859a28198b0c62James Smart list_add_tail(&driver->next, &scsi_nl_drivers); 42922447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 43022447be7d15aefcfab84e9bec4859a28198b0c62James Smart 43122447be7d15aefcfab84e9bec4859a28198b0c62James Smart return 0; 43222447be7d15aefcfab84e9bec4859a28198b0c62James Smart} 43322447be7d15aefcfab84e9bec4859a28198b0c62James SmartEXPORT_SYMBOL_GPL(scsi_nl_add_driver); 43422447be7d15aefcfab84e9bec4859a28198b0c62James Smart 43522447be7d15aefcfab84e9bec4859a28198b0c62James Smart 43622447be7d15aefcfab84e9bec4859a28198b0c62James Smart/** 43722447be7d15aefcfab84e9bec4859a28198b0c62James Smart * scsi_nl_remove_driver - 43822447be7d15aefcfab84e9bec4859a28198b0c62James Smart * An driver is unregistering with the SCSI netlink messages 43922447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 44022447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @vendor_id: The unique identification value for the driver. 44122447be7d15aefcfab84e9bec4859a28198b0c62James Smart **/ 44222447be7d15aefcfab84e9bec4859a28198b0c62James Smartvoid 44322447be7d15aefcfab84e9bec4859a28198b0c62James Smartscsi_nl_remove_driver(u64 vendor_id) 44422447be7d15aefcfab84e9bec4859a28198b0c62James Smart{ 44522447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct scsi_nl_drvr *driver; 44622447be7d15aefcfab84e9bec4859a28198b0c62James Smart unsigned long flags; 44722447be7d15aefcfab84e9bec4859a28198b0c62James Smart 44822447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 44922447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (scsi_nl_state & STATE_EHANDLER_BSY) { 45022447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 45122447be7d15aefcfab84e9bec4859a28198b0c62James Smart msleep(1); 45222447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 45322447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 45422447be7d15aefcfab84e9bec4859a28198b0c62James Smart 45522447be7d15aefcfab84e9bec4859a28198b0c62James Smart list_for_each_entry(driver, &scsi_nl_drivers, next) { 45622447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (driver->vendor_id == vendor_id) { 45722447be7d15aefcfab84e9bec4859a28198b0c62James Smart driver->flags |= HANDLER_DELETING; 45822447be7d15aefcfab84e9bec4859a28198b0c62James Smart while (driver->refcnt != 0) { 45922447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 46022447be7d15aefcfab84e9bec4859a28198b0c62James Smart schedule_timeout_uninterruptible(HZ/4); 46122447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_lock_irqsave(&scsi_nl_lock, flags); 46222447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 46322447be7d15aefcfab84e9bec4859a28198b0c62James Smart list_del(&driver->next); 46422447be7d15aefcfab84e9bec4859a28198b0c62James Smart kfree(driver); 46522447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 46622447be7d15aefcfab84e9bec4859a28198b0c62James Smart return; 46722447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 46822447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 46922447be7d15aefcfab84e9bec4859a28198b0c62James Smart 47022447be7d15aefcfab84e9bec4859a28198b0c62James Smart spin_unlock_irqrestore(&scsi_nl_lock, flags); 47122447be7d15aefcfab84e9bec4859a28198b0c62James Smart 47222447be7d15aefcfab84e9bec4859a28198b0c62James Smart printk(KERN_ERR "%s: removal of driver failed - vendor_id 0x%llx\n", 47322447be7d15aefcfab84e9bec4859a28198b0c62James Smart __func__, (unsigned long long)vendor_id); 47422447be7d15aefcfab84e9bec4859a28198b0c62James Smart return; 47522447be7d15aefcfab84e9bec4859a28198b0c62James Smart} 47622447be7d15aefcfab84e9bec4859a28198b0c62James SmartEXPORT_SYMBOL_GPL(scsi_nl_remove_driver); 47722447be7d15aefcfab84e9bec4859a28198b0c62James Smart 47822447be7d15aefcfab84e9bec4859a28198b0c62James Smart 47922447be7d15aefcfab84e9bec4859a28198b0c62James Smart/** 480b595076a180a56d1bb170e6eceda6eb9d76f4cd3Uwe Kleine-König * scsi_netlink_init - Called by SCSI subsystem to initialize 48122447be7d15aefcfab84e9bec4859a28198b0c62James Smart * the SCSI transport netlink interface 48284314fd4740ad73550c76dee4a9578979d84af48James Smart * 48384314fd4740ad73550c76dee4a9578979d84af48James Smart **/ 48484314fd4740ad73550c76dee4a9578979d84af48James Smartvoid 48584314fd4740ad73550c76dee4a9578979d84af48James Smartscsi_netlink_init(void) 48684314fd4740ad73550c76dee4a9578979d84af48James Smart{ 48784314fd4740ad73550c76dee4a9578979d84af48James Smart int error; 48884314fd4740ad73550c76dee4a9578979d84af48James Smart 48922447be7d15aefcfab84e9bec4859a28198b0c62James Smart INIT_LIST_HEAD(&scsi_nl_drivers); 49022447be7d15aefcfab84e9bec4859a28198b0c62James Smart 49184314fd4740ad73550c76dee4a9578979d84af48James Smart error = netlink_register_notifier(&scsi_netlink_notifier); 49284314fd4740ad73550c76dee4a9578979d84af48James Smart if (error) { 49384314fd4740ad73550c76dee4a9578979d84af48James Smart printk(KERN_ERR "%s: register of event handler failed - %d\n", 494cadbd4a5e36dde7e6c49b587b2c419103c0b7218Harvey Harrison __func__, error); 49584314fd4740ad73550c76dee4a9578979d84af48James Smart return; 49684314fd4740ad73550c76dee4a9578979d84af48James Smart } 49784314fd4740ad73550c76dee4a9578979d84af48James Smart 498b4b510290b056b86611757ce1175a230f1080f53Eric W. Biederman scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT, 499cd40b7d3983c708aabe3d3008ec64ffce56d33b0Denis V. Lunev SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL, 500af65bdfce98d7965fbe93a48b8128444a2eea024Patrick McHardy THIS_MODULE); 50184314fd4740ad73550c76dee4a9578979d84af48James Smart if (!scsi_nl_sock) { 50225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi printk(KERN_ERR "%s: register of receive handler failed\n", 503cadbd4a5e36dde7e6c49b587b2c419103c0b7218Harvey Harrison __func__); 50484314fd4740ad73550c76dee4a9578979d84af48James Smart netlink_unregister_notifier(&scsi_netlink_notifier); 50522447be7d15aefcfab84e9bec4859a28198b0c62James Smart return; 50684314fd4740ad73550c76dee4a9578979d84af48James Smart } 50784314fd4740ad73550c76dee4a9578979d84af48James Smart 50822447be7d15aefcfab84e9bec4859a28198b0c62James Smart /* Register the entry points for the generic SCSI transport */ 50922447be7d15aefcfab84e9bec4859a28198b0c62James Smart error = scsi_nl_add_transport(SCSI_NL_TRANSPORT, 51022447be7d15aefcfab84e9bec4859a28198b0c62James Smart scsi_generic_msg_handler, NULL); 51122447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (error) 51222447be7d15aefcfab84e9bec4859a28198b0c62James Smart printk(KERN_ERR "%s: register of GENERIC transport handler" 51322447be7d15aefcfab84e9bec4859a28198b0c62James Smart " failed - %d\n", __func__, error); 51484314fd4740ad73550c76dee4a9578979d84af48James Smart return; 51584314fd4740ad73550c76dee4a9578979d84af48James Smart} 51684314fd4740ad73550c76dee4a9578979d84af48James Smart 51784314fd4740ad73550c76dee4a9578979d84af48James Smart 51884314fd4740ad73550c76dee4a9578979d84af48James Smart/** 519eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface 52084314fd4740ad73550c76dee4a9578979d84af48James Smart * 52184314fd4740ad73550c76dee4a9578979d84af48James Smart **/ 52284314fd4740ad73550c76dee4a9578979d84af48James Smartvoid 52384314fd4740ad73550c76dee4a9578979d84af48James Smartscsi_netlink_exit(void) 52484314fd4740ad73550c76dee4a9578979d84af48James Smart{ 52522447be7d15aefcfab84e9bec4859a28198b0c62James Smart scsi_nl_remove_transport(SCSI_NL_TRANSPORT); 52622447be7d15aefcfab84e9bec4859a28198b0c62James Smart 52784314fd4740ad73550c76dee4a9578979d84af48James Smart if (scsi_nl_sock) { 528b7c6ba6eb1234e35a74fb8ba8123232a7b1ba9e4Denis V. Lunev netlink_kernel_release(scsi_nl_sock); 52984314fd4740ad73550c76dee4a9578979d84af48James Smart netlink_unregister_notifier(&scsi_netlink_notifier); 53084314fd4740ad73550c76dee4a9578979d84af48James Smart } 53184314fd4740ad73550c76dee4a9578979d84af48James Smart 53284314fd4740ad73550c76dee4a9578979d84af48James Smart return; 53384314fd4740ad73550c76dee4a9578979d84af48James Smart} 53484314fd4740ad73550c76dee4a9578979d84af48James Smart 53584314fd4740ad73550c76dee4a9578979d84af48James Smart 53622447be7d15aefcfab84e9bec4859a28198b0c62James Smart/* 53722447be7d15aefcfab84e9bec4859a28198b0c62James Smart * Exported Interfaces 53822447be7d15aefcfab84e9bec4859a28198b0c62James Smart */ 53922447be7d15aefcfab84e9bec4859a28198b0c62James Smart 54022447be7d15aefcfab84e9bec4859a28198b0c62James Smart/** 54122447be7d15aefcfab84e9bec4859a28198b0c62James Smart * scsi_nl_send_transport_msg - 54222447be7d15aefcfab84e9bec4859a28198b0c62James Smart * Generic function to send a single message from a SCSI transport to 54322447be7d15aefcfab84e9bec4859a28198b0c62James Smart * a single process 54422447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 54522447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @pid: receiving pid 54622447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @hdr: message payload 54722447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 54822447be7d15aefcfab84e9bec4859a28198b0c62James Smart **/ 54922447be7d15aefcfab84e9bec4859a28198b0c62James Smartvoid 55022447be7d15aefcfab84e9bec4859a28198b0c62James Smartscsi_nl_send_transport_msg(u32 pid, struct scsi_nl_hdr *hdr) 55122447be7d15aefcfab84e9bec4859a28198b0c62James Smart{ 55222447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct sk_buff *skb; 55322447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct nlmsghdr *nlh; 55422447be7d15aefcfab84e9bec4859a28198b0c62James Smart const char *fn; 55522447be7d15aefcfab84e9bec4859a28198b0c62James Smart char *datab; 55622447be7d15aefcfab84e9bec4859a28198b0c62James Smart u32 len, skblen; 55722447be7d15aefcfab84e9bec4859a28198b0c62James Smart int err; 55822447be7d15aefcfab84e9bec4859a28198b0c62James Smart 55922447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (!scsi_nl_sock) { 56022447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -ENOENT; 56122447be7d15aefcfab84e9bec4859a28198b0c62James Smart fn = "netlink socket"; 56222447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto msg_fail; 56322447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 56422447be7d15aefcfab84e9bec4859a28198b0c62James Smart 56522447be7d15aefcfab84e9bec4859a28198b0c62James Smart len = NLMSG_SPACE(hdr->msglen); 56622447be7d15aefcfab84e9bec4859a28198b0c62James Smart skblen = NLMSG_SPACE(len); 56722447be7d15aefcfab84e9bec4859a28198b0c62James Smart 56822447be7d15aefcfab84e9bec4859a28198b0c62James Smart skb = alloc_skb(skblen, GFP_KERNEL); 56922447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (!skb) { 57022447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -ENOBUFS; 57122447be7d15aefcfab84e9bec4859a28198b0c62James Smart fn = "alloc_skb"; 57222447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto msg_fail; 57322447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 57422447be7d15aefcfab84e9bec4859a28198b0c62James Smart 57522447be7d15aefcfab84e9bec4859a28198b0c62James Smart nlh = nlmsg_put(skb, pid, 0, SCSI_TRANSPORT_MSG, len - sizeof(*nlh), 0); 57622447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (!nlh) { 57722447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -ENOBUFS; 57822447be7d15aefcfab84e9bec4859a28198b0c62James Smart fn = "nlmsg_put"; 57922447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto msg_fail_skb; 58022447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 58122447be7d15aefcfab84e9bec4859a28198b0c62James Smart datab = NLMSG_DATA(nlh); 58222447be7d15aefcfab84e9bec4859a28198b0c62James Smart memcpy(datab, hdr, hdr->msglen); 58322447be7d15aefcfab84e9bec4859a28198b0c62James Smart 58422447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = nlmsg_unicast(scsi_nl_sock, skb, pid); 58522447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (err < 0) { 58622447be7d15aefcfab84e9bec4859a28198b0c62James Smart fn = "nlmsg_unicast"; 58722447be7d15aefcfab84e9bec4859a28198b0c62James Smart /* nlmsg_unicast already kfree_skb'd */ 58822447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto msg_fail; 58922447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 59022447be7d15aefcfab84e9bec4859a28198b0c62James Smart 59122447be7d15aefcfab84e9bec4859a28198b0c62James Smart return; 59222447be7d15aefcfab84e9bec4859a28198b0c62James Smart 59322447be7d15aefcfab84e9bec4859a28198b0c62James Smartmsg_fail_skb: 59422447be7d15aefcfab84e9bec4859a28198b0c62James Smart kfree_skb(skb); 59522447be7d15aefcfab84e9bec4859a28198b0c62James Smartmsg_fail: 59622447be7d15aefcfab84e9bec4859a28198b0c62James Smart printk(KERN_WARNING 59722447be7d15aefcfab84e9bec4859a28198b0c62James Smart "%s: Dropped Message : pid %d Transport %d, msgtype x%x, " 59822447be7d15aefcfab84e9bec4859a28198b0c62James Smart "msglen %d: %s : err %d\n", 59922447be7d15aefcfab84e9bec4859a28198b0c62James Smart __func__, pid, hdr->transport, hdr->msgtype, hdr->msglen, 60022447be7d15aefcfab84e9bec4859a28198b0c62James Smart fn, err); 60122447be7d15aefcfab84e9bec4859a28198b0c62James Smart return; 60222447be7d15aefcfab84e9bec4859a28198b0c62James Smart} 60322447be7d15aefcfab84e9bec4859a28198b0c62James SmartEXPORT_SYMBOL_GPL(scsi_nl_send_transport_msg); 60422447be7d15aefcfab84e9bec4859a28198b0c62James Smart 60522447be7d15aefcfab84e9bec4859a28198b0c62James Smart 60622447be7d15aefcfab84e9bec4859a28198b0c62James Smart/** 60722447be7d15aefcfab84e9bec4859a28198b0c62James Smart * scsi_nl_send_vendor_msg - called to send a shost vendor unique message 60822447be7d15aefcfab84e9bec4859a28198b0c62James Smart * to a specific process id. 60922447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 61022447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @pid: process id of the receiver 61122447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @host_no: host # sending the message 61222447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @vendor_id: unique identifier for the driver's vendor 61322447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @data_len: amount, in bytes, of vendor unique payload data 61422447be7d15aefcfab84e9bec4859a28198b0c62James Smart * @data_buf: pointer to vendor unique data buffer 61522447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 61622447be7d15aefcfab84e9bec4859a28198b0c62James Smart * Returns: 617af901ca181d92aac3a7dc265144a9081a86d8f39André Goddard Rosa * 0 on successful return 61822447be7d15aefcfab84e9bec4859a28198b0c62James Smart * otherwise, failing error code 61922447be7d15aefcfab84e9bec4859a28198b0c62James Smart * 62022447be7d15aefcfab84e9bec4859a28198b0c62James Smart * Notes: 62122447be7d15aefcfab84e9bec4859a28198b0c62James Smart * This routine assumes no locks are held on entry. 62222447be7d15aefcfab84e9bec4859a28198b0c62James Smart */ 62322447be7d15aefcfab84e9bec4859a28198b0c62James Smartint 62422447be7d15aefcfab84e9bec4859a28198b0c62James Smartscsi_nl_send_vendor_msg(u32 pid, unsigned short host_no, u64 vendor_id, 62522447be7d15aefcfab84e9bec4859a28198b0c62James Smart char *data_buf, u32 data_len) 62622447be7d15aefcfab84e9bec4859a28198b0c62James Smart{ 62722447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct sk_buff *skb; 62822447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct nlmsghdr *nlh; 62922447be7d15aefcfab84e9bec4859a28198b0c62James Smart struct scsi_nl_host_vendor_msg *msg; 63022447be7d15aefcfab84e9bec4859a28198b0c62James Smart u32 len, skblen; 63122447be7d15aefcfab84e9bec4859a28198b0c62James Smart int err; 63222447be7d15aefcfab84e9bec4859a28198b0c62James Smart 63322447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (!scsi_nl_sock) { 63422447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -ENOENT; 63522447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto send_vendor_fail; 63622447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 63722447be7d15aefcfab84e9bec4859a28198b0c62James Smart 63822447be7d15aefcfab84e9bec4859a28198b0c62James Smart len = SCSI_NL_MSGALIGN(sizeof(*msg) + data_len); 63922447be7d15aefcfab84e9bec4859a28198b0c62James Smart skblen = NLMSG_SPACE(len); 64022447be7d15aefcfab84e9bec4859a28198b0c62James Smart 64122447be7d15aefcfab84e9bec4859a28198b0c62James Smart skb = alloc_skb(skblen, GFP_KERNEL); 64222447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (!skb) { 64322447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -ENOBUFS; 64422447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto send_vendor_fail; 64522447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 64622447be7d15aefcfab84e9bec4859a28198b0c62James Smart 64722447be7d15aefcfab84e9bec4859a28198b0c62James Smart nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, 64822447be7d15aefcfab84e9bec4859a28198b0c62James Smart skblen - sizeof(*nlh), 0); 64922447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (!nlh) { 65022447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -ENOBUFS; 65122447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto send_vendor_fail_skb; 65222447be7d15aefcfab84e9bec4859a28198b0c62James Smart } 65322447be7d15aefcfab84e9bec4859a28198b0c62James Smart msg = NLMSG_DATA(nlh); 65422447be7d15aefcfab84e9bec4859a28198b0c62James Smart 65522447be7d15aefcfab84e9bec4859a28198b0c62James Smart INIT_SCSI_NL_HDR(&msg->snlh, SCSI_NL_TRANSPORT, 65622447be7d15aefcfab84e9bec4859a28198b0c62James Smart SCSI_NL_SHOST_VENDOR, len); 65722447be7d15aefcfab84e9bec4859a28198b0c62James Smart msg->vendor_id = vendor_id; 65822447be7d15aefcfab84e9bec4859a28198b0c62James Smart msg->host_no = host_no; 65922447be7d15aefcfab84e9bec4859a28198b0c62James Smart msg->vmsg_datalen = data_len; /* bytes */ 66022447be7d15aefcfab84e9bec4859a28198b0c62James Smart memcpy(&msg[1], data_buf, data_len); 66122447be7d15aefcfab84e9bec4859a28198b0c62James Smart 66222447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = nlmsg_unicast(scsi_nl_sock, skb, pid); 66322447be7d15aefcfab84e9bec4859a28198b0c62James Smart if (err) 66422447be7d15aefcfab84e9bec4859a28198b0c62James Smart /* nlmsg_multicast already kfree_skb'd */ 66522447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto send_vendor_fail; 66622447be7d15aefcfab84e9bec4859a28198b0c62James Smart 66722447be7d15aefcfab84e9bec4859a28198b0c62James Smart return 0; 66822447be7d15aefcfab84e9bec4859a28198b0c62James Smart 66922447be7d15aefcfab84e9bec4859a28198b0c62James Smartsend_vendor_fail_skb: 67022447be7d15aefcfab84e9bec4859a28198b0c62James Smart kfree_skb(skb); 67122447be7d15aefcfab84e9bec4859a28198b0c62James Smartsend_vendor_fail: 67222447be7d15aefcfab84e9bec4859a28198b0c62James Smart printk(KERN_WARNING 67322447be7d15aefcfab84e9bec4859a28198b0c62James Smart "%s: Dropped SCSI Msg : host %d vendor_unique - err %d\n", 67422447be7d15aefcfab84e9bec4859a28198b0c62James Smart __func__, host_no, err); 67522447be7d15aefcfab84e9bec4859a28198b0c62James Smart return err; 67622447be7d15aefcfab84e9bec4859a28198b0c62James Smart} 67722447be7d15aefcfab84e9bec4859a28198b0c62James SmartEXPORT_SYMBOL(scsi_nl_send_vendor_msg); 67822447be7d15aefcfab84e9bec4859a28198b0c62James Smart 67922447be7d15aefcfab84e9bec4859a28198b0c62James Smart 680