]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/scsi/hpsa.c
Merge branch 'davinci-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mv-sheeva.git] / drivers / scsi / hpsa.c
index bcc51f9d3903aaffcef35dfe838ae52de0f55edd..03697ba942510243de25b4f4d093605ac3c16366 100644 (file)
@@ -52,7 +52,7 @@
 #include "hpsa.h"
 
 /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
-#define HPSA_DRIVER_VERSION "1.0.0"
+#define HPSA_DRIVER_VERSION "2.0.1-3"
 #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
@@ -131,6 +131,9 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
 
 static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
                void (*done)(struct scsi_cmnd *));
+static void hpsa_scan_start(struct Scsi_Host *);
+static int hpsa_scan_finished(struct Scsi_Host *sh,
+       unsigned long elapsed_time);
 
 static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
 static int hpsa_slave_alloc(struct scsi_device *sdev);
@@ -177,6 +180,8 @@ static struct scsi_host_template hpsa_driver_template = {
        .name                   = "hpsa",
        .proc_name              = "hpsa",
        .queuecommand           = hpsa_scsi_queue_command,
+       .scan_start             = hpsa_scan_start,
+       .scan_finished          = hpsa_scan_finished,
        .this_id                = -1,
        .sg_tablesize           = MAXSGENTRIES,
        .use_clustering         = ENABLE_CLUSTERING,
@@ -197,6 +202,12 @@ static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
        return (struct ctlr_info *) *priv;
 }
 
+static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh)
+{
+       unsigned long *priv = shost_priv(sh);
+       return (struct ctlr_info *) *priv;
+}
+
 static struct task_struct *hpsa_scan_thread;
 static DEFINE_MUTEX(hpsa_scan_mutex);
 static LIST_HEAD(hpsa_scan_q);
@@ -314,7 +325,7 @@ static int hpsa_scan_func(__attribute__((unused)) void *data)
                        h->busy_scanning = 1;
                        mutex_unlock(&hpsa_scan_mutex);
                        host_no = h->scsi_host ?  h->scsi_host->host_no : -1;
-                       hpsa_update_scsi_devices(h, host_no);
+                       hpsa_scan_start(h->scsi_host);
                        complete_all(&h->scan_wait);
                        mutex_lock(&hpsa_scan_mutex);
                        h->busy_scanning = 0;
@@ -381,8 +392,7 @@ static ssize_t host_store_rescan(struct device *dev,
 {
        struct ctlr_info *h;
        struct Scsi_Host *shost = class_to_shost(dev);
-       unsigned long *priv = shost_priv(shost);
-       h = (struct ctlr_info *) *priv;
+       h = shost_to_hba(shost);
        if (add_to_scan_list(h)) {
                wake_up_process(hpsa_scan_thread);
                wait_for_completion_interruptible(&h->scan_wait);
@@ -665,6 +675,24 @@ lun_assigned:
        return 0;
 }
 
+/* Replace an entry from h->dev[] array. */
+static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
+       int entry, struct hpsa_scsi_dev_t *new_entry,
+       struct hpsa_scsi_dev_t *added[], int *nadded,
+       struct hpsa_scsi_dev_t *removed[], int *nremoved)
+{
+       /* assumes h->devlock is held */
+       BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA);
+       removed[*nremoved] = h->dev[entry];
+       (*nremoved)++;
+       h->dev[entry] = new_entry;
+       added[*nadded] = new_entry;
+       (*nadded)++;
+       dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d changed.\n",
+               scsi_device_type(new_entry->devtype), hostno, new_entry->bus,
+                       new_entry->target, new_entry->lun);
+}
+
 /* Remove an entry from h->dev[] array. */
 static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry,
        struct hpsa_scsi_dev_t *removed[], int *nremoved)
@@ -766,6 +794,8 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
 #define DEVICE_CHANGED 1
 #define DEVICE_SAME 2
        for (i = 0; i < haystack_size; i++) {
+               if (haystack[i] == NULL) /* previously removed. */
+                       continue;
                if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) {
                        *index = i;
                        if (device_is_the_same(needle, haystack[i]))
@@ -823,12 +853,12 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
                        continue; /* remove ^^^, hence i not incremented */
                } else if (device_change == DEVICE_CHANGED) {
                        changes++;
-                       hpsa_scsi_remove_entry(h, hostno, i,
-                               removed, &nremoved);
-                       (void) hpsa_scsi_add_entry(h, hostno, sd[entry],
-                               added, &nadded);
-                       /* add can't fail, we just removed one. */
-                       sd[entry] = NULL; /* prevent it from being freed */
+                       hpsa_scsi_replace_entry(h, hostno, i, sd[entry],
+                               added, &nadded, removed, &nremoved);
+                       /* Set it to NULL to prevent it from being freed
+                        * at the bottom of hpsa_update_scsi_devices()
+                        */
+                       sd[entry] = NULL;
                }
                i++;
        }
@@ -1029,7 +1059,6 @@ static void complete_scsi_command(struct CommandList *cp,
                                 * required
                                 */
                                if ((asc == 0x04) && (ascq == 0x03)) {
-                                       cmd->result = DID_NO_CONNECT << 16;
                                        dev_warn(&h->pdev->dev, "cp %p "
                                                "has check condition: unit "
                                                "not ready, manual "
@@ -1037,14 +1066,22 @@ static void complete_scsi_command(struct CommandList *cp,
                                        break;
                                }
                        }
-
-
+                       if (sense_key == ABORTED_COMMAND) {
+                               /* Aborted command is retryable */
+                               dev_warn(&h->pdev->dev, "cp %p "
+                                       "has check condition: aborted command: "
+                                       "ASC: 0x%x, ASCQ: 0x%x\n",
+                                       cp, asc, ascq);
+                               cmd->result = DID_SOFT_ERROR << 16;
+                               break;
+                       }
                        /* Must be some other type of check condition */
                        dev_warn(&h->pdev->dev, "cp %p has check condition: "
                                        "unknown type: "
                                        "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, "
                                        "Returning result: 0x%x, "
                                        "cmd=[%02x %02x %02x %02x %02x "
+                                       "%02x %02x %02x %02x %02x %02x "
                                        "%02x %02x %02x %02x %02x]\n",
                                        cp, sense_key, asc, ascq,
                                        cmd->result,
@@ -1052,7 +1089,10 @@ static void complete_scsi_command(struct CommandList *cp,
                                        cmd->cmnd[2], cmd->cmnd[3],
                                        cmd->cmnd[4], cmd->cmnd[5],
                                        cmd->cmnd[6], cmd->cmnd[7],
-                                       cmd->cmnd[8], cmd->cmnd[9]);
+                                       cmd->cmnd[8], cmd->cmnd[9],
+                                       cmd->cmnd[10], cmd->cmnd[11],
+                                       cmd->cmnd[12], cmd->cmnd[13],
+                                       cmd->cmnd[14], cmd->cmnd[15]);
                        break;
                }
 
@@ -1995,6 +2035,48 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
        return 0;
 }
 
+static void hpsa_scan_start(struct Scsi_Host *sh)
+{
+       struct ctlr_info *h = shost_to_hba(sh);
+       unsigned long flags;
+
+       /* wait until any scan already in progress is finished. */
+       while (1) {
+               spin_lock_irqsave(&h->scan_lock, flags);
+               if (h->scan_finished)
+                       break;
+               spin_unlock_irqrestore(&h->scan_lock, flags);
+               wait_event(h->scan_wait_queue, h->scan_finished);
+               /* Note: We don't need to worry about a race between this
+                * thread and driver unload because the midlayer will
+                * have incremented the reference count, so unload won't
+                * happen if we're in here.
+                */
+       }
+       h->scan_finished = 0; /* mark scan as in progress */
+       spin_unlock_irqrestore(&h->scan_lock, flags);
+
+       hpsa_update_scsi_devices(h, h->scsi_host->host_no);
+
+       spin_lock_irqsave(&h->scan_lock, flags);
+       h->scan_finished = 1; /* mark scan as finished. */
+       wake_up_all(&h->scan_wait_queue);
+       spin_unlock_irqrestore(&h->scan_lock, flags);
+}
+
+static int hpsa_scan_finished(struct Scsi_Host *sh,
+       unsigned long elapsed_time)
+{
+       struct ctlr_info *h = shost_to_hba(sh);
+       unsigned long flags;
+       int finished;
+
+       spin_lock_irqsave(&h->scan_lock, flags);
+       finished = h->scan_finished;
+       spin_unlock_irqrestore(&h->scan_lock, flags);
+       return finished;
+}
+
 static void hpsa_unregister_scsi(struct ctlr_info *h)
 {
        /* we are being forcibly unloaded, and may not refuse. */
@@ -2007,7 +2089,6 @@ static int hpsa_register_scsi(struct ctlr_info *h)
 {
        int rc;
 
-       hpsa_update_scsi_devices(h, -1);
        rc = hpsa_scsi_detect(h);
        if (rc != 0)
                dev_err(&h->pdev->dev, "hpsa_register_scsi: failed"
@@ -2084,14 +2165,14 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
        h = sdev_to_hba(scsicmd->device);
        if (h == NULL) /* paranoia */
                return FAILED;
-       dev_warn(&h->pdev->dev, "resetting drive\n");
-
        dev = scsicmd->device->hostdata;
        if (!dev) {
                dev_err(&h->pdev->dev, "hpsa_eh_device_reset_handler: "
                        "device lookup failed.\n");
                return FAILED;
        }
+       dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n",
+               h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
        /* send a reset to the SCSI LUN which the command was sent to */
        rc = hpsa_send_reset(h, dev->scsi3addr);
        if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0)
@@ -2206,50 +2287,6 @@ static void cmd_special_free(struct ctlr_info *h, struct CommandList *c)
 
 #ifdef CONFIG_COMPAT
 
-static int do_ioctl(struct scsi_device *dev, int cmd, void *arg)
-{
-       int ret;
-
-       lock_kernel();
-       ret = hpsa_ioctl(dev, cmd, arg);
-       unlock_kernel();
-       return ret;
-}
-
-static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg);
-static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
-       int cmd, void *arg);
-
-static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg)
-{
-       switch (cmd) {
-       case CCISS_GETPCIINFO:
-       case CCISS_GETINTINFO:
-       case CCISS_SETINTINFO:
-       case CCISS_GETNODENAME:
-       case CCISS_SETNODENAME:
-       case CCISS_GETHEARTBEAT:
-       case CCISS_GETBUSTYPES:
-       case CCISS_GETFIRMVER:
-       case CCISS_GETDRIVVER:
-       case CCISS_REVALIDVOLS:
-       case CCISS_DEREGDISK:
-       case CCISS_REGNEWDISK:
-       case CCISS_REGNEWD:
-       case CCISS_RESCANDISK:
-       case CCISS_GETLUNINFO:
-               return do_ioctl(dev, cmd, arg);
-
-       case CCISS_PASSTHRU32:
-               return hpsa_ioctl32_passthru(dev, cmd, arg);
-       case CCISS_BIG_PASSTHRU32:
-               return hpsa_ioctl32_big_passthru(dev, cmd, arg);
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-
 static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
 {
        IOCTL32_Command_struct __user *arg32 =
@@ -2274,7 +2311,7 @@ static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
        if (err)
                return -EFAULT;
 
-       err = do_ioctl(dev, CCISS_PASSTHRU, (void *)p);
+       err = hpsa_ioctl(dev, CCISS_PASSTHRU, (void *)p);
        if (err)
                return err;
        err |= copy_in_user(&arg32->error_info, &p->error_info,
@@ -2311,7 +2348,7 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
        if (err)
                return -EFAULT;
 
-       err = do_ioctl(dev, CCISS_BIG_PASSTHRU, (void *)p);
+       err = hpsa_ioctl(dev, CCISS_BIG_PASSTHRU, (void *)p);
        if (err)
                return err;
        err |= copy_in_user(&arg32->error_info, &p->error_info,
@@ -2320,6 +2357,36 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
                return -EFAULT;
        return err;
 }
+
+static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg)
+{
+       switch (cmd) {
+       case CCISS_GETPCIINFO:
+       case CCISS_GETINTINFO:
+       case CCISS_SETINTINFO:
+       case CCISS_GETNODENAME:
+       case CCISS_SETNODENAME:
+       case CCISS_GETHEARTBEAT:
+       case CCISS_GETBUSTYPES:
+       case CCISS_GETFIRMVER:
+       case CCISS_GETDRIVVER:
+       case CCISS_REVALIDVOLS:
+       case CCISS_DEREGDISK:
+       case CCISS_REGNEWDISK:
+       case CCISS_REGNEWD:
+       case CCISS_RESCANDISK:
+       case CCISS_GETLUNINFO:
+               return hpsa_ioctl(dev, cmd, arg);
+
+       case CCISS_PASSTHRU32:
+               return hpsa_ioctl32_passthru(dev, cmd, arg);
+       case CCISS_BIG_PASSTHRU32:
+               return hpsa_ioctl32_big_passthru(dev, cmd, arg);
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
 #endif
 
 static int hpsa_getpciinfo_ioctl(struct ctlr_info *h, void __user *argp)
@@ -2608,7 +2675,7 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
        case CCISS_DEREGDISK:
        case CCISS_REGNEWDISK:
        case CCISS_REGNEWD:
-               hpsa_update_scsi_devices(h, dev->host->host_no);
+               hpsa_scan_start(h->scsi_host);
                return 0;
        case CCISS_GETPCIINFO:
                return hpsa_getpciinfo_ioctl(h, argp);
@@ -3521,6 +3588,9 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
                goto clean4;
        }
        spin_lock_init(&h->lock);
+       spin_lock_init(&h->scan_lock);
+       init_waitqueue_head(&h->scan_wait_queue);
+       h->scan_finished = 1; /* no scan currently in progress */
 
        pci_set_drvdata(pdev, h);
        memset(h->cmd_pool_bits, 0,