*/
static char *aic79xx = NULL;
-MODULE_AUTHOR("Maintainer: Justin T. Gibbs <gibbs@scsiguy.com>");
-MODULE_DESCRIPTION("Adaptec Aic790X U320 SCSI Host Bus Adapter driver");
+MODULE_AUTHOR("Maintainer: Hannes Reinecke <hare@suse.de>");
+MODULE_DESCRIPTION("Adaptec AIC790X U320 SCSI Host Bus Adapter driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(AIC79XX_DRIVER_VERSION);
module_param(aic79xx, charp, 0444);
" 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"
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);
+uint16_t ahd_inw_atomic(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);
+}
+
+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);
+}
+
+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;
return rtn;
}
-static inline struct scsi_target **
+static struct scsi_target **
ahd_linux_target_in_softc(struct scsi_target *starget)
{
struct ahd_softc *ahd =
.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,
unsigned long flags;
int nseg;
+ nseg = scsi_dma_map(cmd);
+ if (nseg < 0)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
ahd_lock(ahd, &flags);
/*
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;
}
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;
if (scb->flags & SCB_SENSE) {
sense_size = min(sizeof(struct scsi_sense_data)
- ahd_get_sense_residual(scb),
- (u_long)sizeof(cmd->sense_buffer));
+ (u_long)SCSI_SENSE_BUFFERSIZE);
sense_offset = 0;
} else {
/*
scb->sense_data;
sense_size = min_t(size_t,
scsi_4btoul(siu->sense_length),
- sizeof(cmd->sense_buffer));
+ SCSI_SENSE_BUFFERSIZE);
sense_offset = SIU_SENSE_OFFSET(siu);
}
- memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+ memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
memcpy(cmd->sense_buffer,
ahd_get_sense_buf(ahd, scb)
+ sense_offset, sense_size);
struct scsi_sense_data *sense;
sense = (struct scsi_sense_data *)
- &cmd->sense_buffer;
+ cmd->sense_buffer;
if (sense->extra_len >= 5 &&
(sense->add_sense_code == 0x47
|| sense->add_sense_code == 0x48))