- Update to 3.4-rc3.
[linux-flexiantxendom0-3.2.10.git] / drivers / scsi / scsi_error.c
index 386f0c5..cc3f237 100644 (file)
@@ -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>
@@ -35,6 +37,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"
@@ -43,6 +46,7 @@
 #include <trace/events/scsi.h>
 
 #define SENSE_TIMEOUT          (10*HZ)
+#define TEST_UNIT_READY_TIMEOUT        (30*HZ)
 
 /*
  * These should *probably* be handled by the host itself.
@@ -222,6 +226,80 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
 }
 #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.
@@ -244,6 +322,8 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
        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;
@@ -309,7 +389,8 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
                 * if the device is in the process of becoming ready, we
                 * should retry.
                 */
-               if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01))
+               if ((sshdr.asc == 0x04) &&
+                   (sshdr.ascq == 0x01 || sshdr.ascq == 0x0a))
                        return NEEDS_RETRY;
                /*
                 * if the device is not started, we need to wake
@@ -953,7 +1034,7 @@ static int scsi_eh_tur(struct scsi_cmnd *scmd)
        int retry_cnt = 1, rtn;
 
 retry_tur:
-       rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0);
+       rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, TEST_UNIT_READY_TIMEOUT, 0);
 
        SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
                __func__, scmd, rtn));