fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / scsi / dc395x.c
index bde847c..a965ed3 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/spinlock.h>
 #include <linux/pci.h>
 #include <linux/list.h>
+#include <linux/vmalloc.h>
 #include <asm/io.h>
 
 #include <scsi/scsi.h>
@@ -229,13 +230,12 @@ struct ScsiReqBlk {
        struct scsi_cmnd *cmd;
 
        struct SGentry *segment_x;      /* Linear array of hw sg entries (up to 64 entries) */
-       u32 sg_bus_addr;                /* Bus address of sg list (ie, of segment_x) */
+       dma_addr_t sg_bus_addr;         /* Bus address of sg list (ie, of segment_x) */
 
        u8 sg_count;                    /* No of HW sg entries for this request */
        u8 sg_index;                    /* Index of HW sg entry for this request */
-       u32 total_xfer_length;          /* Total number of bytes remaining to be transfered */
-       unsigned char *virt_addr;       /* Virtual address of current transfer position */
-
+       size_t total_xfer_length;       /* Total number of bytes remaining to be transfered */
+       size_t request_length;          /* Total number of bytes in this request */
        /*
         * The sense buffer handling function, request_sense, uses
         * the first hw sg entry (segment_x[0]) and the transfer
@@ -245,7 +245,7 @@ struct ScsiReqBlk {
         * total_xfer_length in xferred. These values are restored in
         * pci_unmap_srb_sense. This is the only place xferred is used.
         */
-       u32 xferred;                    /* Saved copy of total_xfer_length */
+       size_t xferred;                 /* Saved copy of total_xfer_length */
 
        u16 state;
 
@@ -295,8 +295,8 @@ struct DeviceCtlBlk {
 struct AdapterCtlBlk {
        struct Scsi_Host *scsi_host;
 
-       u16 io_port_base;
-       u16 io_port_len;
+       unsigned long io_port_base;
+       unsigned long io_port_len;
 
        struct list_head dcb_list;              /* head of going dcb list */
        struct DeviceCtlBlk *dcb_run_robin;
@@ -311,7 +311,7 @@ struct AdapterCtlBlk {
 
        u8 sel_timeout;
 
-       u8 irq_level;
+       unsigned int irq_level;
        u8 tag_max_num;
        u8 acb_flag;
        u8 gmode2;
@@ -376,6 +376,8 @@ static void disconnect(struct AdapterCtlBlk *acb);
 static void reselect(struct AdapterCtlBlk *acb);
 static u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
                struct ScsiReqBlk *srb);
+static inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
+               struct ScsiReqBlk *srb);
 static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
                struct ScsiReqBlk *srb);
 static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code,
@@ -384,13 +386,11 @@ static void scsi_reset_detect(struct AdapterCtlBlk *acb);
 static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb);
 static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
                struct ScsiReqBlk *srb);
-static inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
-               struct ScsiReqBlk *srb);
 static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
                struct ScsiReqBlk *srb);
 static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
                struct ScsiReqBlk *srb);
-static inline void set_xfer_rate(struct AdapterCtlBlk *acb,
+static void set_xfer_rate(struct AdapterCtlBlk *acb,
                struct DeviceCtlBlk *dcb);
 static void waiting_timeout(unsigned long ptr);
 
@@ -488,7 +488,7 @@ struct ParameterData {
        int def;                /* default value */
        int safe;               /* safe value */
 };
-static struct ParameterData __initdata cfg_data[] = {
+static struct ParameterData __devinitdata cfg_data[] = {
        { /* adapter id */
                CFG_PARAM_UNSET,
                0,
@@ -573,7 +573,7 @@ MODULE_PARM_DESC(reset_delay, "Reset delay in seconds. Default 1 (0-180)");
  * set_safe_settings - if the use_safe_settings option is set then
  * set all values to the safe and slow values.
  **/
-static void __init set_safe_settings(void)
+static void __devinit set_safe_settings(void)
 {
        if (use_safe_settings)
        {
@@ -592,7 +592,7 @@ static void __init set_safe_settings(void)
  * fix_settings - reset any boot parameters which are out of range
  * back to the default values.
  **/
-static void __init fix_settings(void)
+static void __devinit fix_settings(void)
 {
        int i;
 
@@ -619,7 +619,7 @@ static void __init fix_settings(void)
  * Mapping from the eeprom delay index value (index into this array)
  * to the the number of actual seconds that the delay should be for.
  */
-static char __initdata eeprom_index_to_delay_map[] = 
+static char __devinitdata eeprom_index_to_delay_map[] = 
        { 1, 3, 5, 10, 16, 30, 60, 120 };
 
 
@@ -629,7 +629,7 @@ static char __initdata eeprom_index_to_delay_map[] =
  *
  * @eeprom: The eeprom structure in which we find the delay index to map.
  **/
-static void __init eeprom_index_to_delay(struct NvRamType *eeprom)
+static void __devinit eeprom_index_to_delay(struct NvRamType *eeprom)
 {
        eeprom->delay_time = eeprom_index_to_delay_map[eeprom->delay_time];
 }
@@ -642,7 +642,7 @@ static void __init eeprom_index_to_delay(struct NvRamType *eeprom)
  *
  * @delay: The delay, in seconds, to find the eeprom index for.
  **/
-static int __init delay_to_eeprom_index(int delay)
+static int __devinit delay_to_eeprom_index(int delay)
 {
        u8 idx = 0;
        while (idx < 7 && eeprom_index_to_delay_map[idx] < delay)
@@ -658,7 +658,7 @@ static int __init delay_to_eeprom_index(int delay)
  *
  * @eeprom: The eeprom data to override with command line options.
  **/
-static void __init eeprom_override(struct NvRamType *eeprom)
+static void __devinit eeprom_override(struct NvRamType *eeprom)
 {
        u8 id;
 
@@ -742,7 +742,7 @@ static void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
 
 
 /* Find cmd in SRB list */
-inline static struct ScsiReqBlk *find_cmd(struct scsi_cmnd *cmd, 
+static inline struct ScsiReqBlk *find_cmd(struct scsi_cmnd *cmd,
                struct list_head *head)
 {
        struct ScsiReqBlk *i;
@@ -975,7 +975,6 @@ static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
        }
 }
 
-
 /* Prepare SRB for being sent to Device DCB w/ command *cmd */
 static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
                struct ScsiReqBlk *srb)
@@ -989,7 +988,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
        srb->sg_count = 0;
        srb->total_xfer_length = 0;
        srb->sg_bus_addr = 0;
-       srb->virt_addr = 0;
        srb->sg_index = 0;
        srb->adapter_status = 0;
        srb->target_status = 0;
@@ -1020,7 +1018,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
                        reqlen, cmd->request_buffer, cmd->use_sg,
                        srb->sg_count);
 
-               srb->virt_addr = page_address(sl->page);
                for (i = 0; i < srb->sg_count; i++) {
                        u32 busaddr = (u32)sg_dma_address(&sl[i]);
                        u32 seglen = (u32)sl[i].length;
@@ -1065,12 +1062,14 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
                        srb->total_xfer_length++;
 
                srb->segment_x[0].length = srb->total_xfer_length;
-               srb->virt_addr = cmd->request_buffer;
+
                dprintkdbg(DBG_0,
                        "build_srb: [1] len=%d buf=%p use_sg=%d map=%08x\n",
                        srb->total_xfer_length, cmd->request_buffer,
                        cmd->use_sg, srb->segment_x[0].address);
        }
+
+       srb->request_length = srb->total_xfer_length;
 }
 
 
@@ -1220,7 +1219,7 @@ static void dump_register_info(struct AdapterCtlBlk *acb,
                                srb, srb->cmd, srb->cmd->pid,
                                srb->cmd->cmnd[0], srb->cmd->device->id,
                                srb->cmd->device->lun);
-               printk("  sglist=%p cnt=%i idx=%i len=%i\n",
+               printk("  sglist=%p cnt=%i idx=%i len=%zu\n",
                       srb->segment_x, srb->sg_count, srb->sg_index,
                       srb->total_xfer_length);
                printk("  state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n",
@@ -1308,7 +1307,7 @@ static void reset_dev_param(struct AdapterCtlBlk *acb)
  * @cmd - some command for this host (for fetching hooks)
  * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003).
  */
-static int dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
+static int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
 {
        struct AdapterCtlBlk *acb =
                (struct AdapterCtlBlk *)cmd->device->host->hostdata;
@@ -1354,6 +1353,16 @@ static int dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
        return SUCCESS;
 }
 
+static int dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
+{
+       int rc;
+
+       spin_lock_irq(cmd->device->host->host_lock);
+       rc = __dc395x_eh_bus_reset(cmd);
+       spin_unlock_irq(cmd->device->host->host_lock);
+
+       return rc;
+}
 
 /*
  * abort an errant SCSI command
@@ -1392,10 +1401,10 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd)
        }
        srb = find_cmd(cmd, &dcb->srb_going_list);
        if (srb) {
-               dprintkl(KERN_DEBUG, "eh_abort: Command in progress");
+               dprintkl(KERN_DEBUG, "eh_abort: Command in progress\n");
                /* XXX: Should abort the command here */
        } else {
-               dprintkl(KERN_DEBUG, "eh_abort: Command not found");
+               dprintkl(KERN_DEBUG, "eh_abort: Command not found\n");
        }
        return FAILED;
 }
@@ -1676,6 +1685,23 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
 }
 
 
+#define DC395x_ENABLE_MSGOUT \
+ DC395x_write16 (acb, TRM_S1040_SCSI_CONTROL, DO_SETATN); \
+ srb->state |= SRB_MSGOUT
+
+
+/* abort command */
+static inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
+               struct ScsiReqBlk *srb)
+{
+       srb->msgout_buf[0] = ABORT;
+       srb->msg_count = 1;
+       DC395x_ENABLE_MSGOUT;
+       srb->state &= ~SRB_MSGIN;
+       srb->state |= SRB_MSGOUT;
+}
+
+
 /**
  * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to
  *                           have been triggered for this card.
@@ -1787,10 +1813,9 @@ static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb,
 }
 
 
-static irqreturn_t dc395x_interrupt(int irq, void *dev_id,
-               struct pt_regs *regs)
+static irqreturn_t dc395x_interrupt(int irq, void *dev_id)
 {
-       struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)dev_id;
+       struct AdapterCtlBlk *acb = dev_id;
        u16 scsi_status;
        u8 dma_status;
        irqreturn_t handled = IRQ_NONE;
@@ -1937,14 +1962,11 @@ static void sg_verify_length(struct ScsiReqBlk *srb)
 
 /*
  * Compute the next Scatter Gather list index and adjust its length
- * and address if necessary; also compute virt_addr
+ * and address if necessary
  */
 static void sg_update_list(struct ScsiReqBlk *srb, u32 left)
 {
        u8 idx;
-       struct scatterlist *sg;
-       struct scsi_cmnd *cmd = srb->cmd;
-       int segment = cmd->use_sg;
        u32 xferred = srb->total_xfer_length - left; /* bytes transfered */
        struct SGentry *psge = srb->segment_x + srb->sg_index;
 
@@ -1977,29 +1999,6 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left)
                psge++;
        }
        sg_verify_length(srb);
-
-       /* we need the corresponding virtual address */
-       if (!segment) {
-               srb->virt_addr += xferred;
-               return;
-       }
-
-       /* We have to walk the scatterlist to find it */
-       sg = (struct scatterlist *)cmd->request_buffer;
-       while (segment--) {
-               unsigned long mask =
-                   ~((unsigned long)sg->length - 1) & PAGE_MASK;
-               if ((sg_dma_address(sg) & mask) == (psge->address & mask)) {
-                       srb->virt_addr = (page_address(sg->page)
-                                          + psge->address -
-                                          (psge->address & PAGE_MASK));
-                       return;
-               }
-               ++sg;
-       }
-
-       dprintkl(KERN_ERR, "sg_update_list: sg_to_virt failed\n");
-       srb->virt_addr = 0;
 }
 
 
@@ -2011,15 +2010,7 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left)
  */
 static void sg_subtract_one(struct ScsiReqBlk *srb)
 {
-       srb->total_xfer_length--;
-       srb->segment_x[srb->sg_index].length--;
-       if (srb->total_xfer_length &&
-           !srb->segment_x[srb->sg_index].length) {
-               if (debug_enabled(DBG_PIO))
-                       printk(" (next segment)");
-               srb->sg_index++;
-               sg_update_list(srb, srb->total_xfer_length);
-       }
+       sg_update_list(srb, srb->total_xfer_length - 1);
 }
 
 
@@ -2079,7 +2070,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
         * If we need more data, the DMA SG list will be freshly set up, anyway
         */
        dprintkdbg(DBG_PIO, "data_out_phase0: "
-               "DMA{fifcnt=0x%02x fifostat=0x%02x} "
+               "DMA{fifocnt=0x%02x fifostat=0x%02x} "
                "SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n",
                DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
                DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
@@ -2200,12 +2191,11 @@ static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
        data_io_transfer(acb, srb, XFERDATAOUT);
 }
 
-
 static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                u16 *pscsi_status)
 {
        u16 scsi_status = *pscsi_status;
-       u32 d_left_counter = 0;
+
        dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n",
                srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
 
@@ -2223,6 +2213,9 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
         * seem to be a bad idea, actually.
         */
        if (!(srb->state & SRB_XFERPAD)) {
+               u32 d_left_counter;
+               unsigned int sc, fc;
+
                if (scsi_status & PARITYERROR) {
                        dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) "
                                "Parity Error\n", srb->cmd->pid);
@@ -2259,18 +2252,19 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                                DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT));
                }
                /* Now: Check remainig data: The SCSI counters should tell us ... */
-               d_left_counter = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER)
-                   + ((DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f)
+               sc = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER);
+               fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
+               d_left_counter = sc + ((fc & 0x1f)
                       << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 :
                           0));
                dprintkdbg(DBG_KG, "data_in_phase0: "
                        "SCSI{fifocnt=0x%02x%s ctr=0x%08x} "
                        "DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} "
                        "Remain{totxfer=%i scsi_fifo+ctr=%i}\n",
-                       DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
+                       fc,
                        (srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes",
-                       DC395x_read32(acb, TRM_S1040_SCSI_COUNTER),
-                       DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
+                       sc,
+                       fc,
                        DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
                        DC395x_read32(acb, TRM_S1040_DMA_CXCNT),
                        srb->total_xfer_length, d_left_counter);
@@ -2278,38 +2272,79 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                /* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */
                if (d_left_counter
                    && srb->total_xfer_length <= DC395x_LASTPIO) {
+                       size_t left_io = srb->total_xfer_length;
+
                        /*u32 addr = (srb->segment_x[srb->sg_index].address); */
                        /*sg_update_list (srb, d_left_counter); */
-                       dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) to "
-                               "%p for remaining %i bytes:",
-                               DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f,
+                       dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) "
+                                  "for remaining %i bytes:",
+                               fc & 0x1f,
                                (srb->dcb->sync_period & WIDE_SYNC) ?
                                    "words" : "bytes",
-                               srb->virt_addr,
                                srb->total_xfer_length);
                        if (srb->dcb->sync_period & WIDE_SYNC)
                                DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
                                              CFG2_WIDEFIFO);
-                       while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) != 0x40) {
-                               u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
-                               *(srb->virt_addr)++ = byte;
-                               if (debug_enabled(DBG_PIO))
-                                       printk(" %02x", byte);
-                               d_left_counter--;
-                               sg_subtract_one(srb);
-                       }
-                       if (srb->dcb->sync_period & WIDE_SYNC) {
-#if 1
-                /* Read the last byte ... */
-                               if (srb->total_xfer_length > 0) {
-                                       u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
-                                       *(srb->virt_addr)++ = byte;
-                                       srb->total_xfer_length--;
+                       while (left_io) {
+                               unsigned char *virt, *base = NULL;
+                               unsigned long flags = 0;
+                               size_t len = left_io;
+
+                               if (srb->cmd->use_sg) {
+                                       size_t offset = srb->request_length - left_io;
+                                       local_irq_save(flags);
+                                       /* Assumption: it's inside one page as it's at most 4 bytes and
+                                          I just assume it's on a 4-byte boundary */
+                                       base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer,
+                                                                    srb->sg_count, &offset, &len);
+                                       virt = base + offset;
+                               } else {
+                                       virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io;
+                                       len = left_io;
+                               }
+                               left_io -= len;
+
+                               while (len) {
+                                       u8 byte;
+                                       byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+                                       *virt++ = byte;
+
                                        if (debug_enabled(DBG_PIO))
                                                printk(" %02x", byte);
+
+                                       d_left_counter--;
+                                       sg_subtract_one(srb);
+
+                                       len--;
+
+                                       fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
+
+                                       if (fc == 0x40) {
+                                               left_io = 0;
+                                               break;
+                                       }
+                               }
+
+                               WARN_ON((fc != 0x40) == !d_left_counter);
+
+                               if (fc == 0x40 && (srb->dcb->sync_period & WIDE_SYNC)) {
+                                       /* Read the last byte ... */
+                                       if (srb->total_xfer_length > 0) {
+                                               u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+
+                                               *virt++ = byte;
+                                               srb->total_xfer_length--;
+                                               if (debug_enabled(DBG_PIO))
+                                                       printk(" %02x", byte);
+                                       }
+
+                                       DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
+                               }
+
+                               if (srb->cmd->use_sg) {
+                                       scsi_kunmap_atomic_sg(base);
+                                       local_irq_restore(flags);
                                }
-#endif
-                               DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
                        }
                        /*printk(" %08x", *(u32*)(bus_to_virt (addr))); */
                        /*srb->total_xfer_length = 0; */
@@ -2468,21 +2503,43 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
                                      SCMD_FIFO_IN);
                } else {        /* write */
                        int ln = srb->total_xfer_length;
+                       size_t left_io = srb->total_xfer_length;
+
                        if (srb->dcb->sync_period & WIDE_SYNC)
                                DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
                                     CFG2_WIDEFIFO);
-                       dprintkdbg(DBG_PIO,
-                               "data_io_transfer: PIO %i bytes from %p:",
-                               srb->total_xfer_length, srb->virt_addr);
 
-                       while (srb->total_xfer_length) {
-                               if (debug_enabled(DBG_PIO))
-                                       printk(" %02x", (unsigned char) *(srb->virt_addr));
+                       while (left_io) {
+                               unsigned char *virt, *base = NULL;
+                               unsigned long flags = 0;
+                               size_t len = left_io;
+
+                               if (srb->cmd->use_sg) {
+                                       size_t offset = srb->request_length - left_io;
+                                       local_irq_save(flags);
+                                       /* Again, max 4 bytes */
+                                       base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer,
+                                                                    srb->sg_count, &offset, &len);
+                                       virt = base + offset;
+                               } else {
+                                       virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io;
+                                       len = left_io;
+                               }
+                               left_io -= len;
+
+                               while (len--) {
+                                       if (debug_enabled(DBG_PIO))
+                                               printk(" %02x", *virt);
+
+                                       DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *virt++);
 
-                               DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 
-                                    *(srb->virt_addr)++);
+                                       sg_subtract_one(srb);
+                               }
 
-                               sg_subtract_one(srb);
+                               if (srb->cmd->use_sg) {
+                                       scsi_kunmap_atomic_sg(base);
+                                       local_irq_restore(flags);
+                               }
                        }
                        if (srb->dcb->sync_period & WIDE_SYNC) {
                                if (ln % 2) {
@@ -2583,11 +2640,6 @@ static inline u8 msgin_completed(u8 * msgbuf, u32 len)
        return 1;
 }
 
-#define DC395x_ENABLE_MSGOUT \
- DC395x_write16 (acb, TRM_S1040_SCSI_CONTROL, DO_SETATN); \
- srb->state |= SRB_MSGOUT
-
-
 /* reject_msg */
 static inline void msgin_reject(struct AdapterCtlBlk *acb,
                struct ScsiReqBlk *srb)
@@ -2603,18 +2655,6 @@ static inline void msgin_reject(struct AdapterCtlBlk *acb,
 }
 
 
-/* abort command */
-static inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
-               struct ScsiReqBlk *srb)
-{
-       srb->msgout_buf[0] = ABORT;
-       srb->msg_count = 1;
-       DC395x_ENABLE_MSGOUT;
-       srb->state &= ~SRB_MSGIN;
-       srb->state |= SRB_MSGOUT;
-}
-
-
 static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
                struct DeviceCtlBlk *dcb, u8 tag)
 {
@@ -3306,21 +3346,14 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
 {
        u8 tempcnt, status;
        struct scsi_cmnd *cmd = srb->cmd;
-       struct ScsiInqData *ptr;
        enum dma_data_direction dir = cmd->sc_data_direction;
-
-       if (cmd->use_sg) {
-               struct scatterlist* sg = (struct scatterlist *)cmd->request_buffer;
-               ptr = (struct ScsiInqData *)(page_address(sg->page) + sg->offset);
-       } else {
-               ptr = (struct ScsiInqData *)(cmd->request_buffer);
-       }
+       int ckc_only = 1;
 
        dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid,
                srb->cmd->device->id, srb->cmd->device->lun);
-       dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p addr=%p\n",
+       dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n",
                srb, cmd->use_sg, srb->sg_index, srb->sg_count,
-               cmd->request_buffer, ptr);
+               cmd->request_buffer);
        status = srb->target_status;
        if (srb->flag & AUTO_REQSENSE) {
                dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n");
@@ -3459,29 +3492,47 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
                                            srb->segment_x[0].address,
                                            cmd->request_bufflen, dir);
        }
-
-       if ((cmd->result & RES_DID) == 0 && cmd->cmnd[0] == INQUIRY
-           && cmd->cmnd[2] == 0 && cmd->request_bufflen >= 8
-           && dir != PCI_DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2)
-               dcb->inquiry7 = ptr->Flags;
+       ckc_only = 0;
 /* Check Error Conditions */
       ckc_e:
 
+       if (cmd->cmnd[0] == INQUIRY) {
+               unsigned char *base = NULL;
+               struct ScsiInqData *ptr;
+               unsigned long flags = 0;
+
+               if (cmd->use_sg) {
+                       struct scatterlist* sg = (struct scatterlist *)cmd->request_buffer;
+                       size_t offset = 0, len = sizeof(struct ScsiInqData);
+
+                       local_irq_save(flags);
+                       base = scsi_kmap_atomic_sg(sg, cmd->use_sg, &offset, &len);
+                       ptr = (struct ScsiInqData *)(base + offset);
+               } else
+                       ptr = (struct ScsiInqData *)(cmd->request_buffer);
+
+               if (!ckc_only && (cmd->result & RES_DID) == 0
+                   && cmd->cmnd[2] == 0 && cmd->request_bufflen >= 8
+                   && dir != PCI_DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2)
+                       dcb->inquiry7 = ptr->Flags;
+
        /*if( srb->cmd->cmnd[0] == INQUIRY && */
        /*  (host_byte(cmd->result) == DID_OK || status_byte(cmd->result) & CHECK_CONDITION) ) */
-       if (cmd->cmnd[0] == INQUIRY && (cmd->result == (DID_OK << 16)
-                                        || status_byte(cmd->
-                                                       result) &
-                                        CHECK_CONDITION)) {
-
-               if (!dcb->init_tcq_flag) {
-                       add_dev(acb, dcb, ptr);
-                       dcb->init_tcq_flag = 1;
+               if ((cmd->result == (DID_OK << 16)
+                    || status_byte(cmd->result) &
+                    CHECK_CONDITION)) {
+                       if (!dcb->init_tcq_flag) {
+                               add_dev(acb, dcb, ptr);
+                               dcb->init_tcq_flag = 1;
+                       }
                }
 
+               if (cmd->use_sg) {
+                       scsi_kunmap_atomic_sg(base);
+                       local_irq_restore(flags);
+               }
        }
 
-
        /* Here is the info for Doug Gilbert's sg3 ... */
        cmd->resid = srb->total_xfer_length;
        /* This may be interpreted by sb. or not ... */
@@ -3656,7 +3707,7 @@ static void scsi_reset_detect(struct AdapterCtlBlk *acb)
        } else {
                acb->acb_flag |= RESET_DETECT;
                reset_dev_param(acb);
-               doing_srb_done(acb, DID_RESET, 0, 1);
+               doing_srb_done(acb, DID_RESET, NULL, 1);
                /*DC395x_RecoverSRB( acb ); */
                acb->active_dcb = NULL;
                acb->acb_flag = 0;
@@ -3719,7 +3770,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
  * @target: The target for the new device.
  * @lun: The lun for the new device.
  *
- * Return the new device if succesfull or NULL on failure.
+ * Return the new device if successful or NULL on failure.
  **/
 static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
                u8 target, u8 lun)
@@ -3931,7 +3982,7 @@ static void dc395x_slave_destroy(struct scsi_device *scsi_device)
  *
  * @io_port: base I/O address
  **/
-static void __init trms1040_wait_30us(u16 io_port)
+static void __devinit trms1040_wait_30us(unsigned long io_port)
 {
        /* ScsiPortStallExecution(30); wait 30 us */
        outb(5, io_port + TRM_S1040_GEN_TIMER);
@@ -3948,7 +3999,7 @@ static void __init trms1040_wait_30us(u16 io_port)
  * @cmd:       SB + op code (command) to send
  * @addr:      address to send
  **/
-static void __init trms1040_write_cmd(u16 io_port, u8 cmd, u8 addr)
+static void __devinit trms1040_write_cmd(unsigned long io_port, u8 cmd, u8 addr)
 {
        int i;
        u8 send_data;
@@ -3993,7 +4044,7 @@ static void __init trms1040_write_cmd(u16 io_port, u8 cmd, u8 addr)
  * @addr:      offset into EEPROM
  * @byte:      bytes to write
  **/
-static void __init trms1040_set_data(u16 io_port, u8 addr, u8 byte)
+static void __devinit trms1040_set_data(unsigned long io_port, u8 addr, u8 byte)
 {
        int i;
        u8 send_data;
@@ -4047,7 +4098,7 @@ static void __init trms1040_set_data(u16 io_port, u8 addr, u8 byte)
  * @eeprom:    the data to write
  * @io_port:   the base io port
  **/
-static void __init trms1040_write_all(struct NvRamType *eeprom, u16 io_port)
+static void __devinit trms1040_write_all(struct NvRamType *eeprom, unsigned long io_port)
 {
        u8 *b_eeprom = (u8 *)eeprom;
        u8 addr;
@@ -4087,7 +4138,7 @@ static void __init trms1040_write_all(struct NvRamType *eeprom, u16 io_port)
  *
  * Returns the the byte read.
  **/
-static u8 __init trms1040_get_data(u16 io_port, u8 addr)
+static u8 __devinit trms1040_get_data(unsigned long io_port, u8 addr)
 {
        int i;
        u8 read_byte;
@@ -4125,7 +4176,7 @@ static u8 __init trms1040_get_data(u16 io_port, u8 addr)
  * @eeprom:    where to store the data
  * @io_port:   the base io port
  **/
-static void __init trms1040_read_all(struct NvRamType *eeprom, u16 io_port)
+static void __devinit trms1040_read_all(struct NvRamType *eeprom, unsigned long io_port)
 {
        u8 *b_eeprom = (u8 *)eeprom;
        u8 addr;
@@ -4155,7 +4206,7 @@ static void __init trms1040_read_all(struct NvRamType *eeprom, u16 io_port)
  * @eeprom:    caller allocated strcuture to read the eeprom data into
  * @io_port:   io port to read from
  **/
-static void __init check_eeprom(struct NvRamType *eeprom, u16 io_port)
+static void __devinit check_eeprom(struct NvRamType *eeprom, unsigned long io_port)
 {
        u16 *w_eeprom = (u16 *)eeprom;
        u16 w_addr;
@@ -4225,7 +4276,7 @@ static void __init check_eeprom(struct NvRamType *eeprom, u16 io_port)
  *
  * @eeprom: The eeprom data strucutre to show details for.
  **/
-static void __init print_eeprom_settings(struct NvRamType *eeprom)
+static void __devinit print_eeprom_settings(struct NvRamType *eeprom)
 {
        dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), dev_mode=0x%02x\n",
                eeprom->scsi_id,
@@ -4246,15 +4297,14 @@ static void adapter_sg_tables_free(struct AdapterCtlBlk *acb)
        const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
 
        for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page)
-               if (acb->srb_array[i].segment_x)
-                       kfree(acb->srb_array[i].segment_x);
+               kfree(acb->srb_array[i].segment_x);
 }
 
 
 /*
  * Allocate SG tables; as we have to pci_map them, an SG list (struct SGentry*)
  * should never cross a page boundary */
-static int __init adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
+static int __devinit adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
 {
        const unsigned mem_needed = (DC395x_MAX_SRB_CNT+1)
                                    *SEGMENTX_LEN;
@@ -4269,7 +4319,7 @@ static int __init adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
 
        dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages);
        while (pages--) {
-               ptr = (struct SGentry *)kmalloc(PAGE_SIZE, GFP_KERNEL);
+               ptr = kmalloc(PAGE_SIZE, GFP_KERNEL);
                if (!ptr) {
                        adapter_sg_tables_free(acb);
                        return 1;
@@ -4300,7 +4350,7 @@ static int __init adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
  *
  * @acb: The adapter to print the information for.
  **/
-static void __init adapter_print_config(struct AdapterCtlBlk *acb)
+static void __devinit adapter_print_config(struct AdapterCtlBlk *acb)
 {
        u8 bval;
 
@@ -4344,7 +4394,7 @@ static void __init adapter_print_config(struct AdapterCtlBlk *acb)
  *
  * @acb: The adapter to initialize.
  **/
-static void __init adapter_init_params(struct AdapterCtlBlk *acb)
+static void __devinit adapter_init_params(struct AdapterCtlBlk *acb)
 {
        struct NvRamType *eeprom = &acb->eeprom;
        int i;
@@ -4406,7 +4456,7 @@ static void __init adapter_init_params(struct AdapterCtlBlk *acb)
  *
  * @host: The scsi host instance to fill in the values for.
  **/
-static void __init adapter_init_scsi_host(struct Scsi_Host *host)
+static void __devinit adapter_init_scsi_host(struct Scsi_Host *host)
 {
         struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
        struct NvRamType *eeprom = &acb->eeprom;
@@ -4447,7 +4497,7 @@ static void __init adapter_init_scsi_host(struct Scsi_Host *host)
  *
  * @acb: The adapter which we are to init.
  **/
-void __init adapter_init_chip(struct AdapterCtlBlk *acb)
+static void __devinit adapter_init_chip(struct AdapterCtlBlk *acb)
 {
         struct NvRamType *eeprom = &acb->eeprom;
         
@@ -4500,18 +4550,18 @@ void __init adapter_init_chip(struct AdapterCtlBlk *acb)
  * Returns 0 if the initialization succeeds, any other value on
  * failure.
  **/
-static int __init adapter_init(struct AdapterCtlBlk *acb, u32 io_port,
-               u32 io_port_len, u8 irq)
+static int __devinit adapter_init(struct AdapterCtlBlk *acb,
+       unsigned long io_port, u32 io_port_len, unsigned int irq)
 {
        if (!request_region(io_port, io_port_len, DC395X_NAME)) {
-               dprintkl(KERN_ERR, "Failed to reserve IO region 0x%x\n", io_port);
+               dprintkl(KERN_ERR, "Failed to reserve IO region 0x%lx\n", io_port);
                goto failed;
        }
        /* store port base to indicate we have registered it */
        acb->io_port_base = io_port;
        acb->io_port_len = io_port_len;
        
-       if (request_irq(irq, dc395x_interrupt, SA_SHIRQ, DC395X_NAME, acb)) {
+       if (request_irq(irq, dc395x_interrupt, IRQF_SHARED, DC395X_NAME, acb)) {
                /* release the region we just claimed */
                dprintkl(KERN_INFO, "Failed to register IRQ\n");
                goto failed;
@@ -4520,7 +4570,7 @@ static int __init adapter_init(struct AdapterCtlBlk *acb, u32 io_port,
        acb->irq_level = irq;
 
        /* get eeprom configuration information and command line settings etc */
-       check_eeprom(&acb->eeprom, (u16)io_port);
+       check_eeprom(&acb->eeprom, io_port);
        print_eeprom_settings(&acb->eeprom);
 
        /* setup adapter control block */       
@@ -4638,8 +4688,8 @@ static int dc395x_proc_info(struct Scsi_Host *host, char *buffer,
        SPRINTF("SCSI Host Nr %i, ", host->host_no);
        SPRINTF("DC395U/UW/F DC315/U %s\n",
                (acb->config & HCC_WIDE_CARD) ? "Wide" : "");
-       SPRINTF("io_port_base 0x%04x, ", acb->io_port_base);
-       SPRINTF("irq_level 0x%02x, ", acb->irq_level);
+       SPRINTF("io_port_base 0x%04lx, ", acb->io_port_base);
+       SPRINTF("irq_level 0x%04x, ", acb->irq_level);
        SPRINTF(" SelTimeout %ims\n", (1638 * acb->sel_timeout) / 1000);
 
        SPRINTF("MaxID %i, MaxLUN %i, ", host->max_id, host->max_lun);
@@ -4792,11 +4842,11 @@ static void banner_display(void)
 static int __devinit dc395x_init_one(struct pci_dev *dev,
                const struct pci_device_id *id)
 {
-       struct Scsi_Host *scsi_host;
-       struct AdapterCtlBlk *acb;
-       unsigned int io_port_base;
+       struct Scsi_Host *scsi_host = NULL;
+       struct AdapterCtlBlk *acb = NULL;
+       unsigned long io_port_base;
        unsigned int io_port_len;
-       u8 irq;
+       unsigned int irq;
        
        dprintkdbg(DBG_0, "Init one instance (%s)\n", pci_name(dev));
        banner_display();
@@ -4809,23 +4859,23 @@ static int __devinit dc395x_init_one(struct pci_dev *dev,
        io_port_base = pci_resource_start(dev, 0) & PCI_BASE_ADDRESS_IO_MASK;
        io_port_len = pci_resource_len(dev, 0);
        irq = dev->irq;
-       dprintkdbg(DBG_0, "IO_PORT=%04x, IRQ=%x\n", io_port_base, dev->irq);
+       dprintkdbg(DBG_0, "IO_PORT=0x%04lx, IRQ=0x%x\n", io_port_base, dev->irq);
 
        /* allocate scsi host information (includes out adapter) */
        scsi_host = scsi_host_alloc(&dc395x_driver_template,
                                    sizeof(struct AdapterCtlBlk));
        if (!scsi_host) {
                dprintkl(KERN_INFO, "scsi_host_alloc failed\n");
-               return -ENOMEM;
+               goto fail;
        }
        acb = (struct AdapterCtlBlk*)scsi_host->hostdata;
        acb->scsi_host = scsi_host;
+       acb->dev = dev;
 
        /* initialise the adapter and everything we need */
        if (adapter_init(acb, io_port_base, io_port_len, irq)) {
                dprintkl(KERN_INFO, "adapter init failed\n");
-               scsi_host_put(scsi_host);
-               return -ENODEV;
+               goto fail;
        }
 
        pci_set_master(dev);
@@ -4833,14 +4883,20 @@ static int __devinit dc395x_init_one(struct pci_dev *dev,
        /* get the scsi mid level to scan for new devices on the bus */
        if (scsi_add_host(scsi_host, &dev->dev)) {
                dprintkl(KERN_ERR, "scsi_add_host failed\n");
-               adapter_uninit(acb);
-               scsi_host_put(scsi_host);
-               return -ENODEV;
+               goto fail;
        }
        pci_set_drvdata(dev, scsi_host);
        scsi_scan_host(scsi_host);
                
        return 0;
+
+fail:
+       if (acb != NULL)
+               adapter_uninit(acb);
+       if (scsi_host != NULL)
+               scsi_host_put(scsi_host);
+       pci_disable_device(dev);
+       return -ENODEV;
 }
 
 
@@ -4859,6 +4915,7 @@ static void __devexit dc395x_remove_one(struct pci_dev *dev)
 
        scsi_remove_host(scsi_host);
        adapter_uninit(acb);
+       pci_disable_device(dev);
        scsi_host_put(scsi_host);
        pci_set_drvdata(dev, NULL);
 }
@@ -4891,7 +4948,7 @@ static struct pci_driver dc395x_driver = {
  **/
 static int __init dc395x_module_init(void)
 {
-       return pci_module_init(&dc395x_driver);
+       return pci_register_driver(&dc395x_driver);
 }