]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/aic7xxx/aic7xxx_osm.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq
[linux-2.6-omap-h63xx.git] / drivers / scsi / aic7xxx / aic7xxx_osm.c
index 7770befbf50c17171a03077a91e5794070c8217f..fd2b9785ff4fe9aa452cf86cb21ab14f31beb072 100644 (file)
@@ -335,8 +335,8 @@ static uint32_t aic7xxx_periodic_otag;
  */
 static char *aic7xxx = NULL;
 
-MODULE_AUTHOR("Maintainer: Justin T. Gibbs <gibbs@scsiguy.com>");
-MODULE_DESCRIPTION("Adaptec Aic77XX/78XX SCSI Host Bus Adapter driver");
+MODULE_AUTHOR("Maintainer: Hannes Reinecke <hare@suse.de>");
+MODULE_DESCRIPTION("Adaptec AIC77XX/78XX SCSI Host Bus Adapter driver");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(AIC7XXX_DRIVER_VERSION);
 module_param(aic7xxx, charp, 0444);
@@ -347,7 +347,7 @@ MODULE_PARM_DESC(aic7xxx,
 "      debug                   Bitmask of debug values to enable\n"
 "      no_probe                Toggle EISA/VLB controller probing\n"
 "      probe_eisa_vl           Toggle EISA/VLB controller probing\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"
@@ -388,14 +388,83 @@ static int  aic7xxx_setup(char *s);
 static int ahc_linux_unit;
 
 
+/************************** OS Utility Wrappers *******************************/
+void
+ahc_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
+ahc_inb(struct ahc_softc * ahc, long port)
+{
+       uint8_t x;
+
+       if (ahc->tag == BUS_SPACE_MEMIO) {
+               x = readb(ahc->bsh.maddr + port);
+       } else {
+               x = inb(ahc->bsh.ioport + port);
+       }
+       mb();
+       return (x);
+}
+
+void
+ahc_outb(struct ahc_softc * ahc, long port, uint8_t val)
+{
+       if (ahc->tag == BUS_SPACE_MEMIO) {
+               writeb(val, ahc->bsh.maddr + port);
+       } else {
+               outb(val, ahc->bsh.ioport + port);
+       }
+       mb();
+}
+
+void
+ahc_outsb(struct ahc_softc * ahc, 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++)
+               ahc_outb(ahc, port, *array++);
+}
+
+void
+ahc_insb(struct ahc_softc * ahc, 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++ = ahc_inb(ahc, port);
+}
+
 /********************************* Inlines ************************************/
-static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
+static void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
 
-static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
+static int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
                                      struct ahc_dma_seg *sg,
                                      dma_addr_t addr, bus_size_t len);
 
-static __inline void
+static void
 ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
 {
        struct scsi_cmnd *cmd;
@@ -406,7 +475,7 @@ ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
        scsi_dma_unmap(cmd);
 }
 
-static __inline int
+static int
 ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
                  struct ahc_dma_seg *sg, dma_addr_t addr, bus_size_t len)
 {
@@ -442,13 +511,11 @@ ahc_linux_info(struct Scsi_Host *host)
        bp = &buffer[0];
        ahc = *(struct ahc_softc **)host->hostdata;
        memset(bp, 0, sizeof(buffer));
-       strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev ");
-       strcat(bp, AIC7XXX_DRIVER_VERSION);
-       strcat(bp, "\n");
-       strcat(bp, "        <");
+       strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev " AIC7XXX_DRIVER_VERSION "\n"
+                       "        <");
        strcat(bp, ahc->description);
-       strcat(bp, ">\n");
-       strcat(bp, "        ");
+       strcat(bp, ">\n"
+                       "        ");
        ahc_controller_info(ahc, ahc_info);
        strcat(bp, ahc_info);
        strcat(bp, "\n");
@@ -747,7 +814,6 @@ struct scsi_host_template aic7xxx_driver_template = {
        .max_sectors            = 8192,
        .cmd_per_lun            = 2,
        .use_clustering         = ENABLE_CLUSTERING,
-       .use_sg_chaining        = ENABLE_SG_CHAINING,
        .slave_alloc            = ahc_linux_slave_alloc,
        .slave_configure        = ahc_linux_slave_configure,
        .target_alloc           = ahc_linux_target_alloc,
@@ -965,7 +1031,7 @@ aic7xxx_setup(char *s)
        char   *p;
        char   *end;
 
-       static struct {
+       static const struct {
                const char *name;
                uint32_t *flag;
        } options[] = {
@@ -1399,12 +1465,18 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
                        return SCSI_MLQUEUE_DEVICE_BUSY;
        }
 
+       nseg = scsi_dma_map(cmd);
+       if (nseg < 0)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
        /*
         * Get an scb to use.
         */
        scb = ahc_get_scb(ahc);
-       if (!scb)
+       if (!scb) {
+               scsi_dma_unmap(cmd);
                return SCSI_MLQUEUE_HOST_BUSY;
+       }
 
        scb->io_ctx = cmd;
        scb->platform_data->dev = dev;
@@ -1465,8 +1537,6 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
        ahc_set_sense_residual(scb, 0);
        scb->sg_count = 0;
 
-       nseg = scsi_dma_map(cmd);
-       BUG_ON(nseg < 0);
        if (nseg > 0) {
                struct  ahc_dma_seg *sg;
                struct  scatterlist *cur_seg;
@@ -1658,9 +1728,12 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
                untagged_q = &(ahc->untagged_queues[target_offset]);
                TAILQ_REMOVE(untagged_q, scb, links.tqe);
                BUG_ON(!TAILQ_EMPTY(untagged_q));
-       }
-
-       if ((scb->flags & SCB_ACTIVE) == 0) {
+       } else if ((scb->flags & SCB_ACTIVE) == 0) {
+               /*
+                * Transactions aborted from the untagged queue may
+                * not have been dispatched to the controller, so
+                * only check the SCB_ACTIVE flag for tagged transactions.
+                */
                printf("SCB %d done'd twice\n", scb->hscb->tag);
                ahc_dump_card_state(ahc);
                panic("Stopping for safety");
@@ -1801,12 +1874,12 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
 
                        sense_size = min(sizeof(struct scsi_sense_data)
                                       - ahc_get_sense_residual(scb),
-                                        (u_long)sizeof(cmd->sense_buffer));
+                                        (u_long)SCSI_SENSE_BUFFERSIZE);
                        memcpy(cmd->sense_buffer,
                               ahc_get_sense_buf(ahc, scb), sense_size);
-                       if (sense_size < sizeof(cmd->sense_buffer))
+                       if (sense_size < SCSI_SENSE_BUFFERSIZE)
                                memset(&cmd->sense_buffer[sense_size], 0,
-                                      sizeof(cmd->sense_buffer) - sense_size);
+                                      SCSI_SENSE_BUFFERSIZE - sense_size);
                        cmd->result |= (DRIVER_SENSE << 24);
 #ifdef AHC_DEBUG
                        if (ahc_debug & AHC_SHOW_SENSE) {
@@ -2311,7 +2384,7 @@ static void ahc_linux_set_period(struct scsi_target *starget, int period)
        unsigned int ppr_options = tinfo->goal.ppr_options;
        unsigned long flags;
        unsigned long offset = tinfo->goal.offset;
-       struct ahc_syncrate *syncrate;
+       const struct ahc_syncrate *syncrate;
 
        if (offset == 0)
                offset = MAX_OFFSET;
@@ -2355,7 +2428,7 @@ static void ahc_linux_set_offset(struct scsi_target *starget, int offset)
        unsigned int ppr_options = 0;
        unsigned int period = 0;
        unsigned long flags;
-       struct ahc_syncrate *syncrate = NULL;
+       const struct ahc_syncrate *syncrate = NULL;
 
        ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
                            starget->channel + 'A', ROLE_INITIATOR);
@@ -2385,7 +2458,7 @@ static void ahc_linux_set_dt(struct scsi_target *starget, int dt)
        unsigned int period = tinfo->goal.period;
        unsigned int width = tinfo->goal.width;
        unsigned long flags;
-       struct ahc_syncrate *syncrate;
+       const struct ahc_syncrate *syncrate;
 
        if (dt && spi_max_width(starget)) {
                ppr_options |= MSG_EXT_PPR_DT_REQ;