Subject: Netlink interface for SCSI sense codes
From: Hannes Reinecke <hare@suse.de>
Date: Fri Nov 21 10:08:01 2008 +0100:
Git: 97746dc5543ef9113c927022dc54ccd26915563d
Patch-mainline: not yet

Inform the userspace about SCSI sense codes; some of them
carry vital information where userspace should react to.

Signed-off-by: Hannes Reinecke <hare@suse.de>

---
 drivers/scsi/scsi_error.c      |   79 +++++++++++++++++++++++++++++++++++++++++
 include/scsi/scsi_netlink.h    |    6 ++-
 include/scsi/scsi_netlink_ml.h |   64 +++++++++++++++++++++++++++++++++
 3 files changed, 147 insertions(+), 2 deletions(-)

--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -25,6 +25,8 @@
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
+#include <linux/netlink.h>
+#include <net/netlink.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -34,6 +36,7 @@
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_netlink_ml.h>
 
 #include "scsi_priv.h"
 #include "scsi_logging.h"
@@ -218,6 +221,80 @@ static inline void scsi_eh_prt_fail_stat
 }
 #endif
 
+#ifdef CONFIG_SCSI_NETLINK
+/**
+ * scsi_post_sense_event - called to post a 'Sense Code' event
+ *
+ * @sdev:		SCSI device the sense code occured on
+ * @sshdr:		SCSI sense code
+ *
+ * Returns:
+ *   0 on succesful return
+ *   otherwise, failing error code
+ *
+ */
+static void scsi_post_sense_event(struct scsi_device *sdev,
+			struct scsi_sense_hdr *sshdr)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr	*nlh;
+	struct scsi_nl_sense_msg *msg;
+	u32 len, skblen;
+	int err;
+
+	if (!scsi_nl_sock) {
+		err = -ENOENT;
+		goto send_fail;
+	}
+
+	len = SCSI_NL_MSGALIGN(sizeof(*msg));
+	skblen = NLMSG_SPACE(len);
+
+	skb = alloc_skb(skblen, GFP_ATOMIC);
+	if (!skb) {
+		err = -ENOBUFS;
+		goto send_fail;
+	}
+
+	nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
+				skblen - sizeof(*nlh), 0);
+	if (!nlh) {
+		err = -ENOBUFS;
+		goto send_fail_skb;
+	}
+	msg = NLMSG_DATA(nlh);
+
+	INIT_SCSI_NL_HDR(&msg->snlh, SCSI_NL_TRANSPORT_ML,
+			 ML_NL_SCSI_SENSE, len);
+	msg->host_no = sdev->host->host_no;
+	msg->channel = sdev->channel;
+	msg->id = sdev->id;
+	msg->lun = sdev->lun;
+	msg->sense = (sshdr->response_code << 24) | (sshdr->sense_key << 16) |
+		(sshdr->asc << 8) | sshdr->ascq;
+
+	err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_ML_EVENTS,
+			      GFP_KERNEL);
+	if (err && (err != -ESRCH))
+		/* nlmsg_multicast already kfree_skb'd */
+		goto send_fail;
+
+	return;
+
+send_fail_skb:
+	kfree_skb(skb);
+send_fail:
+	sdev_printk(KERN_WARNING, sdev,
+		    "Dropped SCSI Msg %02x/%02x/%02x/%02x: err %d\n",
+		    sshdr->response_code, sshdr->sense_key,
+		    sshdr->asc, sshdr->ascq, err);
+	return;
+}
+#else
+static inline void scsi_post_sense_event(struct scsi_device *sdev,
+			   struct scsi_sense_hdr *sshdr) {}
+#endif
+
 /**
  * scsi_check_sense - Examine scsi cmd sense
  * @scmd:	Cmd to have sense checked.
@@ -240,6 +317,8 @@ static int scsi_check_sense(struct scsi_
 	if (scsi_sense_is_deferred(&sshdr))
 		return NEEDS_RETRY;
 
+	scsi_post_sense_event(sdev, &sshdr);
+
 	if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh &&
 			sdev->scsi_dh_data->scsi_dh->check_sense) {
 		int rc;
--- a/include/scsi/scsi_netlink.h
+++ b/include/scsi/scsi_netlink.h
@@ -35,7 +35,8 @@
 /* SCSI Transport Broadcast Groups */
 	/* leaving groups 0 and 1 unassigned */
 #define SCSI_NL_GRP_FC_EVENTS		(1<<2)		/* Group 2 */
-#define SCSI_NL_GRP_CNT			3
+#define SCSI_NL_GRP_ML_EVENTS		(1<<3)		/* Group 3 */
+#define SCSI_NL_GRP_CNT			4
 
 
 /* SCSI_TRANSPORT_MSG event message header */
@@ -56,7 +57,8 @@ struct scsi_nl_hdr {
 /* scsi_nl_hdr->transport value */
 #define SCSI_NL_TRANSPORT			0
 #define SCSI_NL_TRANSPORT_FC			1
-#define SCSI_NL_MAX_TRANSPORTS			2
+#define SCSI_NL_TRANSPORT_ML			2
+#define SCSI_NL_MAX_TRANSPORTS			3
 
 /* Transport-based scsi_nl_hdr->msgtype values are defined in each transport */
 
--- /dev/null
+++ b/include/scsi/scsi_netlink_ml.h
@@ -0,0 +1,64 @@
+/*
+ *  SCSI Midlayer Netlink Interface
+ *
+ *  Copyright (C) 2008 Hannes Reinecke, SuSE Linux Products GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef SCSI_NETLINK_ML_H
+#define SCSI_NETLINK_ML_H
+
+#include <scsi/scsi_netlink.h>
+
+/*
+ * This file intended to be included by both kernel and user space
+ */
+
+/*
+ * FC Transport Message Types
+ */
+	/* kernel -> user */
+#define ML_NL_SCSI_SENSE			0x0100
+	/* user -> kernel */
+/* none */
+
+
+/*
+ * Message Structures :
+ */
+
+/* macro to round up message lengths to 8byte boundary */
+#define SCSI_NL_MSGALIGN(len)		(((len) + 7) & ~7)
+
+
+/*
+ * SCSI Midlayer SCSI Sense messages :
+ *   SCSI_NL_SCSI_SENSE
+ *
+ */
+struct scsi_nl_sense_msg {
+	struct scsi_nl_hdr snlh;		/* must be 1st element ! */
+	uint64_t seconds;
+	u64 id;
+	u64 lun;
+	u16 host_no;
+	u16 channel;
+	u32 sense;
+} __attribute__((aligned(sizeof(uint64_t))));
+
+
+#endif /* SCSI_NETLINK_ML_H */
+
