patch-2.0.26 linux/drivers/scsi/u14-34f.c

Next file: linux/drivers/scsi/u14-34f.h
Previous file: linux/drivers/scsi/scsi.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.25/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
@@ -1,6 +1,13 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25
+ *          Added multichannel support.
+ *
+ *      27 Sep 1996 rev. 2.12 for linux 2.1.0
+ *          Portability cleanups (virtual/bus addressing, little/big endian
+ *          support).
+ *
  *      09 Jul 1996 rev. 2.11 for linux 2.0.4
  *          "Data over/under-run" no longer implies a redo on all targets.
  *          Number of internal retries is now limited.
@@ -157,6 +164,7 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/byteorder.h>
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -197,6 +205,8 @@
 #undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
 
+#define MAX_CHANNEL 1
+#define MAX_LUN 8
 #define MAX_TARGET 8
 #define MAX_IRQ 16
 #define MAX_BOARDS 4
@@ -248,9 +258,9 @@
    unsigned char dcn: 1;                /* disable disconnect */
    unsigned char ca: 1;                 /* use cache (if available) */
    unsigned char sg: 1;                 /* scatter/gather operation */
-   unsigned char target: 3;             /* target SCSI id */
-   unsigned char ch_no: 2;              /* SCSI channel (always 0 for 14f) */
-   unsigned char lun: 3;                /* logical unit number */
+   unsigned char target: 3;             /* SCSI target id */
+   unsigned char channel: 2;            /* SCSI channel number */
+   unsigned char lun: 3;                /* SCSI logical unit number */
    unsigned int data_address PACKED;    /* transfer data pointer */
    unsigned int data_len PACKED;        /* length in bytes */
    unsigned int command_link PACKED;    /* for linking command chains */
@@ -266,8 +276,8 @@
    Scsi_Cmnd *SCpnt;
 
    struct sg_list {
-      unsigned int address;     /* Segment Address */
-      unsigned int num_bytes;   /* Segment Length */
+      unsigned int address;             /* Segment Address */
+      unsigned int num_bytes;           /* Segment Length */
       } sglist[MAX_SGLIST];
 
    unsigned int index;   /* cp index */
@@ -283,8 +293,8 @@
    char board_name[16];                 /* Name of this board */
    char board_id[256];                  /* data from INQUIRY on this board */
    int in_reset;                        /* True if board is doing a reset */
-   int target_time_out[MAX_TARGET];     /* N. of timeout errors on target */
-   int target_reset[MAX_TARGET];        /* If TRUE redo operation on target */
+   int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */
+   int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */
    unsigned int retries;                /* Number of internal retries */
    unsigned long last_retried_pid;      /* Pid of last retried command */
    unsigned char subversion;            /* Bus type, either ISA or ESA */
@@ -295,17 +305,31 @@
    unsigned char slot;
    };
 
-static struct Scsi_Host * sh[MAX_BOARDS + 1];
-static const char* driver_name = "Ux4F";
+static struct Scsi_Host *sh[MAX_BOARDS + 1];
+static const char *driver_name = "Ux4F";
 static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
 
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
+#if defined(__BIG_ENDIAN)
+#define H2DEV(x) ((unsigned long)( \
+	(((unsigned long)(x) & 0x000000ffU) << 24) | \
+	(((unsigned long)(x) & 0x0000ff00U) <<  8) | \
+	(((unsigned long)(x) & 0x00ff0000U) >>  8) | \
+	(((unsigned long)(x) & 0xff000000U) >> 24)))
+#else
+#define H2DEV(x) (x)
+#endif
+
+#define DEV2H(x) H2DEV(x)
+#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
+#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
+
 static void u14_34f_interrupt_handler(int, void *, struct pt_regs *);
 static int do_trace = FALSE;
 
-static inline unchar wait_on_busy(ushort iobase) {
+static inline int wait_on_busy(unsigned int iobase) {
    unsigned int loop = MAXLOOP;
 
    while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED)
@@ -322,8 +346,8 @@
    memset(cpp, 0, sizeof(struct mscp));
    cpp->opcode = OP_HOST_ADAPTER;
    cpp->xdir = DTD_IN;
-   cpp->data_address = (unsigned int) HD(j)->board_id;
-   cpp->data_len = sizeof(HD(j)->board_id);
+   cpp->data_address = V2DEV(HD(j)->board_id);
+   cpp->data_len = H2DEV(sizeof(HD(j)->board_id));
    cpp->scsi_cdbs_len = 6;
    cpp->scsi_cdbs[0] = HA_CMD_INQUIRY;
 
@@ -338,7 +362,7 @@
    outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
 
    /* Store pointer in OGM address bytes */
-   outl((unsigned int)cpp, sh[j]->io_port + REG_OGM);
+   outl(V2DEV(cpp), sh[j]->io_port + REG_OGM);
 
    /* Issue OGM interrupt */
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
@@ -357,9 +381,9 @@
    return FALSE;
 }
 
-static inline int port_detect(ushort *port_base, unsigned int j, 
-			      Scsi_Host_Template * tpnt) {
-   unsigned char irq, dma_channel, subversion;
+static inline int port_detect(unsigned int *port_base, unsigned int j, 
+			      Scsi_Host_Template *tpnt) {
+   unsigned char irq, dma_channel, subversion, c;
    unsigned char in_byte;
 
    /* Allowed BIOS base addresses (NULL indicates reserved) */
@@ -447,6 +471,7 @@
       }
 
    sh[j]->io_port = *port_base;
+   sh[j]->unique_id = *port_base;
    sh[j]->n_io_port = REGION_SIZE;
    sh[j]->base = bios_segment_table[config_1.bios_segment];
    sh[j]->irq = irq;
@@ -505,6 +530,10 @@
       enable_dma(dma_channel);
       }
 
+   sh[j]->max_channel = MAX_CHANNEL - 1;
+   sh[j]->max_id = MAX_TARGET;
+   sh[j]->max_lun = MAX_LUN;
+
    if (HD(j)->subversion == ISA && !board_inquiry(j)) {
       HD(j)->board_id[40] = 0;
 
@@ -519,21 +548,29 @@
 
    printk("%s: PORT 0x%03x, BIOS 0x%05x, IRQ %u, DMA %u, SG %d, "\
 	  "Mbox %d, CmdLun %d, C%d.\n", BN(j), sh[j]->io_port, 
-	  (int)sh[j]->base, sh[j]->irq, 
-	  sh[j]->dma_channel, sh[j]->sg_tablesize, 
-	  sh[j]->can_queue, sh[j]->cmd_per_lun,
+	  (int)sh[j]->base, sh[j]->irq, sh[j]->dma_channel,
+          sh[j]->sg_tablesize, sh[j]->can_queue, sh[j]->cmd_per_lun,
 	  sh[j]->hostt->use_clustering);
+
+   if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
+      printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
+             BN(j), sh[j]->max_id, sh[j]->max_lun);
+
+   for (c = 0; c <= sh[j]->max_channel; c++)
+      printk("%s: SCSI channel %u enabled, host target ID %u.\n",
+             BN(j), c, sh[j]->this_id);
+
    return TRUE;
 }
 
-int u14_34f_detect (Scsi_Host_Template * tpnt) {
+int u14_34f_detect(Scsi_Host_Template *tpnt) {
    unsigned int j = 0, k, flags;
 
-   ushort io_port[] = {
+   unsigned int io_port[] = {
       0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140, 0x0
       };
 
-   ushort *port_base = io_port;
+   unsigned int *port_base = io_port;
 
    tpnt->proc_dir = &proc_scsi_u14_34f;
 
@@ -563,19 +600,19 @@
 
 static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
    unsigned int k, data_len = 0;
-   struct scatterlist * sgpnt;
+   struct scatterlist *sgpnt;
 
    sgpnt = (struct scatterlist *) SCpnt->request_buffer;
 
    for (k = 0; k < SCpnt->use_sg; k++) {
-      cpp->sglist[k].address = (unsigned int) sgpnt[k].address;
-      cpp->sglist[k].num_bytes = sgpnt[k].length;
+      cpp->sglist[k].address = V2DEV(sgpnt[k].address);
+      cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length);
       data_len += sgpnt[k].length;
       }
 
    cpp->use_sg = SCpnt->use_sg;
-   cpp->data_address = (unsigned int) cpp->sglist;
-   cpp->data_len = data_len;
+   cpp->data_address = V2DEV(cpp->sglist);
+   cpp->data_len = H2DEV(data_len);
 }
 
 int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
@@ -634,8 +671,9 @@
    cpp->index = i;
    SCpnt->host_scribble = (unsigned char *) &cpp->index;
 
-   if (do_trace) printk("%s: qcomm, mbox %d, target %d, pid %ld.\n",
-			BN(j), i, SCpnt->target, SCpnt->pid);
+   if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
+			BN(j), i, SCpnt->channel, SCpnt->target, 
+                        SCpnt->lun, SCpnt->pid);
 
    cpp->xdir = DTD_IN;
 
@@ -646,10 +684,11 @@
 	}
 
    cpp->opcode = OP_SCSI;
+   cpp->channel = SCpnt->channel;
    cpp->target = SCpnt->target;
    cpp->lun = SCpnt->lun;
    cpp->SCpnt = SCpnt;
-   cpp->sense_addr = (unsigned int) SCpnt->sense_buffer;
+   cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
    cpp->sense_len = sizeof SCpnt->sense_buffer;
 
    if (SCpnt->use_sg) {
@@ -657,8 +696,8 @@
       build_sg_list(cpp, SCpnt);
       }
    else {
-      cpp->data_address = (unsigned int)SCpnt->request_buffer;
-      cpp->data_len = SCpnt->request_bufflen;
+      cpp->data_address = V2DEV(SCpnt->request_buffer);
+      cpp->data_len = H2DEV(SCpnt->request_bufflen);
       }
 
    cpp->scsi_cdbs_len = SCpnt->cmd_len;
@@ -667,15 +706,16 @@
    if (wait_on_busy(sh[j]->io_port)) {
       SCpnt->result = DID_ERROR << 16;
       SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, target %d, pid %ld, adapter busy, DID_ERROR, done.\n", 
-	     BN(j), SCpnt->target, SCpnt->pid);
+      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy, DID_ERROR,"\
+             " done.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun,
+             SCpnt->pid);
       restore_flags(flags);
       done(SCpnt);
       return 0;
       }
 
    /* Store pointer in OGM address bytes */
-   outl((unsigned int)cpp, sh[j]->io_port + REG_OGM);
+   outl(V2DEV(cpp), sh[j]->io_port + REG_OGM);
 
    /* Issue OGM interrupt */
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
@@ -693,15 +733,15 @@
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
 
    if (SCarg->host_scribble == NULL) {
-      printk("%s: abort, target %d, pid %ld inactive.\n",
-	     BN(j), SCarg->target, SCarg->pid);
+      printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
+	     BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
       restore_flags(flags);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
    i = *(unsigned int *)SCarg->host_scribble;
-   printk("%s: abort, mbox %d, target %d, pid %ld.\n",
-	  BN(j), i, SCarg->target, SCarg->pid);
+   printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
+	  BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
 
    if (i >= sh[j]->can_queue)
       panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
@@ -744,16 +784,17 @@
    panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
 }
 
-int u14_34f_reset(Scsi_Cmnd * SCarg, unsigned int reset_flags) {
-   unsigned int i, j, flags, time, k, limit = 0;
+int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
+   unsigned int i, j, flags, time, k, c, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
 
    save_flags(flags);
    cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
-   printk("%s: reset, enter, target %d, pid %ld, reset_flags %u.\n", 
-	  BN(j), SCarg->target, SCarg->pid, reset_flags);
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n", 
+	  BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
+          reset_flags);
 
    if (SCarg->host_scribble == NULL)
       printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
@@ -772,9 +813,11 @@
 
    HD(j)->retries = 0;
 
-   for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE;
-
-   for (k = 0; k < MAX_TARGET; k++) HD(j)->target_time_out[k] = 0;
+   for (c = 0; c <= sh[j]->max_channel; c++)
+      for (k = 0; k < sh[j]->max_id; k++) {
+         HD(j)->target_redo[k][c] = TRUE;
+         HD(j)->target_to[k][c] = 0;
+         }
 
    for (i = 0; i < sh[j]->can_queue; i++) {
 
@@ -859,7 +902,7 @@
       }
 }
 
-int u14_34f_biosparam(Disk * disk, kdev_t dev, int * dkinfo) {
+int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
    unsigned int j = 0;
    int size = disk->capacity;
 
@@ -869,9 +912,10 @@
    return 0;
 }
 
-static void u14_34f_interrupt_handler(int irq, void *dev_id, struct pt_regs * regs) {
+static void u14_34f_interrupt_handler(int irq, void *dev_id,
+                                      struct pt_regs *regs) {
    Scsi_Cmnd *SCpnt;
-   unsigned int i, j, k, flags, status, tstatus, loops, total_loops = 0;
+   unsigned int i, j, k, c, flags, status, tstatus, loops, total_loops = 0;
    struct mscp *spp;
 
    save_flags(flags);
@@ -901,7 +945,7 @@
 	 if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
 			      BN(j), HD(j)->iocount);
 
-	 spp = (struct mscp *)inl(sh[j]->io_port + REG_ICM);
+	 spp = (struct mscp *)DEV2V(inl(sh[j]->io_port + REG_ICM));
 
 	 /* Clear interrupt pending flag */
 	 outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
@@ -956,9 +1000,8 @@
 		  status = DID_ERROR << 16;
 
 	       /* If there was a bus reset, redo operation on each target */
-	       else if (tstatus != GOOD
-			&& SCpnt->device->type == TYPE_DISK
-			&& HD(j)->target_reset[SCpnt->target])
+	       else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
+		        && HD(j)->target_redo[SCpnt->target][SCpnt->channel])
 		  status = DID_BUS_BUSY << 16;
 
 	       /* Works around a flaw in scsi.c */
@@ -971,26 +1014,27 @@
 		  status = DID_OK << 16;
 
 	       if (tstatus == GOOD)
-		  HD(j)->target_reset[SCpnt->target] = FALSE;
+		  HD(j)->target_redo[SCpnt->target][SCpnt->channel] = FALSE;
 
 	       if (spp->target_status && SCpnt->device->type == TYPE_DISK)
-		  printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
-			 "0x%x, sense key 0x%x.\n", BN(j), 
-			 SCpnt->target, SCpnt->lun, SCpnt->pid,
-			 spp->target_status, SCpnt->sense_buffer[2]);
+		  printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
+                         "target_status 0x%x, sense key 0x%x.\n", BN(j), 
+			 SCpnt->channel, SCpnt->target, SCpnt->lun,
+                         SCpnt->pid, spp->target_status,
+                         SCpnt->sense_buffer[2]);
 
-	       HD(j)->target_time_out[SCpnt->target] = 0;
+	       HD(j)->target_to[SCpnt->target][SCpnt->channel] = 0;
 
                if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
 
 	       break;
 	    case ASST:     /* Selection Time Out */
 
-	       if (HD(j)->target_time_out[SCpnt->target] > 1)
+	       if (HD(j)->target_to[SCpnt->target][SCpnt->channel] > 1)
 		  status = DID_ERROR << 16;
 	       else {
 		  status = DID_TIME_OUT << 16;
-		  HD(j)->target_time_out[SCpnt->target]++;
+		  HD(j)->target_to[SCpnt->target][SCpnt->channel]++;
 		  }
 
 	       break;
@@ -1001,8 +1045,10 @@
 	    case 0x96:     /* Illegal SCSI command */
 	    case 0xa3:     /* SCSI bus reset error */
 
-	       for (k = 0; k < MAX_TARGET; k++) 
-		  HD(j)->target_reset[k] = TRUE;
+	       for (c = 0; c <= sh[j]->max_channel; c++) 
+	          for (k = 0; k < sh[j]->max_id; k++) 
+	             HD(j)->target_redo[k][c] = TRUE;
+   
 
 	    case 0x92:     /* Data over/under-run */
 
@@ -1042,9 +1088,10 @@
 	     do_trace)
 #endif
 	    printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
-		   " target %d:%d, pid %ld, count %d.\n",
+		   " target %d.%d:%d, pid %ld, count %d.\n",
 		   BN(j), i, spp->adapter_status, spp->target_status,
-		   SCpnt->target, SCpnt->lun, SCpnt->pid, HD(j)->iocount);
+		   SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
+                   HD(j)->iocount);
 
 	 /* Set the command state to inactive */
 	 SCpnt->host_scribble = NULL;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov