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