Merge branch 'linus' into cont_syslog
[safe/jmp/linux-2.6] / drivers / scsi / aic7xxx / aic79xx_osm.c
index 3c4efa4..4c41332 100644 (file)
@@ -53,6 +53,7 @@ static struct scsi_transport_template *ahd_linux_transport_template = NULL;
 #include <linux/blkdev.h>              /* For block_size() */
 #include <linux/delay.h>       /* For ssleep/msleep */
 #include <linux/device.h>
+#include <linux/slab.h>
 
 /*
  * Bucket size for counting good commands in between bad ones.
@@ -193,7 +194,7 @@ struct ahd_linux_iocell_opts
 #define AIC79XX_PRECOMP_INDEX  0
 #define AIC79XX_SLEWRATE_INDEX 1
 #define AIC79XX_AMPLITUDE_INDEX        2
-static struct ahd_linux_iocell_opts aic79xx_iocell_info[] =
+static const struct ahd_linux_iocell_opts aic79xx_iocell_info[] =
 {
        AIC79XX_DEFAULT_IOOPTS,
        AIC79XX_DEFAULT_IOOPTS,
@@ -325,7 +326,7 @@ MODULE_PARM_DESC(aic79xx,
 "      verbose                 Enable verbose/diagnostic logging\n"
 "      allow_memio             Allow device registers to be memory mapped\n"
 "      debug                   Bitmask of debug values to enable\n"
-"      no_reset                Supress initial bus resets\n"
+"      no_reset                Suppress initial bus resets\n"
 "      extended                Enable extended geometry on all controllers\n"
 "      periodic_otag           Send an ordered tagged transaction\n"
 "                              periodically to prevent tag starvation.\n"
@@ -369,10 +370,167 @@ static void ahd_release_simq(struct ahd_softc *ahd);
 static int ahd_linux_unit;
 
 
+/************************** OS Utility Wrappers *******************************/
+void ahd_delay(long);
+void
+ahd_delay(long usec)
+{
+       /*
+        * udelay on Linux can have problems for
+        * multi-millisecond waits.  Wait at most
+        * 1024us per call.
+        */
+       while (usec > 0) {
+               udelay(usec % 1024);
+               usec -= 1024;
+       }
+}
+
+
+/***************************** Low Level I/O **********************************/
+uint8_t ahd_inb(struct ahd_softc * ahd, long port);
+void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val);
+void ahd_outw_atomic(struct ahd_softc * ahd,
+                                    long port, uint16_t val);
+void ahd_outsb(struct ahd_softc * ahd, long port,
+                              uint8_t *, int count);
+void ahd_insb(struct ahd_softc * ahd, long port,
+                              uint8_t *, int count);
+
+uint8_t
+ahd_inb(struct ahd_softc * ahd, long port)
+{
+       uint8_t x;
+
+       if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+               x = readb(ahd->bshs[0].maddr + port);
+       } else {
+               x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
+       }
+       mb();
+       return (x);
+}
+
+#if 0 /* unused */
+static uint16_t
+ahd_inw_atomic(struct ahd_softc * ahd, long port)
+{
+       uint8_t x;
+
+       if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+               x = readw(ahd->bshs[0].maddr + port);
+       } else {
+               x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
+       }
+       mb();
+       return (x);
+}
+#endif
+
+void
+ahd_outb(struct ahd_softc * ahd, long port, uint8_t val)
+{
+       if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+               writeb(val, ahd->bshs[0].maddr + port);
+       } else {
+               outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
+       }
+       mb();
+}
+
+void
+ahd_outw_atomic(struct ahd_softc * ahd, long port, uint16_t val)
+{
+       if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+               writew(val, ahd->bshs[0].maddr + port);
+       } else {
+               outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
+       }
+       mb();
+}
+
+void
+ahd_outsb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
+{
+       int i;
+
+       /*
+        * There is probably a more efficient way to do this on Linux
+        * but we don't use this for anything speed critical and this
+        * should work.
+        */
+       for (i = 0; i < count; i++)
+               ahd_outb(ahd, port, *array++);
+}
+
+void
+ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
+{
+       int i;
+
+       /*
+        * There is probably a more efficient way to do this on Linux
+        * but we don't use this for anything speed critical and this
+        * should work.
+        */
+       for (i = 0; i < count; i++)
+               *array++ = ahd_inb(ahd, port);
+}
+
+/******************************* PCI Routines *********************************/
+uint32_t
+ahd_pci_read_config(ahd_dev_softc_t pci, int reg, int width)
+{
+       switch (width) {
+       case 1:
+       {
+               uint8_t retval;
+
+               pci_read_config_byte(pci, reg, &retval);
+               return (retval);
+       }
+       case 2:
+       {
+               uint16_t retval;
+               pci_read_config_word(pci, reg, &retval);
+               return (retval);
+       }
+       case 4:
+       {
+               uint32_t retval;
+               pci_read_config_dword(pci, reg, &retval);
+               return (retval);
+       }
+       default:
+               panic("ahd_pci_read_config: Read size too big");
+               /* NOTREACHED */
+               return (0);
+       }
+}
+
+void
+ahd_pci_write_config(ahd_dev_softc_t pci, int reg, uint32_t value, int width)
+{
+       switch (width) {
+       case 1:
+               pci_write_config_byte(pci, reg, value);
+               break;
+       case 2:
+               pci_write_config_word(pci, reg, value);
+               break;
+       case 4:
+               pci_write_config_dword(pci, reg, value);
+               break;
+       default:
+               panic("ahd_pci_write_config: Write size too big");
+               /* NOTREACHED */
+       }
+}
+
 /****************************** Inlines ***************************************/
-static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*);
+static void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*);
 
-static __inline void
+static void
 ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb)
 {
        struct scsi_cmnd *cmd;
@@ -400,13 +558,11 @@ ahd_linux_info(struct Scsi_Host *host)
        bp = &buffer[0];
        ahd = *(struct ahd_softc **)host->hostdata;
        memset(bp, 0, sizeof(buffer));
-       strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev ");
-       strcat(bp, AIC79XX_DRIVER_VERSION);
-       strcat(bp, "\n");
-       strcat(bp, "        <");
+       strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev " AIC79XX_DRIVER_VERSION "\n"
+                       "        <");
        strcat(bp, ahd->description);
-       strcat(bp, ">\n");
-       strcat(bp, "        ");
+       strcat(bp, ">\n"
+                       "        ");
        ahd_controller_info(ahd, ahd_info);
        strcat(bp, ahd_info);
 
@@ -432,7 +588,7 @@ ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
        return rtn;
 }
 
-static inline struct scsi_target **
+static struct scsi_target **
 ahd_linux_target_in_softc(struct scsi_target *starget)
 {
        struct  ahd_softc *ahd =
@@ -472,19 +628,15 @@ ahd_linux_target_alloc(struct scsi_target *starget)
                                            starget->id, &tstate);
 
                if ((flags  & CFPACKETIZED) == 0) {
-                       /* Do not negotiate packetized transfers */
-                       spi_rd_strm(starget) = 0;
-                       spi_pcomp_en(starget) = 0;
-                       spi_rti(starget) = 0;
-                       spi_wr_flow(starget) = 0;
-                       spi_hold_mcs(starget) = 0;
+                       /* don't negotiate packetized (IU) transfers */
+                       spi_max_iu(starget) = 0;
                } else {
                        if ((ahd->features & AHD_RTI) == 0)
                                spi_rti(starget) = 0;
                }
 
                if ((flags & CFQAS) == 0)
-                       spi_qas(starget) = 0;
+                       spi_max_qas(starget) = 0;
 
                /* Transinfo values have been set to BIOS settings */
                spi_max_width(starget) = (flags & CFWIDEB) ? 1 : 0;
@@ -766,7 +918,6 @@ struct scsi_host_template aic79xx_driver_template = {
        .max_sectors            = 8192,
        .cmd_per_lun            = 2,
        .use_clustering         = ENABLE_CLUSTERING,
-       .use_sg_chaining        = ENABLE_SG_CHAINING,
        .slave_alloc            = ahd_linux_slave_alloc,
        .slave_configure        = ahd_linux_slave_configure,
        .target_alloc           = ahd_linux_target_alloc,
@@ -992,7 +1143,7 @@ aic79xx_setup(char *s)
        char   *p;
        char   *end;
 
-       static struct {
+       static const struct {
                const char *name;
                uint32_t *flag;
        } options[] = {
@@ -1224,7 +1375,7 @@ ahd_platform_init(struct ahd_softc *ahd)
         * Lookup and commit any modified IO Cell options.
         */
        if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) {
-               struct ahd_linux_iocell_opts *iocell_opts;
+               const struct ahd_linux_iocell_opts *iocell_opts;
 
                iocell_opts = &aic79xx_iocell_info[ahd->unit];
                if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP)
@@ -1414,6 +1565,10 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
        unsigned long flags;
        int nseg;
 
+       nseg = scsi_dma_map(cmd);
+       if (nseg < 0)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
        ahd_lock(ahd, &flags);
 
        /*
@@ -1431,6 +1586,7 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
        if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
                ahd->flags |= AHD_RESOURCE_SHORTAGE;
                ahd_unlock(ahd, &flags);
+               scsi_dma_unmap(cmd);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
 
@@ -1486,8 +1642,6 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
        ahd_set_sense_residual(scb, 0);
        scb->sg_count = 0;
 
-       nseg = scsi_dma_map(cmd);
-       BUG_ON(nseg < 0);
        if (nseg > 0) {
                void *sg = scb->sg_list;
                struct scatterlist *cur_seg;
@@ -2182,7 +2336,7 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd)
                        /*
                         * The sequencer will never re-reference the
                         * in-core SCB.  To make sure we are notified
-                        * during reslection, set the MK_MESSAGE flag in
+                        * during reselection, set the MK_MESSAGE flag in
                         * the card's copy of the SCB.
                         */
                        ahd_outb(ahd, SCB_CONTROL,
@@ -2611,7 +2765,7 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp)
                uint8_t precomp;
 
                if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) {
-                       struct ahd_linux_iocell_opts *iocell_opts;
+                       const struct ahd_linux_iocell_opts *iocell_opts;
 
                        iocell_opts = &aic79xx_iocell_info[ahd->unit];
                        precomp = iocell_opts->precomp;