fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / scsi / aacraid / linit.c
index 2716178..d2cf875 100644 (file)
  * Abstract: Linux Driver entry module for Adaptec RAID Array Controller
  */
 
-#define AAC_DRIVER_VERSION             "1.1-4"
-#ifndef AAC_DRIVER_BRANCH
-#define AAC_DRIVER_BRANCH              ""
-#endif
-#define AAC_DRIVER_BUILD_DATE          __DATE__ " " __TIME__
-#define AAC_DRIVERNAME                 "aacraid"
 
 #include <linux/compat.h>
 #include <linux/blkdev.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
 #include <linux/syscalls.h>
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
+#include <linux/kthread.h>
 #include <asm/semaphore.h>
 
 #include <scsi/scsi.h>
 
 #include "aacraid.h"
 
+#define AAC_DRIVER_VERSION             "1.1-5"
+#ifndef AAC_DRIVER_BRANCH
+#define AAC_DRIVER_BRANCH              ""
+#endif
+#define AAC_DRIVER_BUILD_DATE          __DATE__ " " __TIME__
+#define AAC_DRIVERNAME                 "aacraid"
+
 #ifdef AAC_DRIVER_BUILD
 #define _str(x) #x
 #define str(x) _str(x)
@@ -71,7 +74,7 @@
 MODULE_AUTHOR("Red Hat Inc and Adaptec");
 MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, "
                   "Adaptec Advanced Raid Products, "
-                  "and HP NetRAID-4M SCSI driver");
+                  "HP NetRAID-4M, IBM ServeRAID & ICP SCSI driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(AAC_DRIVER_FULL_VERSION);
 
@@ -79,6 +82,8 @@ static LIST_HEAD(aac_devices);
 static int aac_cfg_major = -1;
 char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
 
+extern int expose_physicals;
+
 /*
  * Because of the way Linux names scsi devices, the order in this table has
  * become important.  Check for on-board Raid first, add-in cards second.
@@ -112,11 +117,11 @@ static struct pci_device_id aac_pci_tbl[] = {
        { 0x9005, 0x0286, 0x9005, 0x029b, 0, 0, 22 }, /* AAR-2820SA (Intruder) */
        { 0x9005, 0x0286, 0x9005, 0x029c, 0, 0, 23 }, /* AAR-2620SA (Intruder) */
        { 0x9005, 0x0286, 0x9005, 0x029d, 0, 0, 24 }, /* AAR-2420SA (Intruder) */
-       { 0x9005, 0x0286, 0x9005, 0x029e, 0, 0, 25 }, /* ICP9024R0 (Lancer) */
-       { 0x9005, 0x0286, 0x9005, 0x029f, 0, 0, 26 }, /* ICP9014R0 (Lancer) */
+       { 0x9005, 0x0286, 0x9005, 0x029e, 0, 0, 25 }, /* ICP9024RO (Lancer) */
+       { 0x9005, 0x0286, 0x9005, 0x029f, 0, 0, 26 }, /* ICP9014RO (Lancer) */
        { 0x9005, 0x0286, 0x9005, 0x02a0, 0, 0, 27 }, /* ICP9047MA (Lancer) */
        { 0x9005, 0x0286, 0x9005, 0x02a1, 0, 0, 28 }, /* ICP9087MA (Lancer) */
-       { 0x9005, 0x0286, 0x9005, 0x02a3, 0, 0, 29 }, /* ICP5085AU (Hurricane) */
+       { 0x9005, 0x0286, 0x9005, 0x02a3, 0, 0, 29 }, /* ICP5445AU (Hurricane44) */
        { 0x9005, 0x0285, 0x9005, 0x02a4, 0, 0, 30 }, /* ICP9085LI (Marauder-X) */
        { 0x9005, 0x0285, 0x9005, 0x02a5, 0, 0, 31 }, /* ICP5085BR (Marauder-E) */
        { 0x9005, 0x0286, 0x9005, 0x02a6, 0, 0, 32 }, /* ICP9067MA (Intruder-6) */
@@ -132,15 +137,15 @@ static struct pci_device_id aac_pci_tbl[] = {
        { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 41 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
        { 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 42 }, /* AAR-2610SA PCI SATA 6ch */
        { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 43 }, /* ASR-2240S (SabreExpress) */
-       { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005SAS */
+       { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005 */
        { 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 45 }, /* IBM 8i (AvonPark) */
        { 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 45 }, /* IBM 8i (AvonPark Lite) */
        { 0x9005, 0x0286, 0x1014, 0x9580, 0, 0, 46 }, /* IBM 8k/8k-l8 (Aurora) */
        { 0x9005, 0x0286, 0x1014, 0x9540, 0, 0, 47 }, /* IBM 8k/8k-l4 (Aurora Lite) */
-       { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000SAS (BlackBird) */
+       { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000 (BlackBird) */
        { 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 49 }, /* ASR-4800SAS (Marauder-X) */
        { 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 50 }, /* ASR-4805SAS (Marauder-E) */
-       { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-4810SAS (Hurricane */
+       { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-3800 (Hurricane44) */
 
        { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 52 }, /* Perc 320/DC*/
        { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 53 }, /* Adaptec 5400S (Mustang)*/
@@ -188,11 +193,11 @@ static struct aac_driver_ident aac_drivers[] = {
        { aac_rkt_init, "aacraid",  "ADAPTEC ", "AAR-2820SA      ", 1 }, /* AAR-2820SA (Intruder) */
        { aac_rkt_init, "aacraid",  "ADAPTEC ", "AAR-2620SA      ", 1 }, /* AAR-2620SA (Intruder) */
        { aac_rkt_init, "aacraid",  "ADAPTEC ", "AAR-2420SA      ", 1 }, /* AAR-2420SA (Intruder) */
-       { aac_rkt_init, "aacraid",  "ICP     ", "ICP9024R0       ", 2 }, /* ICP9024R0 (Lancer) */
-       { aac_rkt_init, "aacraid",  "ICP     ", "ICP9014R0       ", 1 }, /* ICP9014R0 (Lancer) */
+       { aac_rkt_init, "aacraid",  "ICP     ", "ICP9024RO       ", 2 }, /* ICP9024RO (Lancer) */
+       { aac_rkt_init, "aacraid",  "ICP     ", "ICP9014RO       ", 1 }, /* ICP9014RO (Lancer) */
        { aac_rkt_init, "aacraid",  "ICP     ", "ICP9047MA       ", 1 }, /* ICP9047MA (Lancer) */
        { aac_rkt_init, "aacraid",  "ICP     ", "ICP9087MA       ", 1 }, /* ICP9087MA (Lancer) */
-       { aac_rkt_init, "aacraid",  "ICP     ", "ICP5085AU       ", 1 }, /* ICP5085AU (Hurricane) */
+       { aac_rkt_init, "aacraid",  "ICP     ", "ICP5445AU       ", 1 }, /* ICP5445AU (Hurricane44) */
        { aac_rx_init, "aacraid",  "ICP     ", "ICP9085LI       ", 1 }, /* ICP9085LI (Marauder-X) */
        { aac_rx_init, "aacraid",  "ICP     ", "ICP5085BR       ", 1 }, /* ICP5085BR (Marauder-E) */
        { aac_rkt_init, "aacraid",  "ICP     ", "ICP9067MA       ", 1 }, /* ICP9067MA (Intruder-6) */
@@ -207,14 +212,14 @@ static struct aac_driver_ident aac_drivers[] = {
        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2026ZCR     ", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2610SA      ", 1 }, /* SATA 6Ch (Bearcat) */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2240S       ", 1 }, /* ASR-2240S (SabreExpress) */
-       { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4005SAS     ", 1 }, /* ASR-4005SAS */
+       { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4005        ", 1 }, /* ASR-4005 */
        { aac_rx_init, "ServeRAID","IBM     ", "ServeRAID 8i    ", 1 }, /* IBM 8i (AvonPark) */
        { aac_rkt_init, "ServeRAID","IBM     ", "ServeRAID 8k-l8 ", 1 }, /* IBM 8k/8k-l8 (Aurora) */
        { aac_rkt_init, "ServeRAID","IBM     ", "ServeRAID 8k-l4 ", 1 }, /* IBM 8k/8k-l4 (Aurora Lite) */
-       { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4000SAS     ", 1 }, /* ASR-4000SAS (BlackBird & AvonPark) */
+       { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4000        ", 1 }, /* ASR-4000 (BlackBird & AvonPark) */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4800SAS     ", 1 }, /* ASR-4800SAS (Marauder-X) */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4805SAS     ", 1 }, /* ASR-4805SAS (Marauder-E) */
-       { aac_rkt_init, "aacraid",  "ADAPTEC ", "ASR-4810SAS     ", 1 }, /* ASR-4810SAS (Hurricane) */
+       { aac_rkt_init, "aacraid",  "ADAPTEC ", "ASR-3800        ", 1 }, /* ASR-3800 (Hurricane44) */
 
        { aac_rx_init, "percraid", "DELL    ", "PERC 320/DC     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/
        { aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
@@ -241,6 +246,7 @@ static struct aac_driver_ident aac_drivers[] = {
 static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
        cmd->scsi_done = done;
+       cmd->SCp.phase = AAC_OWNER_LOWLEVEL;
        return (aac_scsi_cmd(cmd) ? FAILED : 0);
 } 
 
@@ -390,6 +396,7 @@ static int aac_slave_configure(struct scsi_device *sdev)
                sdev->skip_ms_page_3f = 1;
        }
        if ((sdev->type == TYPE_DISK) &&
+                       !expose_physicals &&
                        (sdev_channel(sdev) != CONTAINER_CHANNEL)) {
                struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
                if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
@@ -449,27 +456,23 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
 
        printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", 
                                        AAC_DRIVERNAME);
-
-
-       spin_lock_irq(host->host_lock);
-
        aac = (struct aac_dev *)host->hostdata;
-       if (aac_adapter_check_health(aac)) {
-               printk(KERN_ERR "%s: Host adapter appears dead\n", 
-                               AAC_DRIVERNAME);
-               spin_unlock_irq(host->host_lock);
-               return -ENODEV;
-       }
+
+       if ((count = aac_check_health(aac)))
+               return count;
        /*
         * Wait for all commands to complete to this specific
         * target (block maximum 60 seconds).
         */
        for (count = 60; count; --count) {
-               int active = 0;
+               int active = aac->in_reset;
+
+               if (active == 0)
                __shost_for_each_device(dev, host) {
                        spin_lock_irqsave(&dev->list_lock, flags);
                        list_for_each_entry(command, &dev->cmd_list, list) {
-                               if (command->serial_number) {
+                               if ((command != cmd) &&
+                                   (command->SCp.phase == AAC_OWNER_FIRMWARE)) {
                                        active++;
                                        break;
                                }
@@ -482,13 +485,10 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
                /*
                 * We can exit If all the commands are complete
                 */
-               spin_unlock_irq(host->host_lock);
                if (active == 0)
                        return SUCCESS;
                ssleep(1);
-               spin_lock_irq(host->host_lock);
        }
-       spin_unlock_irq(host->host_lock);
        printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
        return -ETIMEDOUT;
 }
@@ -567,12 +567,12 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
                
                f = compat_alloc_user_space(sizeof(*f));
                ret = 0;
-               if (clear_user(f, sizeof(*f) != sizeof(*f)))
+               if (clear_user(f, sizeof(*f)))
                        ret = -EFAULT;
                if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32)))
                        ret = -EFAULT;
                if (!ret)
-                       ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
+                       ret = aac_do_ioctl(dev, cmd, f);
                break;
        }
 
@@ -685,6 +685,18 @@ static ssize_t aac_show_serial_number(struct class_device *class_dev,
        return len;
 }
 
+static ssize_t aac_show_max_channel(struct class_device *class_dev, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+         class_to_shost(class_dev)->max_channel);
+}
+
+static ssize_t aac_show_max_id(struct class_device *class_dev, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+         class_to_shost(class_dev)->max_id);
+}
+
 
 static struct class_device_attribute aac_model = {
        .attr = {
@@ -728,6 +740,20 @@ static struct class_device_attribute aac_serial_number = {
        },
        .show = aac_show_serial_number,
 };
+static struct class_device_attribute aac_max_channel = {
+       .attr = {
+               .name = "max_channel",
+               .mode = S_IRUGO,
+       },
+       .show = aac_show_max_channel,
+};
+static struct class_device_attribute aac_max_id = {
+       .attr = {
+               .name = "max_id",
+               .mode = S_IRUGO,
+       },
+       .show = aac_show_max_id,
+};
 
 static struct class_device_attribute *aac_attrs[] = {
        &aac_model,
@@ -736,6 +762,8 @@ static struct class_device_attribute *aac_attrs[] = {
        &aac_monitor_version,
        &aac_bios_version,
        &aac_serial_number,
+       &aac_max_channel,
+       &aac_max_id,
        NULL
 };
 
@@ -773,6 +801,7 @@ static struct scsi_host_template aac_driver_template = {
        .cmd_per_lun                    = AAC_NUM_IO_FIB, 
 #endif 
        .use_clustering                 = ENABLE_CLUSTERING,
+       .emulated                       = 1,
 };
 
 
@@ -796,18 +825,19 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        error = pci_enable_device(pdev);
        if (error)
                goto out;
+       error = -ENODEV;
 
        if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || 
                        pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
-               goto out;
+               goto out_disable_pdev;
        /*
         * If the quirk31 bit is set, the adapter needs adapter
         * to driver communication memory to be allocated below 2gig
         */
        if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) 
-               if (pci_set_dma_mask(pdev, 0x7FFFFFFFULL) ||
-                               pci_set_consistent_dma_mask(pdev, 0x7FFFFFFFULL))
-                       goto out;
+               if (pci_set_dma_mask(pdev, DMA_31BIT_MASK) ||
+                               pci_set_consistent_dma_mask(pdev, DMA_31BIT_MASK))
+                       goto out_disable_pdev;
        
        pci_set_master(pdev);
 
@@ -837,23 +867,16 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
         *      Map in the registers from the adapter.
         */
        aac->base_size = AAC_MIN_FOOTPRINT_SIZE;
-       if ((aac->regs.sa = ioremap(
-         (unsigned long)aac->scsi_host_ptr->base, AAC_MIN_FOOTPRINT_SIZE))
-         == NULL) {    
-               printk(KERN_WARNING "%s: unable to map adapter.\n",
-                 AAC_DRIVERNAME);
-               goto out_free_fibs;
-       }
        if ((*aac_drivers[index].init)(aac))
                goto out_unmap;
 
        /*
         *      Start any kernel threads needed
         */
-       aac->thread_pid = kernel_thread((int (*)(void *))aac_command_thread,
-         aac, 0);
-       if (aac->thread_pid < 0) {
+       aac->thread = kthread_run(aac_command_thread, aac, AAC_DRIVERNAME);
+       if (IS_ERR(aac->thread)) {
                printk(KERN_ERR "aacraid: Unable to create command thread.\n");
+               error = PTR_ERR(aac->thread);
                goto out_deinit;
        }
 
@@ -901,12 +924,12 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
         * all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
         * physical channels are address by their actual physical number+1
         */
-       if (aac->nondasd_support == 1)
-               shost->max_channel = aac->maximum_num_channels + 1;
+       if ((aac->nondasd_support == 1) || expose_physicals)
+               shost->max_channel = aac->maximum_num_channels;
        else
-               shost->max_channel = 1;
+               shost->max_channel = 0;
 
-       aac_get_config_status(aac);
+       aac_get_config_status(aac, 0);
        aac_get_containers(aac);
        list_add(&aac->entry, insert);
 
@@ -934,9 +957,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        return 0;
 
  out_deinit:
-       kill_proc(aac->thread_pid, SIGKILL, 0);
-       wait_for_completion(&aac->aif_completion);
-
+       kthread_stop(aac->thread);
        aac_send_shutdown(aac);
        aac_adapter_disable_int(aac);
        free_irq(pdev->irq, aac);
@@ -944,8 +965,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        aac_fib_map_free(aac);
        pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
        kfree(aac->queues);
-       iounmap(aac->regs.sa);
- out_free_fibs:
+       aac_adapter_ioremap(aac, 0);
        kfree(aac->fibs);
        kfree(aac->fsa_dev);
  out_free_host:
@@ -970,8 +990,7 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
 
        scsi_remove_host(shost);
 
-       kill_proc(aac->thread_pid, SIGKILL, 0);
-       wait_for_completion(&aac->aif_completion);
+       kthread_stop(aac->thread);
 
        aac_send_shutdown(aac);
        aac_adapter_disable_int(aac);
@@ -981,7 +1000,7 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
        kfree(aac->queues);
 
        free_irq(pdev->irq, aac);
-       iounmap(aac->regs.sa);
+       aac_adapter_ioremap(aac, 0);
        
        kfree(aac->fibs);
        kfree(aac->fsa_dev);
@@ -989,6 +1008,10 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
        list_del(&aac->entry);
        scsi_host_put(shost);
        pci_disable_device(pdev);
+       if (list_empty(&aac_devices)) {
+               unregister_chrdev(aac_cfg_major, "aac");
+               aac_cfg_major = -1;
+       }
 }
 
 static struct pci_driver aac_pci_driver = {
@@ -1021,7 +1044,8 @@ static int __init aac_init(void)
 
 static void __exit aac_exit(void)
 {
-       unregister_chrdev(aac_cfg_major, "aac");
+       if (aac_cfg_major > -1)
+               unregister_chrdev(aac_cfg_major, "aac");
        pci_unregister_driver(&aac_pci_driver);
 }