summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
commit482368b1a8e45430672c58c9a42e7d2004367126 (patch)
treece2a1a567d4d62dee7c2e71a46a99cf72cf1d606 /drivers/scsi
parente4d0251c6f56ab2e191afb70f80f382793e23f74 (diff)
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/Config.in7
-rw-r--r--drivers/scsi/Makefile10
-rw-r--r--drivers/scsi/README.aic7xxx21
-rw-r--r--drivers/scsi/aha152x.c8
-rw-r--r--drivers/scsi/aic7xxx.c1240
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.reg3
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.seq48
-rw-r--r--drivers/scsi/aic7xxx_proc.c22
-rw-r--r--drivers/scsi/aic7xxx_reg.h18
-rw-r--r--drivers/scsi/aic7xxx_seq.c466
-rw-r--r--drivers/scsi/constants.c30
-rw-r--r--drivers/scsi/eata.c2
-rw-r--r--drivers/scsi/eata_dma_proc.c2
-rw-r--r--drivers/scsi/esp.c26
-rw-r--r--drivers/scsi/fdomain.c4
-rw-r--r--drivers/scsi/hosts.c59
-rw-r--r--drivers/scsi/hosts.h40
-rw-r--r--drivers/scsi/mac_esp.c5
-rw-r--r--drivers/scsi/mac_scsi.c85
-rw-r--r--drivers/scsi/mesh.c4
-rw-r--r--drivers/scsi/mvme16x.c2
-rw-r--r--drivers/scsi/pci2000.c81
-rw-r--r--drivers/scsi/pci2000.h28
-rw-r--r--drivers/scsi/pci2220i.c1652
-rw-r--r--drivers/scsi/pci2220i.h286
-rw-r--r--drivers/scsi/pcmcia/.cvsignore10
-rw-r--r--drivers/scsi/pcmcia/Config.in23
-rw-r--r--drivers/scsi/pcmcia/Makefile67
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c437
-rw-r--r--drivers/scsi/pcmcia/apa1480_stub.c174
-rw-r--r--drivers/scsi/pcmcia/fdomain_stub.c398
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c428
-rw-r--r--drivers/scsi/psi_dale.h498
-rw-r--r--drivers/scsi/qla1280.c5
-rw-r--r--drivers/scsi/qlogicfas.c3
-rw-r--r--drivers/scsi/qlogicfc.c19
-rw-r--r--drivers/scsi/qlogicpti.c17
-rw-r--r--drivers/scsi/scsi.c429
-rw-r--r--drivers/scsi/scsi.h112
-rw-r--r--drivers/scsi/scsi_error.c7
-rw-r--r--drivers/scsi/scsi_ioctl.c18
-rw-r--r--drivers/scsi/scsi_lib.c215
-rw-r--r--drivers/scsi/scsi_merge.c327
-rw-r--r--drivers/scsi/scsi_obsolete.c16
-rw-r--r--drivers/scsi/scsi_scan.c10
-rw-r--r--drivers/scsi/scsi_syms.c17
-rw-r--r--drivers/scsi/sd.c50
-rw-r--r--drivers/scsi/sg.c14
-rw-r--r--drivers/scsi/sr.c62
-rw-r--r--drivers/scsi/sr.h2
-rw-r--r--drivers/scsi/sr_ioctl.c63
-rw-r--r--drivers/scsi/sr_vendor.c12
-rw-r--r--drivers/scsi/st.c733
-rw-r--r--drivers/scsi/st.h9
-rw-r--r--drivers/scsi/sun3_NCR5380.c3012
-rw-r--r--drivers/scsi/sun3_scsi.c366
-rw-r--r--drivers/scsi/sun3_scsi.h262
57 files changed, 9722 insertions, 2242 deletions
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index e4af6a65e..9faa91e1b 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -8,7 +8,7 @@ fi
dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
-if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then
+if [ "$CONFIG_CHR_DEV_ST" != "n" ]; then
int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2
fi
@@ -193,3 +193,8 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
fi
endmenu
+
+if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
+ source drivers/scsi/pcmcia/Config.in
+fi
+
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index af4a242ff..16f26fbcd 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -13,6 +13,16 @@ MIX_OBJS :=
MOD_LIST_NAME := SCSI_MODULES
SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c))
+ALL_SUB_DIRS := pcmcia
+ifeq ($(CONFIG_PCMCIA),y)
+ SUB_DIRS += pcmcia
+ MOD_IN_SUB_DIRS += pcmcia
+else
+ ifeq ($(CONFIG_PCMCIA),m)
+ MOD_IN_SUB_DIRS += pcmcia
+ endif
+endif
+
CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF
CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
diff --git a/drivers/scsi/README.aic7xxx b/drivers/scsi/README.aic7xxx
index 100f9ff95..70ef93d92 100644
--- a/drivers/scsi/README.aic7xxx
+++ b/drivers/scsi/README.aic7xxx
@@ -208,6 +208,19 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
will often result in the machine crashing or spontaneously rebooting
during startup. Examples of machines that need this are the
Dell PowerEdge 6300 machines.
+
+ "aic7xxx=seltime:2" - This option controls how long the card waits
+ during a device selection sequence for the device to respond.
+ The original SCSI spec says that this "should be" 256ms. This
+ is generally not required with modern devices. However, some
+ very old SCSI I devices need the full 256ms. Most modern devices
+ can run fine with only 64ms. The default for this option is
+ 64ms. If you need to change this option, then use the following
+ table to set the proper value in the example above:
+ 0 - 256ms
+ 1 - 128ms
+ 2 - 64ms
+ 3 - 32ms
"aic7xxx=panic_on_abort" - This option is for debugging and will cause
the driver to panic the linux kernel and freeze the system the first
@@ -485,12 +498,14 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
Web sites
------------------------------
- http://people.redhat.com/dledford/aic7xxx.html
- - Primary web site maintained by Doug Ledford.
+ http://people.redhat.com/dledford/
+ - My web site, also the primary aic7xxx site with several related
+ pages.
Dean W. Gehnert
deang@teleport.com
$Revision: 3.0 $
-Modified by Doug Ledford 1998-9
+Modified by Doug Ledford 1998-2000
+
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 38550e1d3..30faaa9ad 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -200,13 +200,9 @@
**************************************************************************/
-#if defined(PCMCIA)
-#define MODULE
-#endif
-
#include <linux/module.h>
-#if defined(PCMCIA)
+#ifdef PCMCIA
#undef MODULE
#endif
@@ -877,9 +873,9 @@ static int tc1550_porttest(int io_port)
static int checksetup(struct aha152x_setup *setup)
{
- int i;
#if !defined(PCMCIA)
+ int i;
for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++)
;
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
index 77f52f337..6ca7147d5 100644
--- a/drivers/scsi/aic7xxx.c
+++ b/drivers/scsi/aic7xxx.c
@@ -264,7 +264,7 @@
*/
#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
-#define AIC7XXX_C_VERSION "5.1.21"
+#define AIC7XXX_C_VERSION "5.2.0"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -719,6 +719,11 @@ struct seeprom_config {
#define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in)
/*
+ * The stored DMA mapping for single-buffer data transfers.
+ */
+#define aic7xxx_mapping(cmd) ((cmd)->SCp.phase)
+
+/*
* So we can keep track of our host structs
*/
static struct aic7xxx_host *first_aic7xxx = NULL;
@@ -823,6 +828,7 @@ typedef enum {
* and what flags weren't. This way, I could clean up the flag usage on
* a use by use basis. Doug Ledford
*/
+ AHC_NO_STPWR = 0x00040000,
AHC_RESET_DELAY = 0x00080000,
AHC_A_SCANNED = 0x00100000,
AHC_B_SCANNED = 0x00200000,
@@ -883,6 +889,17 @@ typedef enum {
AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA3,
} ahc_feature;
+#define SCB_DMA_ADDR(scb, addr) ((unsigned long)(addr) + (scb)->scb_dma->dma_offset)
+
+struct aic7xxx_scb_dma {
+ unsigned long dma_offset; /* Correction you have to add
+ * to virtual address to get
+ * dma handle in this region */
+ dma_addr_t dma_address; /* DMA handle of the start,
+ * for unmap */
+ unsigned int dma_len; /* DMA length */
+};
+
struct aic7xxx_scb {
struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
@@ -891,15 +908,17 @@ struct aic7xxx_scb {
struct hw_scatterlist *sg_list; /* SG list in adapter format */
unsigned char tag_action;
unsigned char sg_count;
- unsigned char sense_cmd[6]; /*
+ unsigned char *sense_cmd; /*
* Allocate 6 characters for
* sense command.
*/
+ unsigned char *cmnd;
unsigned int sg_length; /* We init this during buildscb so we
* don't have to calculate anything
* during underflow/overflow/stat code
*/
void *kmalloc_ptr;
+ struct aic7xxx_scb_dma *scb_dma;
};
/*
@@ -937,6 +956,8 @@ typedef struct {
unsigned char numscbs; /* current number of scbs */
unsigned char maxhscbs; /* hardware scbs */
unsigned char maxscbs; /* max scbs including pageable scbs */
+ unsigned int hscbs_dma; /* DMA handle to hscbs */
+ unsigned int hscbs_dma_len; /* length of the above DMA area */
void *hscb_kmalloc_ptr;
} scb_data_type;
@@ -1014,6 +1035,9 @@ struct aic7xxx_host {
volatile unsigned char activescbs; /* active scbs */
volatile unsigned char max_activescbs;
volatile unsigned char qinfifonext;
+ volatile unsigned char *untagged_scbs;
+ volatile unsigned char *qoutfifo;
+ volatile unsigned char *qinfifo;
#define DEVICE_PRESENT 0x01
#define BUS_DEVICE_RESET_PENDING 0x02
@@ -1063,16 +1087,9 @@ struct aic7xxx_host {
* We put the less frequently used host structure items after the more
* frequently used items to try and ease the burden on the cache subsystem.
* These entries are not *commonly* accessed, whereas the preceding entries
- * are accessed very often. The only exceptions are the qinfifo, qoutfifo,
- * and untagged_scbs array. But, they are often accessed only once and each
- * access into these arrays is likely to blow a cache line, so they are put
- * down here so we can minimize the number of cache lines required to hold
- * the preceeding entries.
+ * are accessed very often.
*/
- volatile unsigned char untagged_scbs[256];
- volatile unsigned char qoutfifo[256];
- volatile unsigned char qinfifo[256];
unsigned int irq; /* IRQ for this adapter */
int instance; /* aic7xxx instance number */
int scsi_id; /* host adapter SCSI ID */
@@ -1085,9 +1102,7 @@ struct aic7xxx_host {
unsigned short ultraenb; /* Ultra mode target list */
unsigned short bios_control; /* bios control - SEEPROM */
unsigned short adapter_control; /* adapter control - SEEPROM */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
- struct pci_dev *pdev;
-#endif
+ struct pci_dev *pdev;
unsigned char pci_bus;
unsigned char pci_device_fn;
struct seeprom_config sc;
@@ -1098,6 +1113,7 @@ struct aic7xxx_host {
int host_no; /* SCSI host number */
unsigned long mbase; /* I/O memory address */
ahc_chip chip; /* chip type */
+ dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
/*
* Statistics Kept:
@@ -1354,10 +1370,10 @@ static int aic7xxx_scbram = 0;
/*
* So that we can set how long each device is given as a selection timeout.
* The table of values goes like this:
- * 0 - 256ms
- * 1 - 128ms
- * 2 - 64ms
- * 3 - 32ms
+ * 0 - 256ms
+ * 1 - 128ms
+ * 2 - 64ms
+ * 3 - 32ms
* We default to 64ms because it's fast. Some old SCSI-I devices need a
* longer time. The final value has to be left shifted by 3, hence 0x10
* is the final value.
@@ -1467,6 +1483,7 @@ aic_inb(struct aic7xxx_host *p, long port)
{
x = inb(p->base + port);
}
+ mb();
return(x);
#else
return(inb(p->base + port));
@@ -1770,6 +1787,7 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr,
struct ins_format1 *fmt1_ins;
struct ins_format3 *fmt3_ins;
unsigned char opcode;
+ volatile unsigned char hcntrl;
instr = *(union ins_formats*) &seqprog[instrptr * 4];
@@ -1871,12 +1889,13 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr,
}
}
aic_outb(p, (instr.integer & 0xff), SEQRAM);
- udelay(50);
+ hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
- udelay(50);
+ hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
- udelay(50);
+ hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
+ hcntrl = aic_inb(p, HCNTRL);
udelay(50);
break;
@@ -1991,21 +2010,6 @@ aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded)
/*+F*************************************************************************
* Function:
- * aic7xxx_delay
- *
- * Description:
- * Delay for specified amount of time. We use mdelay because the timer
- * interrupt is not guaranteed to be enabled. This will cause an
- * infinite loop since jiffies (clock ticks) is not updated.
- *-F*************************************************************************/
-static void
-aic7xxx_delay(int seconds)
-{
- mdelay(seconds * 1000);
-}
-
-/*+F*************************************************************************
- * Function:
* aic7xxx_info
*
* Description:
@@ -2728,15 +2732,14 @@ static int
aic7xxx_allocate_scb(struct aic7xxx_host *p)
{
struct aic7xxx_scb *scbp = NULL;
- int scb_size = sizeof(struct aic7xxx_scb) +
- sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
+ int scb_size = (sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG) + 12 + 6;
int i;
int step = PAGE_SIZE / 1024;
unsigned long scb_count = 0;
struct hw_scatterlist *hsgp;
struct aic7xxx_scb *scb_ap;
- unsigned long temp;
-
+ struct aic7xxx_scb_dma *scb_dma;
+ unsigned char *bufs;
if (p->scb_data->numscbs < p->scb_data->maxscbs)
{
@@ -2750,6 +2753,11 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
* efficiency since scb_size * (i -1) is growing slightly faster
* than the right hand side. If the number of SG array elements
* is changed, this function may not be near so efficient any more.
+ *
+ * Since the DMA'able buffers are now allocated in a seperate
+ * chunk this algorithm has been modified to match. The '12'
+ * and '6' factors in scb_size are for the DMA'able command byte
+ * and sensebuffers respectively. -DaveM
*/
for ( i=step;; i *= 2 )
{
@@ -2760,44 +2768,53 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
}
}
scb_count = MIN( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs);
- scb_ap = (struct aic7xxx_scb *)kmalloc(scb_size * scb_count, GFP_ATOMIC);
- if (scb_ap != NULL)
+ scb_ap = (struct aic7xxx_scb *)kmalloc(sizeof (struct aic7xxx_scb) * scb_count
+ + sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC);
+ if (scb_ap == NULL)
+ return(0);
+ scb_dma = (struct aic7xxx_scb_dma *)&scb_ap[scb_count];
+ hsgp = (struct hw_scatterlist *)
+ pci_alloc_consistent(p->pdev, scb_size * scb_count,
+ &scb_dma->dma_address);
+ if (hsgp == NULL)
{
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- {
- if (p->scb_data->numscbs == 0)
- printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
- p->host_no, -1, -1, -1, scb_count);
- else
- printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
- p->host_no, -1, -1, -1, scb_count);
- }
-#endif
- memset(scb_ap, 0, scb_count * scb_size);
- temp = (unsigned long) &scb_ap[scb_count];
- temp += 1023;
- temp &= ~1023;
- hsgp = (struct hw_scatterlist *)temp;
- for (i=0; i < scb_count; i++)
- {
- scbp = &scb_ap[i];
- scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
- scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
- memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
- scbp->hscb->tag = p->scb_data->numscbs;
- /*
- * Place in the scb array; never is removed
- */
- p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
- scbq_insert_tail(&p->scb_data->free_scbs, scbp);
- }
- scbp->kmalloc_ptr = scb_ap;
+ kfree(scb_ap);
+ return(0);
}
- else
+ bufs = (unsigned char *)&hsgp[scb_count * AIC7XXX_MAX_SG];
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+ if (aic7xxx_verbose > 0xffff)
{
- return(0);
+ if (p->scb_data->numscbs == 0)
+ printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
+ p->host_no, -1, -1, -1, scb_count);
+ else
+ printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
+ p->host_no, -1, -1, -1, scb_count);
+ }
+#endif
+ memset(scb_ap, 0, sizeof (struct aic7xxx_scb) * scb_count);
+ scb_dma->dma_offset = (unsigned long)scb_dma->dma_address
+ - (unsigned long)hsgp;
+ scb_dma->dma_len = scb_size * scb_count;
+ for (i=0; i < scb_count; i++)
+ {
+ scbp = &scb_ap[i];
+ scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
+ scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
+ scbp->sense_cmd = bufs;
+ scbp->cmnd = bufs + 6;
+ bufs += 12 + 6;
+ scbp->scb_dma = scb_dma;
+ memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
+ scbp->hscb->tag = p->scb_data->numscbs;
+ /*
+ * Place in the scb array; never is removed
+ */
+ p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
+ scbq_insert_tail(&p->scb_data->free_scbs, scbp);
}
+ scbp->kmalloc_ptr = scb_ap;
}
return(scb_count);
}
@@ -2882,6 +2899,24 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
struct aic7xxx_scb *scbp;
unsigned char queue_depth;
+ if (cmd->use_sg > 1)
+ {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *)cmd->request_buffer;
+ pci_unmap_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ }
+ else if (cmd->request_bufflen)
+ pci_unmap_single(p->pdev, aic7xxx_mapping(cmd),
+ cmd->request_bufflen,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ if (scb->flags & SCB_SENSE)
+ {
+ pci_unmap_single(p->pdev,
+ le32_to_cpu(scb->sg_list[0].address),
+ sizeof(cmd->sense_buffer),
+ PCI_DMA_FROMDEVICE);
+ }
if (scb->flags & SCB_RECOVERY_SCB)
{
p->flags &= ~AHC_ABORT_PENDING;
@@ -3889,11 +3924,19 @@ aic7xxx_reset_current_bus(struct aic7xxx_host *p)
while ( (aic_inb(p, SCSISEQ) & SCSIRSTO) == 0)
mdelay(5);
- mdelay(10);
+ /*
+ * Some of the new Ultra2 chipsets need a longer delay after a chip
+ * reset than just the init setup creates, so we have to delay here
+ * before we go into a reset in order to make the chips happy.
+ */
+ if (p->features & AHC_ULTRA2)
+ mdelay(250);
+ else
+ mdelay(50);
/* Turn off the bus reset. */
aic_outb(p, 0, SCSISEQ);
- mdelay(5);
+ mdelay(10);
aic7xxx_clear_intstat(p);
/* Re-enable reset interrupts. */
@@ -4772,6 +4815,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
case CHECK_CONDITION:
if ( !(scb->flags & SCB_SENSE) )
{
+ unsigned char *sense_buffer;
/*
* XXX - How do we save the residual (if there is one).
*/
@@ -4782,14 +4826,13 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
* Send a sense command to the requesting target.
* XXX - revisit this and get rid of the memcopys.
*/
- memcpy(&scb->sense_cmd[0], &generic_sense[0],
+ memcpy(scb->sense_cmd, &generic_sense[0],
sizeof(generic_sense));
scb->sense_cmd[1] = (cmd->lun << 5);
scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
- scb->sg_list[0].address =
- cpu_to_le32(VIRT_TO_BUS(&cmd->sense_buffer[0]));
+ sense_buffer = cmd->sense_buffer;
scb->sg_list[0].length =
cpu_to_le32(sizeof(cmd->sense_buffer));
@@ -4801,11 +4844,10 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
hscb->control = 0;
hscb->target_status = 0;
hscb->SG_list_pointer =
- cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
- hscb->data_pointer = scb->sg_list[0].address;
+ cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list));
hscb->data_count = scb->sg_list[0].length;
hscb->SCSI_cmd_pointer =
- cpu_to_le32(VIRT_TO_BUS(&scb->sense_cmd[0]));
+ cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd));
hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
hscb->residual_SG_segment_count = 0;
hscb->residual_data_count[0] = 0;
@@ -4854,12 +4896,14 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
* SENSE information anyway.
*/
if (cmd->next->cmnd[0] != TEST_UNIT_READY)
- {
- scb->sg_list[0].address =
- cpu_to_le32(VIRT_TO_BUS(&cmd->next->sense_buffer[0]));
- hscb->data_pointer = scb->sg_list[0].address;
- }
+ sense_buffer = cmd->next->sense_buffer;
}
+ scb->sg_list[0].address =
+ cpu_to_le32(pci_map_single(p->pdev, sense_buffer,
+ sizeof(cmd->sense_buffer),
+ PCI_DMA_FROMDEVICE));
+ hscb->data_pointer = scb->sg_list[0].address;
+
scb->flags |= SCB_SENSE;
/*
* Ensure the target is busy since this will be an
@@ -5134,7 +5178,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
else if (scb->flags & SCB_MSGOUT_PPR)
{
unsigned int max_sync, period;
- unsigned char options = p->transinfo[tindex].goal_options;
+ unsigned char options = 0;
if (p->features & AHC_ULTRA2)
{
@@ -5145,9 +5189,10 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
(p->dev_flags[tindex] & DEVICE_SCSI_3) &&
(p->transinfo[tindex].goal_width ==
MSG_EXT_WDTR_BUS_16_BIT) &&
- (options != 0) )
+ (p->transinfo[tindex].goal_options != 0) )
{
max_sync = AHC_SYNCRATE_ULTRA3;
+ options = p->transinfo[tindex].goal_options;
}
else
{
@@ -5296,6 +5341,188 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
}
break;
+ case WIDE_RESIDUE:
+ {
+ unsigned char resid_sgcnt, index;
+ unsigned char scb_index = aic_inb(p, SCB_TAG);
+ unsigned int cur_addr, resid_dcnt;
+ unsigned int native_addr, native_length;
+ int i;
+
+ if(scb_index > p->scb_data->numscbs)
+ {
+ printk(WARN_LEAD "invalid scb_index during WIDE_RESIDUE.\n",
+ p->host_no, -1, -1, -1);
+ /*
+ * XXX: Add error handling here
+ */
+ break;
+ }
+ scb = p->scb_data->scb_array[scb_index];
+ if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk(WARN_LEAD "invalid scb during WIDE_RESIDUE flags:0x%x "
+ "scb->cmd:0x%lx\n", p->host_no, CTL_OF_SCB(scb),
+ scb->flags, (unsigned long)scb->cmd);
+ break;
+ }
+
+ /*
+ * We have a valid scb to use on this WIDE_RESIDUE message, so
+ * we need to walk the sg list looking for this particular sg
+ * segment, then see if we happen to be at the very beginning of
+ * the segment. If we are, then we have to back things up to
+ * the previous segment. If not, then we simply need to remove
+ * one byte from this segments address and add one to the byte
+ * count.
+ */
+ cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
+ (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
+ resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
+ resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
+ (aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
+ (aic_inb(p, SCB_RESID_DCNT + 2) << 24);
+ index = scb->sg_count - resid_sgcnt;
+ native_addr = le32_to_cpu(scb->sg_list[index].address);
+ native_length = le32_to_cpu(scb->sg_list[index].length);
+ /*
+ * Make sure this is a valid sg_seg for the given pointer
+ */
+ if(cur_addr < native_addr ||
+ cur_addr > (native_addr + native_length))
+ {
+ printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
+ p->host_no, CTL_OF_SCB(scb), cur_addr);
+ if(index > 0)
+ printk(WARN_LEAD " sg_address[-1]:0x%x sg_length[-1]:%d\n",
+ p->host_no, CTL_OF_SCB(scb),
+ le32_to_cpu(scb->sg_list[index - 1].address),
+ le32_to_cpu(scb->sg_list[index - 1].length));
+ printk(WARN_LEAD " sg_address:0x%x sg_length:%d\n",
+ p->host_no, CTL_OF_SCB(scb),
+ native_addr, native_length);
+ if(resid_sgcnt > 1)
+ printk(WARN_LEAD " sg_address[1]:0x%x sg_length[1]:%d\n",
+ p->host_no, CTL_OF_SCB(scb),
+ le32_to_cpu(scb->sg_list[index + 1].address),
+ le32_to_cpu(scb->sg_list[index + 1].length));
+ break;
+ }
+
+ /*
+ * If our current address matches the sg_seg->address then we
+ * have to back up the sg array to the previous segment and set
+ * it up to have only one byte of transfer left to go.
+ */
+ if(cur_addr == native_addr)
+ {
+ if(index == 0)
+ {
+ printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
+ "transferred.\n", p->host_no, CTL_OF_SCB(scb));
+ break;
+ }
+ resid_sgcnt++;
+ index--;
+ cur_addr = le32_to_cpu(scb->sg_list[index].address) +
+ le32_to_cpu(scb->sg_list[index].length) - 1;
+ native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8)
+ | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24);
+ native_addr -= SG_SIZEOF;
+ aic_outb(p, resid_sgcnt, SG_COUNT);
+ aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
+ aic_outb(p, native_addr & 0xff, SG_NEXT);
+ aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1);
+ aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2);
+ aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3);
+ aic_outb(p, 1, SCB_RESID_DCNT);
+ aic_outb(p, 0, SCB_RESID_DCNT + 1);
+ aic_outb(p, 0, SCB_RESID_DCNT + 2);
+ aic_outb(p, 1, HCNT);
+ aic_outb(p, 0, HCNT + 1);
+ aic_outb(p, 0, HCNT + 2);
+ aic_outb(p, cur_addr & 0xff, HADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+ /*
+ * The sequencer actually wants to find the new address and byte
+ * count in the SHCNT and SHADDR register sets. These registers
+ * are a shadow of the regular HCNT and HADDR registers. On the
+ * Ultra2 controllers, these registers are read only and the way
+ * we have to set their values is to put the values we want into
+ * the HCNT and HADDR registers and then output PRELOADEN into
+ * the DFCNTRL register which causes the card to latch the current
+ * values in the HADDR and HCNT registers and drop it through to
+ * the shadow registers. On older cards we copy them directly
+ * across by hand.
+ */
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ i=0;
+ udelay(1);
+ while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ udelay(1);
+ }
+ }
+ else
+ {
+ aic_outb(p, 1, STCNT);
+ aic_outb(p, 0, STCNT + 1);
+ aic_outb(p, 0, STCNT + 2);
+ aic_outb(p, cur_addr & 0xff, SHADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+ }
+ }
+ else
+ {
+ /*
+ * Back the data pointer up by one and add one to the remaining
+ * byte count. Then store that in the HCNT and HADDR registers.
+ */
+ cur_addr--;
+ resid_dcnt++;
+ aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2);
+ aic_outb(p, resid_dcnt & 0xff, HCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2);
+ aic_outb(p, cur_addr & 0xff, HADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ i=0;
+ udelay(1);
+ while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ udelay(1);
+ }
+ }
+ else
+ {
+ aic_outb(p, resid_dcnt & 0xff, STCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2);
+ aic_outb(p, cur_addr & 0xff, SHADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+ }
+ }
+ }
+ break;
+
+
#if AIC7XXX_NOT_YET
case TRACEPOINT:
{
@@ -5655,16 +5882,6 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
break;
}
- /*
- * If we aren't on one of the new Ultra3 cards, then reject any PPR
- * message since we can't support any option field other than 0
- */
- if( !(p->features & AHC_ULTRA3) )
- {
- reject = TRUE;
- break;
- }
-
if (p->msg_len < (MSG_EXT_PPR_LEN + 2))
{
break;
@@ -6810,7 +7027,7 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
return;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
spin_lock_irqsave(&io_request_lock, cpu_flags);
- if(test_and_set_bit(AHC_IN_ISR_BIT, &p->flags))
+ if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags))
{
return;
}
@@ -6820,7 +7037,7 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
} while ( (aic_inb(p, INTSTAT) & INT_PEND) );
aic7xxx_done_cmds_complete(p);
aic7xxx_run_waiting_queues(p);
- clear_bit(AHC_IN_ISR_BIT, &p->flags);
+ clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags);
spin_unlock_irqrestore(&io_request_lock, cpu_flags);
#else
if(set_bit(AHC_IN_ISR_BIT, (int *)&p->flags))
@@ -7212,6 +7429,21 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
#undef CLOCK_PULSE
}
+#define CLOCK_PULSE(p) \
+ do { \
+ int limit = 0; \
+ do { \
+ mb(); \
+ pause_sequencer(p); /* This is just to generate some PCI */ \
+ /* traffic so the PCI read is flushed */ \
+ /* it shouldn't be needed, but some */ \
+ /* chipsets do indeed appear to need */ \
+ /* something to force PCI reads to get */ \
+ /* flushed */ \
+ udelay(1); /* Do nothing */ \
+ } while (((aic_inb(p, SEECTL) & SEERDY) == 0) && (++limit < 1000)); \
+ } while(0)
+
/*+F*************************************************************************
* Function:
* acquire_seeprom
@@ -7222,7 +7454,6 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
static int
acquire_seeprom(struct aic7xxx_host *p)
{
- int wait;
/*
* Request access of the memory port. When access is
@@ -7232,12 +7463,7 @@ acquire_seeprom(struct aic7xxx_host *p)
* should be no contention.
*/
aic_outb(p, SEEMS, SEECTL);
- wait = 1000; /* 1000 msec = 1 second */
- while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
- {
- wait--;
- mdelay(1); /* 1 msec */
- }
+ CLOCK_PULSE(p);
if ((aic_inb(p, SEECTL) & SEERDY) == 0)
{
aic_outb(p, 0, SEECTL);
@@ -7256,7 +7482,12 @@ acquire_seeprom(struct aic7xxx_host *p)
static void
release_seeprom(struct aic7xxx_host *p)
{
+ /*
+ * Make sure the SEEPROM is ready before we release it.
+ */
+ CLOCK_PULSE(p);
aic_outb(p, 0, SEECTL);
+ CLOCK_PULSE(p);
}
/*+F*************************************************************************
@@ -7322,12 +7553,6 @@ read_seeprom(struct aic7xxx_host *p, int offset,
};
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
-#define CLOCK_PULSE(p) \
- while ((aic_inb(p, SEECTL) & SEERDY) == 0) \
- { \
- ; /* Do nothing */ \
- }
-
/*
* Request access of the memory port.
*/
@@ -7443,7 +7668,6 @@ read_seeprom(struct aic7xxx_host *p, int offset,
}
return (1);
-#undef CLOCK_PULSE
}
/*+F*************************************************************************
@@ -7458,12 +7682,18 @@ read_brdctl(struct aic7xxx_host *p)
{
unsigned char brdctl, value;
+ /*
+ * Make sure the SEEPROM is ready before we access it
+ */
+ CLOCK_PULSE(p);
if (p->features & AHC_ULTRA2)
{
brdctl = BRDRW_ULTRA2;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
- return(aic_inb(p, BRDCTL));
+ CLOCK_PULSE(p);
+ value = aic_inb(p, BRDCTL);
+ CLOCK_PULSE(p);
+ return(value);
}
brdctl = BRDRW;
if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
@@ -7472,10 +7702,11 @@ read_brdctl(struct aic7xxx_host *p)
brdctl |= BRDCS;
}
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
value = aic_inb(p, BRDCTL);
+ CLOCK_PULSE(p);
aic_outb(p, 0, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
return (value);
}
@@ -7491,18 +7722,23 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
{
unsigned char brdctl;
+ /*
+ * Make sure the SEEPROM is ready before we access it
+ */
+ CLOCK_PULSE(p);
if (p->features & AHC_ULTRA2)
{
brdctl = value;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
+ CLOCK_PULSE(p);
brdctl |= BRDSTB_ULTRA2;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
+ CLOCK_PULSE(p);
brdctl &= ~BRDSTB_ULTRA2;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
+ CLOCK_PULSE(p);
read_brdctl(p);
+ CLOCK_PULSE(p);
}
else
{
@@ -7514,19 +7750,21 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
}
brdctl = BRDSTB | BRDCS;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
brdctl |= value;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
brdctl &= ~BRDSTB;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
brdctl &= ~BRDCS;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
}
}
+#undef CLOCK_PULSE
+
/*+F*************************************************************************
* Function:
* aic785x_cable_detect
@@ -7903,12 +8141,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
unsigned char term, scsi_conf;
struct Scsi_Host *host;
- /*
- * Lock out other contenders for our i/o space.
- */
- request_region(p->base, MAXREG - MINREG, "aic7xxx");
-
-
host = p->host;
p->scb_data->maxscbs = AIC7XXX_MAXSCB;
@@ -7944,12 +8176,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
p->dev_timer.function = (void *)aic7xxx_timer;
p->dev_timer_active = 0;
- for (i = 0; i < NUMBER(p->untagged_scbs); i++)
- {
- p->untagged_scbs[i] = SCB_LIST_NULL;
- p->qinfifo[i] = SCB_LIST_NULL;
- p->qoutfifo[i] = SCB_LIST_NULL;
- }
/*
* We currently have no commands of any type
*/
@@ -7980,7 +8206,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
printk("VLB slot %d\n", p->pci_device_fn);
break;
default:
- printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+ printk("PCI %d/%d/%d\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
PCI_FUNC(p->pci_device_fn));
break;
}
@@ -8016,6 +8242,20 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
}
aic_outb(p, 0, SEQ_FLAGS);
+ /*
+ * We are starting to do real work on the card....it's possible we could
+ * generate some spurious interrupts at this point, especially in the
+ * event of a PCI error or some such. If there are other devices already
+ * registered on the same interrupt as us, this could cause the machine
+ * to lock up. So, we disable the interrupt this card is on until we
+ * finish our card setup. We only need to do this for modules, if we are
+ * compiled into the kernel then interrupts are already off during this
+ * part of the code.
+ */
+#ifdef MODULE
+ disable_irq(p->irq);
+#endif
+
detect_maxscb(p);
@@ -8051,15 +8291,15 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
#endif
if ( (aic7xxx_stpwlev >> p->instance) & 0x01 )
{
- devconfig |= 0x02;
+ devconfig |= STPWLEVEL;
if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("(scsi%d) Force setting STPWLEV bit\n", p->host_no);
+ printk("(scsi%d) Force setting STPWLEVEL bit\n", p->host_no);
}
else
{
- devconfig &= ~0x02;
+ devconfig &= ~STPWLEVEL;
if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("(scsi%d) Force clearing STPWLEV bit\n", p->host_no);
+ printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no);
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_write_config_byte(p->pdev, DEVCONFIG, devconfig);
@@ -8121,11 +8361,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
}
/*
- * Clear out any possible pending interrupts.
- */
- aic7xxx_clear_intstat(p);
-
- /*
* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
*/
if (p->features & AHC_TWIN)
@@ -8168,7 +8403,17 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term |
ENSTIMER | ACTNEGEN, SXFRCTL1);
aic_outb(p, 0, SIMODE0);
- aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+ /*
+ * If we are a cardbus adapter then don't enable SCSI reset detection.
+ * We shouldn't likely be sharing SCSI busses with someone else, and
+ * if we don't have a cable currently plugged into the controller then
+ * we won't have a power source for the SCSI termination, which means
+ * we'll see infinite incoming bus resets.
+ */
+ if(p->flags & AHC_NO_STPWR)
+ aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1);
+ else
+ aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
aic_outb(p, 0, SCSIRATE);
if ( p->features & AHC_ULTRA2)
aic_outb(p, 0, SCSIOFFSET);
@@ -8227,44 +8472,57 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
{
size_t array_size;
unsigned int hscb_physaddr;
- unsigned long temp;
array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
if (p->scb_data->hscbs == NULL)
{
- /*
- * A little padding so we can align thing the way we want
+ /* pci_alloc_consistent enforces the alignment already and
+ * clears the area as well.
*/
- p->scb_data->hscbs = kmalloc(array_size + 0x1f, GFP_ATOMIC);
+ p->scb_data->hscbs = pci_alloc_consistent(p->pdev, array_size,
+ &p->scb_data->hscbs_dma);
+ /* We have to use pci_free_consistent, not kfree */
+ p->scb_data->hscb_kmalloc_ptr = NULL;
+ p->scb_data->hscbs_dma_len = array_size;
}
if (p->scb_data->hscbs == NULL)
{
printk("(scsi%d) Unable to allocate hardware SCB array; "
"failing detection.\n", p->host_no);
+ aic_outb(p, 0, SIMODE1);
+#ifdef MODULE
+ enable_irq(p->irq);
+#endif
p->irq = 0;
return(0);
}
- /*
- * Save the actual kmalloc buffer pointer off, then align our
- * buffer to a 32 byte boundary
- */
- p->scb_data->hscb_kmalloc_ptr = p->scb_data->hscbs;
- temp = (unsigned long)p->scb_data->hscbs;
- temp += 0x1f;
- temp &= ~0x1f;
- p->scb_data->hscbs = (struct aic7xxx_hwscb *)temp;
- /* At least the control byte of each SCB needs to be 0. */
- memset(p->scb_data->hscbs, 0, array_size);
-
- /* Tell the sequencer where it can find the hardware SCB array. */
- hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
+
+ hscb_physaddr = p->scb_data->hscbs_dma;
aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR);
aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1);
aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2);
aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3);
/* Set up the fifo areas at the same time */
- hscb_physaddr = VIRT_TO_BUS(&p->untagged_scbs[0]);
+ p->untagged_scbs = pci_alloc_consistent(p->pdev, 3*256, &p->fifo_dma);
+ if (p->untagged_scbs == NULL)
+ {
+ printk("(scsi%d) Unable to allocate hardware FIFO arrays; "
+ "failing detection.\n", p->host_no);
+ p->irq = 0;
+ return(0);
+ }
+
+ p->qoutfifo = p->untagged_scbs + 256;
+ p->qinfifo = p->qoutfifo + 256;
+ for (i = 0; i < 256; i++)
+ {
+ p->untagged_scbs[i] = SCB_LIST_NULL;
+ p->qinfifo[i] = SCB_LIST_NULL;
+ p->qoutfifo[i] = SCB_LIST_NULL;
+ }
+
+ hscb_physaddr = p->fifo_dma;
aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR);
aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1);
aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2);
@@ -8315,11 +8573,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
first_aic7xxx = p;
/*
- * Clear out any possible pending interrupts, again.
- */
- aic7xxx_clear_intstat(p);
-
- /*
* Allocate the first set of scbs for this controller. This is to stream-
* line code elsewhere in the driver. If we have to check for the existence
* of scbs in certain code sections, it slows things down. However, as
@@ -8373,20 +8626,21 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel);
}
- /*
- * Some of the new Ultra2 chipsets need a longer delay after a chip
- * reset than just the init setup creates, so we have to delay here
- * before we go into a reset in order to make the chips happy.
- */
- if (p->features & AHC_ULTRA2)
- mdelay(250);
aic7xxx_reset_current_bus(p);
/*
- * Delay for the reset delay.
+ * Delay for the reset delay by setting the timer, this will delay
+ * future commands sent to any devices.
*/
- if (!reset_delay)
- aic7xxx_delay(AIC7XXX_RESET_DELAY);
+ p->flags |= AHC_RESET_DELAY;
+ for(i=0; i<MAX_TARGETS; i++)
+ {
+ p->dev_expires[i] = jiffies + (4 * HZ);
+ p->dev_timer_active |= (0x01 << i);
+ }
+ p->dev_timer.expires = p->dev_expires[p->scsi_id];
+ add_timer(&p->dev_timer);
+ p->dev_timer_active |= (0x01 << MAX_TARGETS);
}
else
{
@@ -8396,11 +8650,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
"the no_reset\n", p->host_no);
printk(KERN_INFO "(scsi%d) option unless you have a verifiable need "
"for it.\n", p->host_no);
- printk(KERN_INFO "(scsi%d) The no_reset option is known to break some "
- "systems,\n", p->host_no);
- printk(KERN_INFO "(scsi%d) and is not supported by the driver author\n",
- p->host_no);
- aic7xxx_delay(AIC7XXX_RESET_DELAY);
}
}
@@ -8426,10 +8675,23 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
{
printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
"controller.\n", p->host_no, p->irq);
+ aic_outb(p, 0, SIMODE1);
+#ifdef MODULE
+ enable_irq(p->irq);
+#endif
p->irq = 0;
return (0);
}
+ if(aic_inb(p, INTSTAT) & INT_PEND)
+ printk(INFO_LEAD "spurious interrupt during configuration, cleared.\n",
+ p->host_no, -1, -1 , -1);
+ aic7xxx_clear_intstat(p);
+
+#ifdef MODULE
+ enable_irq(p->irq);
+#endif
+
unpause_sequencer(p, /* unpause_always */ TRUE);
return (found);
@@ -8462,7 +8724,7 @@ aic7xxx_chip_reset(struct aic7xxx_host *p)
wait = 1000; /* 1 second (1000 * 1 msec) */
while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
{
- mdelay(1); /* 1 msec */
+ udelay(1); /* 1 msec */
}
pause_sequencer(p);
@@ -8566,9 +8828,11 @@ aic7xxx_free(struct aic7xxx_host *p)
*/
if (p->scb_data != NULL)
{
+ struct aic7xxx_scb_dma *scb_dma = NULL;
if (p->scb_data->hscbs != NULL)
{
- kfree(p->scb_data->hscb_kmalloc_ptr);
+ pci_free_consistent(p->pdev, p->scb_data->hscbs_dma_len,
+ p->scb_data->hscbs, p->scb_data->hscbs_dma);
p->scb_data->hscbs = p->scb_data->hscb_kmalloc_ptr = NULL;
}
/*
@@ -8579,6 +8843,14 @@ aic7xxx_free(struct aic7xxx_host *p)
*/
for (i = 0; i < p->scb_data->numscbs; i++)
{
+ if (p->scb_data->scb_array[i]->scb_dma != scb_dma)
+ {
+ scb_dma = p->scb_data->scb_array[i]->scb_dma;
+ pci_free_consistent(p->pdev, scb_dma->dma_len,
+ (void *)((unsigned long)scb_dma->dma_address
+ - scb_dma->dma_offset),
+ scb_dma->dma_address);
+ }
if (p->scb_data->scb_array[i]->kmalloc_ptr != NULL)
kfree(p->scb_data->scb_array[i]->kmalloc_ptr);
p->scb_data->scb_array[i] = NULL;
@@ -8606,6 +8878,7 @@ aic7xxx_free(struct aic7xxx_host *p)
}
}
+ pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma);
}
/*+F*************************************************************************
@@ -8657,15 +8930,15 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
if (!have_seeprom)
{
p->sc_size = 128;
- have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+ have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
scarray, p->sc_size, p->sc_type);
if (!have_seeprom)
{
if(p->sc_type == C46)
- have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+ have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
scarray, p->sc_size, C56_66);
else
- have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+ have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
scarray, p->sc_size, C46);
}
}
@@ -9098,260 +9371,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
template->sg_tablesize = AIC7XXX_MAX_SG;
-#if defined(__i386__) || defined(__alpha__)
-#ifdef CONFIG_PCI
- /*
- * PCI-bus chipset probe.
- */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
- if (pci_present())
- {
- if (pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82450GX,
- NULL))
- aic7xxx_no_probe = 1;
- if (pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82451NX,
- NULL))
- aic7xxx_no_probe = 1;
- }
-#else
-#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca
- if (pcibios_present())
- {
- unsigned char pci_bus, pci_devfn;
- if (!(pcibios_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82450GX,
- 0, &pci_bus, &pci_devfn)) )
- aic7xxx_no_probe = 1;
- if (!(pcibios_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82451NX,
- 0, &pci_bus, &pci_devfn)) )
- aic7xxx_no_probe = 1;
- }
-#endif /* LINUX_VERSION_CODE */
-#endif /* CONFIG_PCI */
- /*
- * EISA/VL-bus card signature probe.
- */
- slot = MINSLOT;
- while ( (slot <= MAXSLOT) &&
- !(aic7xxx_no_probe) )
- {
- base = SLOTBASE(slot) + MINREG;
-
- if (check_region(base, MAXREG - MINREG))
- {
- /*
- * Some other driver has staked a
- * claim to this i/o region already.
- */
- slot++;
- continue; /* back to the beginning of the for loop */
- }
- flags = 0;
- type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
- if (type == -1)
- {
- slot++;
- continue;
- }
- temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
- if (temp_p == NULL)
- {
- printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
- slot++;
- continue; /* back to the beginning of the while loop */
- }
- /*
- * Pause the card preserving the IRQ type. Allow the operator
- * to override the IRQ trigger.
- */
- if (aic7xxx_irq_trigger == 1)
- hcntrl = IRQMS; /* Level */
- else if (aic7xxx_irq_trigger == 0)
- hcntrl = 0; /* Edge */
- else
- hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
- memset(temp_p, 0, sizeof(struct aic7xxx_host));
- temp_p->unpause = hcntrl | INTEN;
- temp_p->pause = hcntrl | PAUSE | INTEN;
- temp_p->base = base;
- temp_p->mbase = 0;
- temp_p->maddr = 0;
- temp_p->pci_bus = 0;
- temp_p->pci_device_fn = slot;
- aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
- while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
- if (aic7xxx_chip_reset(temp_p) == -1)
- temp_p->irq = 0;
- else
- temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
- temp_p->flags |= AHC_PAGESCBS;
-
- switch (temp_p->irq)
- {
- case 9:
- case 10:
- case 11:
- case 12:
- case 14:
- case 15:
- break;
-
- default:
- printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
- "level %d, ignoring.\n", temp_p->irq);
- kfree(temp_p);
- slot++;
- continue; /* back to the beginning of the while loop */
- }
-
- /*
- * We are commited now, everything has been checked and this card
- * has been found, now we just set it up
- */
-
- /*
- * Insert our new struct into the list at the end
- */
- if (list_p == NULL)
- {
- list_p = current_p = temp_p;
- }
- else
- {
- current_p = list_p;
- while (current_p->next != NULL)
- current_p = current_p->next;
- current_p->next = temp_p;
- }
-
- switch (type)
- {
- case 0:
- temp_p->board_name_index = 2;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at EISA %d\n",
- board_names[2], slot);
- /* FALLTHROUGH */
- case 1:
- {
- temp_p->chip = AHC_AIC7770 | AHC_EISA;
- temp_p->features |= AHC_AIC7770_FE;
- temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
-
- /*
- * Get the primary channel information. Right now we don't
- * do anything with this, but someday we will be able to inform
- * the mid-level SCSI code which channel is primary.
- */
- if (temp_p->board_name_index == 0)
- {
- temp_p->board_name_index = 3;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at EISA %d\n",
- board_names[3], slot);
- }
- if (temp_p->bios_control & CHANNEL_B_PRIMARY)
- {
- temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
- }
-
- if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
- {
- temp_p->flags &= ~AHC_BIOS_ENABLED;
- }
- else
- {
- temp_p->flags &= ~AHC_USEDEFAULTS;
- temp_p->flags |= AHC_BIOS_ENABLED;
- if ( (temp_p->bios_control & 0x20) == 0 )
- {
- temp_p->bios_address = 0xcc000;
- temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
- }
- else
- {
- temp_p->bios_address = 0xd0000;
- temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
- }
- }
- temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
- temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
- if (temp_p->features & AHC_WIDE)
- {
- temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
- temp_p->scsi_id_b = temp_p->scsi_id;
- }
- else
- {
- temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
- temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
- }
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- break;
- }
-
- case 2:
- case 3:
- temp_p->chip = AHC_AIC7770 | AHC_VL;
- temp_p->features |= AHC_AIC7770_FE;
- if (type == 2)
- temp_p->flags |= AHC_BIOS_ENABLED;
- else
- temp_p->flags &= ~AHC_BIOS_ENABLED;
- if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
- sxfrctl1 = STPWEN;
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- temp_p->board_name_index = 4;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at VLB %d\n",
- board_names[2], slot);
- switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
- {
- case 0x00:
- temp_p->bios_address = 0xe0000;
- break;
- case 0x20:
- temp_p->bios_address = 0xc8000;
- break;
- case 0x40:
- temp_p->bios_address = 0xd0000;
- break;
- case 0x60:
- temp_p->bios_address = 0xd8000;
- break;
- default:
- break; /* can't get here */
- }
- break;
-
- default: /* Won't get here. */
- break;
- }
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
- (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
- temp_p->irq,
- (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
- }
-
- /*
- * Set the FIFO threshold and the bus off time.
- */
- hostconf = aic_inb(temp_p, HOSTCONF);
- aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
- aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
- slot++;
- found++;
- }
-
-#endif /* defined(__i386__) || defined(__alpha__) */
-
#ifdef CONFIG_PCI
/*
* PCI-bus probe.
@@ -9485,7 +9504,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
AHC_AIC7896_FE, 25,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWR,
AHC_AIC7860_FE, 26,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
@@ -9594,8 +9613,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
if (aic7xxx_verbose & VERBOSE_PROBE2)
printk("aic7xxx: <%s> at PCI %d/%d\n",
board_names[aic_pdevs[i].board_name_index],
- PCI_SLOT(temp_p->pdev->devfn),
- PCI_FUNC(temp_p->pdev->devfn));
+ PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
pci_read_config_word(pdev, PCI_COMMAND, &command);
if (aic7xxx_verbose & VERBOSE_PROBE2)
{
@@ -9651,8 +9670,9 @@ aic7xxx_detect(Scsi_Host_Template *template)
if ( temp_p == NULL )
continue;
if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at PCI %d/%d\n",
+ printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
@@ -9682,14 +9702,28 @@ aic7xxx_detect(Scsi_Host_Template *template)
#endif /* AIC7XXX_STRICT_PCI_SETUP */
#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
+ if(check_region(temp_p->base, MAXREG - MINREG))
+ {
+ printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
+ board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
+ PCI_SLOT(temp_p->pci_device_fn),
+ PCI_FUNC(temp_p->pci_device_fn));
+ printk("aic7xxx: I/O ports already in use, ignoring.\n");
+ kfree(temp_p);
+ temp_p = NULL;
+ continue;
+ }
+
temp_p->unpause = INTEN;
temp_p->pause = temp_p->unpause | PAUSE;
if ( ((temp_p->base == 0) &&
(temp_p->mbase == 0)) ||
(temp_p->irq == 0) )
{
- printk("aic7xxx: <%s> at PCI %d/%d\n",
+ printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
@@ -9724,8 +9758,9 @@ aic7xxx_detect(Scsi_Host_Template *template)
/*
* OK.....we failed our test....go back to programmed I/O
*/
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
@@ -9742,6 +9777,11 @@ aic7xxx_detect(Scsi_Host_Template *template)
#endif
/*
+ * Lock out other contenders for our i/o space.
+ */
+ request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
+
+ /*
* We HAVE to make sure the first pause_sequencer() and all other
* subsequent I/O that isn't PCI config space I/O takes place
* after the MMAPed I/O region is configured and tested. The
@@ -9773,14 +9813,31 @@ aic7xxx_detect(Scsi_Host_Template *template)
/*
* Get current termination setting
*/
- sxfrctl1 = aic_inb(temp_p, SXFRCTL1) & STPWEN;
+ sxfrctl1 = aic_inb(temp_p, SXFRCTL1);
if (aic7xxx_chip_reset(temp_p) == -1)
{
+ release_region(temp_p->base, MAXREG - MINREG);
kfree(temp_p);
temp_p = NULL;
continue;
}
+ /*
+ * Very quickly put the term setting back into the register since
+ * the chip reset may cause odd things to happen. This is to keep
+ * LVD busses with lots of drives from draining the power out of
+ * the diffsense line before we get around to running the
+ * configure_termination() function. Also restore the STPWLEVEL
+ * bit of DEVCONFIG
+ */
+ aic_outb(temp_p, sxfrctl1, SXFRCTL1);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+ pcibios_write_config_dword(temp_p->pci_bus, temp_p->pci_device_fn,
+ DEVCONFIG, devconfig);
+#else
+ pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig);
+#endif
+ sxfrctl1 &= STPWEN;
/*
* We need to set the CHNL? assignments before loading the SEEPROM
@@ -9815,7 +9872,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
case AHC_AIC7896: /* 7896/7 */
case AHC_AIC7899: /* 7899 */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
- if (PCI_FUNC(temp_p->pdev->devfn) != 0)
+ if (PCI_FUNC(pdev->devfn) != 0)
{
temp_p->flags |= AHC_CHNLB;
}
@@ -10007,8 +10064,9 @@ aic7xxx_detect(Scsi_Host_Template *template)
}
else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
{
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk("aic7xxx: external SCB RAM detected, "
@@ -10025,8 +10083,9 @@ aic7xxx_detect(Scsi_Host_Template *template)
}
else if (devconfig & RAMPSM)
{
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk("aic7xxx: external SCB RAM detected, "
@@ -10091,6 +10150,235 @@ aic7xxx_detect(Scsi_Host_Template *template)
} /* for PCI_DEVICES */
} /* PCI BIOS present */
#endif CONFIG_PCI
+
+#if defined(__i386__) || defined(__alpha__)
+ /*
+ * EISA/VL-bus card signature probe.
+ */
+ slot = MINSLOT;
+ while ( (slot <= MAXSLOT) &&
+ !(aic7xxx_no_probe) )
+ {
+ base = SLOTBASE(slot) + MINREG;
+
+ if (check_region(base, MAXREG - MINREG))
+ {
+ /*
+ * Some other driver has staked a
+ * claim to this i/o region already.
+ */
+ slot++;
+ continue; /* back to the beginning of the for loop */
+ }
+ flags = 0;
+ type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
+ if (type == -1)
+ {
+ slot++;
+ continue;
+ }
+ temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
+ if (temp_p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+ slot++;
+ continue; /* back to the beginning of the while loop */
+ }
+ /*
+ * Lock out other contenders for our i/o space.
+ */
+ request_region(base, MAXREG - MINREG, "aic7xxx");
+
+ /*
+ * Pause the card preserving the IRQ type. Allow the operator
+ * to override the IRQ trigger.
+ */
+ if (aic7xxx_irq_trigger == 1)
+ hcntrl = IRQMS; /* Level */
+ else if (aic7xxx_irq_trigger == 0)
+ hcntrl = 0; /* Edge */
+ else
+ hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
+ memset(temp_p, 0, sizeof(struct aic7xxx_host));
+ temp_p->unpause = hcntrl | INTEN;
+ temp_p->pause = hcntrl | PAUSE | INTEN;
+ temp_p->base = base;
+ temp_p->mbase = 0;
+ temp_p->maddr = 0;
+ temp_p->pci_bus = 0;
+ temp_p->pci_device_fn = slot;
+ aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
+ while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+ if (aic7xxx_chip_reset(temp_p) == -1)
+ temp_p->irq = 0;
+ else
+ temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
+ temp_p->flags |= AHC_PAGESCBS;
+
+ switch (temp_p->irq)
+ {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ break;
+
+ default:
+ printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+ "level %d, ignoring.\n", temp_p->irq);
+ kfree(temp_p);
+ release_region(base, MAXREG - MINREG);
+ slot++;
+ continue; /* back to the beginning of the while loop */
+ }
+
+ /*
+ * We are commited now, everything has been checked and this card
+ * has been found, now we just set it up
+ */
+
+ /*
+ * Insert our new struct into the list at the end
+ */
+ if (list_p == NULL)
+ {
+ list_p = current_p = temp_p;
+ }
+ else
+ {
+ current_p = list_p;
+ while (current_p->next != NULL)
+ current_p = current_p->next;
+ current_p->next = temp_p;
+ }
+
+ switch (type)
+ {
+ case 0:
+ temp_p->board_name_index = 2;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("aic7xxx: <%s> at EISA %d\n",
+ board_names[2], slot);
+ /* FALLTHROUGH */
+ case 1:
+ {
+ temp_p->chip = AHC_AIC7770 | AHC_EISA;
+ temp_p->features |= AHC_AIC7770_FE;
+ temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
+
+ /*
+ * Get the primary channel information. Right now we don't
+ * do anything with this, but someday we will be able to inform
+ * the mid-level SCSI code which channel is primary.
+ */
+ if (temp_p->board_name_index == 0)
+ {
+ temp_p->board_name_index = 3;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("aic7xxx: <%s> at EISA %d\n",
+ board_names[3], slot);
+ }
+ if (temp_p->bios_control & CHANNEL_B_PRIMARY)
+ {
+ temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
+ }
+
+ if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
+ {
+ temp_p->flags &= ~AHC_BIOS_ENABLED;
+ }
+ else
+ {
+ temp_p->flags &= ~AHC_USEDEFAULTS;
+ temp_p->flags |= AHC_BIOS_ENABLED;
+ if ( (temp_p->bios_control & 0x20) == 0 )
+ {
+ temp_p->bios_address = 0xcc000;
+ temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
+ }
+ else
+ {
+ temp_p->bios_address = 0xd0000;
+ temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
+ }
+ }
+ temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
+ temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
+ if (temp_p->features & AHC_WIDE)
+ {
+ temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
+ temp_p->scsi_id_b = temp_p->scsi_id;
+ }
+ else
+ {
+ temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
+ temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
+ }
+ aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+ break;
+ }
+
+ case 2:
+ case 3:
+ temp_p->chip = AHC_AIC7770 | AHC_VL;
+ temp_p->features |= AHC_AIC7770_FE;
+ if (type == 2)
+ temp_p->flags |= AHC_BIOS_ENABLED;
+ else
+ temp_p->flags &= ~AHC_BIOS_ENABLED;
+ if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
+ sxfrctl1 = STPWEN;
+ aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+ temp_p->board_name_index = 4;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("aic7xxx: <%s> at VLB %d\n",
+ board_names[2], slot);
+ switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
+ {
+ case 0x00:
+ temp_p->bios_address = 0xe0000;
+ break;
+ case 0x20:
+ temp_p->bios_address = 0xc8000;
+ break;
+ case 0x40:
+ temp_p->bios_address = 0xd0000;
+ break;
+ case 0x60:
+ temp_p->bios_address = 0xd8000;
+ break;
+ default:
+ break; /* can't get here */
+ }
+ break;
+
+ default: /* Won't get here. */
+ break;
+ }
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ {
+ printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
+ (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
+ temp_p->irq,
+ (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+ printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+ (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
+ }
+
+ /*
+ * Set the FIFO threshold and the bus off time.
+ */
+ hostconf = aic_inb(temp_p, HOSTCONF);
+ aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
+ aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
+ slot++;
+ found++;
+ }
+
+#endif /* defined(__i386__) || defined(__alpha__) */
+
/*
* Now, we re-order the probed devices by BIOS address and BUS class.
* In general, we follow this algorithm to make the adapters show up
@@ -10333,6 +10621,7 @@ aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
cmd->lun = 0;
cmd->request_bufflen = 255;
cmd->request_buffer = buffer;
+ cmd->sc_data_direction = SCSI_DATA_READ;
cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
cmd->bufflen = 0;
cmd->buffer = NULL;
@@ -10391,7 +10680,7 @@ aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
* instead of slowing down if those exist. That's hard to do with simple
* checksums though.
*/
- if(aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
"validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -10422,7 +10711,7 @@ aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
}
else
{
- if(aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "Performing Domain validation.\n",
p->host_no, CTL_OF_CMD(cmd));
@@ -10447,7 +10736,7 @@ aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
}
else
{
- if( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
(p->needdv & (1<<tindex)) )
{
printk(INFO_LEAD "Successfully completed Domain validation.\n",
@@ -10663,7 +10952,8 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* little-endian format.
*/
hscb->SCSI_cmd_length = cmd->cmd_len;
- hscb->SCSI_cmd_pointer = cpu_to_le32(VIRT_TO_BUS(cmd->cmnd));
+ memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len);
+ hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd));
if (cmd->use_sg)
{
@@ -10675,10 +10965,11 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* differences and the kernel SG list uses virtual addresses where
* we need physical addresses.
*/
- int i;
+ int i, use_sg;
sg = (struct scatterlist *)cmd->request_buffer;
scb->sg_length = 0;
+ use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
/*
* Copy the segments into the SG array. NOTE!!! - We used to
* have the first entry both in the data_pointer area and the first
@@ -10686,29 +10977,34 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* entry in both places, but now we download the address of
* scb->sg_list[1] instead of 0 to the sg pointer in the hscb.
*/
- for (i = 0; i < cmd->use_sg; i++)
+ for (i = 0; i < use_sg; i++)
{
- scb->sg_list[i].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
- scb->sg_list[i].length = cpu_to_le32(sg[i].length);
- scb->sg_length += sg[i].length;
+ unsigned int len = sg_dma_len(sg+i);
+ scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg+i));
+ scb->sg_list[i].length = cpu_to_le32(len);
+ scb->sg_length += len;
}
/* Copy the first SG into the data pointer area. */
hscb->data_pointer = scb->sg_list[0].address;
hscb->data_count = scb->sg_list[0].length;
- scb->sg_count = cmd->use_sg;
- hscb->SG_segment_count = cmd->use_sg;
- hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[1]));
+ scb->sg_count = i;
+ hscb->SG_segment_count = i;
+ hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1]));
}
else
{
if (cmd->request_bufflen)
{
- scb->sg_count = 1;
- scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
+ unsigned int address = pci_map_single(p->pdev, cmd->request_buffer,
+ cmd->request_bufflen,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ aic7xxx_mapping(cmd) = address;
+ scb->sg_list[0].address = cpu_to_le32(address);
scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
+ scb->sg_count = 1;
scb->sg_length = cmd->request_bufflen;
hscb->SG_segment_count = 1;
- hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
+ hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[0]));
hscb->data_count = scb->sg_list[0].length;
hscb->data_pointer = scb->sg_list[0].address;
}
@@ -11991,7 +12287,7 @@ aic7xxx_print_card(struct aic7xxx_host *p)
break;
case AHC_PCI:
default:
- printk("PCI %d/%d.\n", PCI_SLOT(p->pci_device_fn),
+ printk("PCI %d/%d/%d.\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
PCI_FUNC(p->pci_device_fn));
break;
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
index 6cc347d5b..fb554727b 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.reg
+++ b/drivers/scsi/aic7xxx/aic7xxx.reg
@@ -691,7 +691,8 @@ register INTSTAT {
mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/
mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */
mask EXTENDED_MSG 0x40|SEQINT /* Extended message received */
- mask ABORT_REQUESTED 0x50|SEQINT /* Reconect of aborted SCB */
+ mask WIDE_RESIDUE 0x50|SEQINT /* need kernel to back up */
+ /* the SG array for us */
mask REJECT_MSG 0x60|SEQINT /* Reject message received */
mask BAD_STATUS 0x70|SEQINT /* Bad status from target */
mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
index 8e8dc98ee..de3afbf92 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.seq
+++ b/drivers/scsi/aic7xxx/aic7xxx.seq
@@ -517,10 +517,12 @@ data_phase_loop:
}
data_phase_inbounds:
/* If we are the last SG block, tell the hardware. */
-if ((p->features & AHC_ULTRA2) == 0) {
cmp SG_COUNT,0x01 jne data_phase_wideodd;
- and DMAPARAMS, ~WIDEODD;
-}
+ if ((p->features & AHC_ULTRA2) == 0) {
+ and DMAPARAMS, ~WIDEODD;
+ } else {
+ mvi SG_CACHEPTR, LAST_SEG;
+ }
data_phase_wideodd:
if ((p->features & AHC_ULTRA2) != 0) {
mov SINDEX, ALLONES;
@@ -530,7 +532,7 @@ data_phase_dma_loop:
test SSTAT0, SDONE jnz data_phase_dma_done;
test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */
data_phase_dma_phasemis:
- test SSTAT0,SDONE jnz . + 2;
+ test SSTAT0,SDONE jnz data_phase_dma_done;
clr SINDEX; /* Remember the phasemiss */
} else {
mov DMAPARAMS call dma;
@@ -615,9 +617,10 @@ prefetched_segs_avail:
test SSTAT1, REQINIT jz .;
test SSTAT1,PHASEMIS jz data_phase_loop;
+/* This drops the last SG segment down to the shadow layer for us */
if ((p->features & AHC_ULTRA2) != 0) {
mov DFCNTRL, DMAPARAMS;
- test SSTAT0, SDONE jnz .;
+ test SSTAT0, SDONE jnz .;
}
data_phase_finish:
@@ -713,7 +716,7 @@ p_command:
mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
test SSTAT0, SDONE jnz .;
p_command_dma_loop:
- test SSTAT0, DMADONE jnz p_command_ultra2_dma_done;
+ test SSTAT0, SDONE jnz p_command_ultra2_dma_done;
test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */
p_command_ultra2_dma_done:
and DFCNTRL, ~HDMAEN;
@@ -830,6 +833,7 @@ p_mesgin:
cmp A,MSG_EXTENDED je mesgin_extended;
cmp A,MSG_MESSAGE_REJECT je mesgin_reject;
cmp A,MSG_NOOP je mesgin_done;
+ cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_wide_residue;
rej_mesgin:
/*
@@ -1057,6 +1061,36 @@ mesgin_reject:
jmp mesgin_done;
/*
+ * Wide Residue. We handle the simple cases, but pass of the one hard case
+ * to the kernel (when the residue byte happened to cause us to advance our
+ * sg element array, so we know have to back that advance out).
+ */
+mesgin_wide_residue:
+ mvi ARG_1 call inb_next; /* ACK the wide_residue and get */
+ /* the size byte */
+/*
+ * See if we'll ignore this wide residue (because it's an overrun byte)
+ */
+ if ((p->features & AHC_ULTRA2) != 0) {
+ test SSTAT2, WIDE_RES jnz mesgin_done;
+ } else {
+ test SCB_RESID_SGCNT,0xff jnz wide_residue_int;
+ test SCB_RESID_DCNT[0],0xff jnz wide_residue_int;
+ test SCB_RESID_DCNT[1],0xff jnz wide_residue_int;
+ test SCB_RESID_DCNT[2],0xff jnz wide_residue_int;
+ jmp mesgin_done;
+ }
+wide_residue_int:
+/*
+ * In order for this to be reliable, we have to do all sorts of horrible
+ * magic in terms of resetting the datafifo and reloading the shadow layer
+ * with the correct new values (so that a subsequent save data pointers
+ * message will do the right thing). We let the kernel do that work.
+ */
+ mvi INTSTAT,WIDE_RESIDUE;
+ jmp mesgin_done;
+
+/*
* [ ADD MORE MESSAGE HANDLING HERE ]
*/
@@ -1093,7 +1127,7 @@ inb_next_wait:
* before continuing.
*/
test SSTAT1, REQINIT jz inb_next_wait;
- test SSTAT1, SCSIPERR jnz inb_next_wait;
+ test SSTAT1, SCSIPERR jnz .;
and LASTPHASE, PHASE_MASK, SCSISIGI;
cmp LASTPHASE, P_MESGIN jne mesgin_phasemis;
inb_first:
diff --git a/drivers/scsi/aic7xxx_proc.c b/drivers/scsi/aic7xxx_proc.c
index 1fb00893e..ec80af90d 100644
--- a/drivers/scsi/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx_proc.c
@@ -178,7 +178,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
size += sprintf(BLS, " SCSI Adapter: %s\n",
board_names[p->board_name_index]);
if (p->flags & AHC_TWIN)
- size += sprintf(BLS, " Twin Channel\n");
+ size += sprintf(BLS, " Twin Channel Controller ");
else
{
char *channel = "";
@@ -209,9 +209,22 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
ultra = "Ultra-2 LVD/SE ";
else if (p->features & AHC_ULTRA)
ultra = "Ultra ";
- size += sprintf(BLS, " %s%sController%s\n",
+ size += sprintf(BLS, " %s%sController%s ",
ultra, wide, channel);
}
+ switch(p->chip & ~AHC_CHIPID_MASK)
+ {
+ case AHC_VL:
+ size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
+ break;
+ case AHC_EISA:
+ size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
+ break;
+ default:
+ size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
+ PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
+ break;
+ }
if( !(p->maddr) )
{
size += sprintf(BLS, " Programmed I/O Base: %lx\n", p->base);
@@ -224,11 +237,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
{
size += sprintf(BLS, " BIOS Memory Address: 0x%08x\n", p->bios_address);
}
- if( p->chip & AHC_PCI )
- {
- size += sprintf(BLS, " PCI Bus 0x%02x Device 0x%02x\n", p->pci_bus,
- p->pci_device_fn);
- }
size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
(p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
diff --git a/drivers/scsi/aic7xxx_reg.h b/drivers/scsi/aic7xxx_reg.h
index f86e1bec8..4baa00911 100644
--- a/drivers/scsi/aic7xxx_reg.h
+++ b/drivers/scsi/aic7xxx_reg.h
@@ -188,8 +188,8 @@
#define BRDRW 0x04
#define BRDRW_ULTRA2 0x02
#define BRDCTL1 0x02
-#define BRDSTB_ULTRA2 0x01
#define BRDCTL0 0x01
+#define BRDSTB_ULTRA2 0x01
#define SEECTL 0x1e
#define EXTARBACK 0x80
@@ -402,7 +402,7 @@
#define RESIDUAL 0x81
#define BAD_STATUS 0x71
#define REJECT_MSG 0x61
-#define ABORT_REQUESTED 0x51
+#define WIDE_RESIDUE 0x51
#define EXTENDED_MSG 0x41
#define NO_MATCH 0x31
#define NO_IDENT 0x21
@@ -465,6 +465,8 @@
#define TARGCRCENDEN 0x08
#define TARGCRCCNTEN 0x04
+#define QOUTCNT 0x9e
+
#define SCSIPHASE 0x9e
#define SP_STATUS 0x20
#define SP_COMMAND 0x10
@@ -473,8 +475,6 @@
#define SP_DATA_IN 0x02
#define SP_DATA_OUT 0x01
-#define QOUTCNT 0x9e
-
#define SFUNCT 0x9f
#define ALT_MODE 0x80
@@ -595,8 +595,8 @@
#define RD_DFTHRSH_63 0x03
#define RD_DFTHRSH_50 0x02
#define RD_DFTHRSH_25 0x01
-#define WR_DFTHRSH_MIN 0x00
#define RD_DFTHRSH_MIN 0x00
+#define WR_DFTHRSH_MIN 0x00
#define SG_CACHEPTR 0xfc
#define SG_USER_DATA 0xfc
@@ -604,18 +604,18 @@
#define LAST_SEG_DONE 0x01
+#define CMD_GROUP_CODE_SHIFT 0x05
+#define BUS_8_BIT 0x00
+#define QOUTFIFO_OFFSET 0x01
+#define CCSGRAM_MAXSEGS 0x10
#define CMD_GROUP2_BYTE_DELTA 0xfa
#define MAX_OFFSET_8BIT 0x0f
#define BUS_16_BIT 0x01
#define QINFIFO_OFFSET 0x02
#define CMD_GROUP5_BYTE_DELTA 0x0b
-#define CMD_GROUP_CODE_SHIFT 0x05
#define MAX_OFFSET_ULTRA2 0x7f
#define MAX_OFFSET_16BIT 0x08
-#define BUS_8_BIT 0x00
-#define QOUTFIFO_OFFSET 0x01
#define UNTAGGEDSCB_OFFSET 0x00
-#define CCSGRAM_MAXSEGS 0x10
#define SCB_LIST_NULL 0xff
#define SG_SIZEOF 0x08
#define CMD_GROUP4_BYTE_DELTA 0x04
diff --git a/drivers/scsi/aic7xxx_seq.c b/drivers/scsi/aic7xxx_seq.c
index 49502b6cd..511bfcb73 100644
--- a/drivers/scsi/aic7xxx_seq.c
+++ b/drivers/scsi/aic7xxx_seq.c
@@ -26,12 +26,12 @@ static unsigned char seqprog[] = {
0x00, 0x4d, 0x12, 0x70,
0x01, 0x4e, 0x9c, 0x18,
0xbf, 0x60, 0xc0, 0x08,
- 0x00, 0x6a, 0xa8, 0x5c,
+ 0x00, 0x6a, 0xbe, 0x5c,
0xff, 0x4e, 0xc8, 0x18,
- 0x02, 0x6a, 0xbe, 0x5b,
+ 0x02, 0x6a, 0xd4, 0x5b,
0xff, 0x52, 0x20, 0x09,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0x52, 0x34, 0x5c,
+ 0x00, 0x52, 0x4a, 0x5c,
0x03, 0xb0, 0x52, 0x31,
0xff, 0xb0, 0x52, 0x09,
0xff, 0xb1, 0x54, 0x09,
@@ -76,7 +76,7 @@ static unsigned char seqprog[] = {
0x10, 0x03, 0xfc, 0x78,
0xff, 0x50, 0xc8, 0x08,
0x88, 0x6a, 0xcc, 0x00,
- 0x49, 0x6a, 0x24, 0x5c,
+ 0x49, 0x6a, 0x3a, 0x5c,
0x01, 0x6a, 0x26, 0x01,
0xff, 0x6a, 0xca, 0x08,
0x08, 0x01, 0x02, 0x00,
@@ -117,11 +117,11 @@ static unsigned char seqprog[] = {
0xff, 0x65, 0xca, 0x18,
0xff, 0x65, 0xd8, 0x68,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x9a, 0x5c,
+ 0x00, 0x65, 0xb0, 0x5c,
0x40, 0x51, 0xf0, 0x78,
0xe4, 0x6a, 0x06, 0x00,
0x08, 0x01, 0x02, 0x00,
- 0x04, 0x6a, 0x56, 0x5b,
+ 0x04, 0x6a, 0x6c, 0x5b,
0x01, 0x50, 0xa0, 0x18,
0x00, 0x50, 0xf6, 0xe0,
0xff, 0x6a, 0xa0, 0x08,
@@ -147,13 +147,13 @@ static unsigned char seqprog[] = {
0x08, 0x6a, 0x66, 0x58,
0x80, 0x6a, 0x68, 0x00,
0x80, 0x36, 0x6c, 0x00,
- 0x00, 0x65, 0x08, 0x5c,
+ 0x00, 0x65, 0x1e, 0x5c,
0xff, 0x3d, 0xc8, 0x08,
0xbf, 0x64, 0x5a, 0x79,
- 0x80, 0x64, 0x20, 0x72,
- 0xa0, 0x64, 0x50, 0x72,
- 0xc0, 0x64, 0x48, 0x72,
- 0xe0, 0x64, 0x90, 0x72,
+ 0x80, 0x64, 0x22, 0x72,
+ 0xa0, 0x64, 0x52, 0x72,
+ 0xc0, 0x64, 0x4a, 0x72,
+ 0xe0, 0x64, 0x92, 0x72,
0x01, 0x6a, 0x22, 0x01,
0x00, 0x65, 0x22, 0x41,
0xf7, 0x11, 0x22, 0x08,
@@ -173,13 +173,13 @@ static unsigned char seqprog[] = {
0x03, 0xa9, 0x18, 0x31,
0x03, 0xa9, 0x10, 0x30,
0x08, 0x6a, 0xcc, 0x00,
- 0xa9, 0x6a, 0x1e, 0x5c,
+ 0xa9, 0x6a, 0x34, 0x5c,
0x00, 0x65, 0x7a, 0x41,
0xa8, 0x6a, 0x6a, 0x00,
0x79, 0x6a, 0x6a, 0x00,
0x40, 0x3d, 0x62, 0x69,
0x04, 0x35, 0x6a, 0x00,
- 0x00, 0x65, 0x78, 0x5b,
+ 0x00, 0x65, 0x8e, 0x5b,
0x80, 0x6a, 0xd4, 0x01,
0x10, 0x36, 0x4e, 0x69,
0x10, 0x36, 0x6c, 0x00,
@@ -187,10 +187,10 @@ static unsigned char seqprog[] = {
0x03, 0x8c, 0x10, 0x30,
0x05, 0xa3, 0x70, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0xac, 0x6a, 0x16, 0x5c,
- 0x00, 0x65, 0x10, 0x5c,
+ 0xac, 0x6a, 0x2c, 0x5c,
+ 0x00, 0x65, 0x26, 0x5c,
0x38, 0x6a, 0xcc, 0x00,
- 0xa3, 0x6a, 0x1a, 0x5c,
+ 0xa3, 0x6a, 0x30, 0x5c,
0xff, 0x38, 0x8a, 0x69,
0x80, 0x02, 0x04, 0x00,
0xe7, 0x35, 0x6a, 0x08,
@@ -199,51 +199,52 @@ static unsigned char seqprog[] = {
0xff, 0x6a, 0x10, 0x00,
0xff, 0x6a, 0x12, 0x00,
0xff, 0x6a, 0x14, 0x00,
- 0x01, 0x38, 0x8e, 0x61,
+ 0x01, 0x38, 0x90, 0x61,
0xbf, 0x35, 0x6a, 0x08,
+ 0x02, 0x6a, 0xf8, 0x01,
0xff, 0x69, 0xca, 0x08,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x0b, 0x92, 0x69,
- 0x04, 0x0b, 0x9e, 0x69,
- 0x10, 0x0c, 0x94, 0x79,
- 0x04, 0x0b, 0x9c, 0x69,
+ 0x04, 0x0b, 0x94, 0x69,
+ 0x04, 0x0b, 0xa0, 0x69,
+ 0x10, 0x0c, 0x96, 0x79,
+ 0x04, 0x0b, 0xa0, 0x69,
0xff, 0x6a, 0xca, 0x08,
- 0x00, 0x35, 0x60, 0x5b,
- 0x80, 0x02, 0xf2, 0x69,
- 0xff, 0x65, 0xe2, 0x79,
+ 0x00, 0x35, 0x76, 0x5b,
+ 0x80, 0x02, 0xf4, 0x69,
+ 0xff, 0x65, 0xe4, 0x79,
0xff, 0x38, 0x70, 0x18,
- 0xff, 0x38, 0xe2, 0x79,
- 0x80, 0xea, 0xbe, 0x61,
+ 0xff, 0x38, 0xe4, 0x79,
+ 0x80, 0xea, 0xc0, 0x61,
0xef, 0x38, 0xc8, 0x18,
0x80, 0x6a, 0xc8, 0x00,
- 0x00, 0x65, 0xb0, 0x49,
+ 0x00, 0x65, 0xb2, 0x49,
0x33, 0x38, 0xc8, 0x28,
0xff, 0x64, 0xd0, 0x09,
0x04, 0x39, 0xc0, 0x31,
0x09, 0x6a, 0xd6, 0x01,
- 0x80, 0xeb, 0xb6, 0x79,
+ 0x80, 0xeb, 0xb8, 0x79,
0xf7, 0xeb, 0xd6, 0x09,
- 0x08, 0xeb, 0xba, 0x69,
+ 0x08, 0xeb, 0xbc, 0x69,
0x01, 0x6a, 0xd6, 0x01,
0x08, 0xe9, 0x10, 0x31,
0x03, 0x8c, 0x10, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0x39, 0x6a, 0x1c, 0x5c,
+ 0x39, 0x6a, 0x32, 0x5c,
0x08, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x0d, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x9a, 0x5c,
- 0x88, 0x6a, 0x8a, 0x5c,
- 0x00, 0x65, 0x10, 0x5c,
+ 0x00, 0x65, 0xb0, 0x5c,
+ 0x88, 0x6a, 0xa0, 0x5c,
+ 0x00, 0x65, 0x26, 0x5c,
0xff, 0x6a, 0xc8, 0x08,
0x08, 0x39, 0x72, 0x18,
0x00, 0x3a, 0x74, 0x20,
- 0x01, 0x0c, 0xda, 0x79,
+ 0x01, 0x0c, 0xdc, 0x79,
0x10, 0x0c, 0x7a, 0x79,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x0b, 0xe0, 0x69,
- 0x00, 0x65, 0xfa, 0x59,
+ 0x04, 0x0b, 0xe2, 0x69,
+ 0x00, 0x65, 0xfc, 0x59,
0x03, 0x08, 0x52, 0x31,
0xff, 0x38, 0x50, 0x09,
0xff, 0x08, 0x52, 0x09,
@@ -251,275 +252,285 @@ static unsigned char seqprog[] = {
0xff, 0x0a, 0x56, 0x09,
0xff, 0x38, 0x50, 0x09,
0x00, 0x65, 0x22, 0x41,
- 0x00, 0x65, 0xfa, 0x59,
+ 0x00, 0x65, 0xfc, 0x59,
0x7f, 0x02, 0x04, 0x08,
0xe1, 0x6a, 0x22, 0x01,
0x00, 0x65, 0x22, 0x41,
- 0x04, 0x93, 0x10, 0x6a,
+ 0x04, 0x93, 0x12, 0x6a,
0xdf, 0x93, 0x26, 0x09,
- 0x20, 0x93, 0xfe, 0x69,
+ 0x20, 0x93, 0x00, 0x6a,
0x02, 0x93, 0x26, 0x01,
- 0x01, 0x94, 0x00, 0x7a,
- 0x01, 0x94, 0x00, 0x7a,
- 0x01, 0x94, 0x00, 0x7a,
- 0x01, 0x94, 0x00, 0x7a,
- 0x01, 0x94, 0x00, 0x7a,
- 0x01, 0x94, 0x00, 0x7a,
- 0x10, 0x94, 0x0e, 0x6a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x10, 0x94, 0x10, 0x6a,
0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0x12, 0x6a,
+ 0x08, 0x93, 0x14, 0x6a,
0xdf, 0x93, 0x26, 0x09,
- 0x20, 0x93, 0x16, 0x6a,
+ 0x20, 0x93, 0x18, 0x6a,
0x03, 0x08, 0x52, 0x31,
0xff, 0x38, 0x50, 0x09,
0x12, 0x01, 0x02, 0x00,
0xff, 0x6a, 0xd4, 0x0c,
- 0x00, 0x65, 0x78, 0x5b,
+ 0x00, 0x65, 0x8e, 0x5b,
0x05, 0xb4, 0x10, 0x31,
0x02, 0x6a, 0x1a, 0x31,
0x03, 0x8c, 0x10, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0xb4, 0x6a, 0x1a, 0x5c,
+ 0xb4, 0x6a, 0x30, 0x5c,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
- 0x00, 0x65, 0x10, 0x5c,
- 0x3d, 0x6a, 0x60, 0x5b,
+ 0x00, 0x65, 0x26, 0x5c,
+ 0x3d, 0x6a, 0x76, 0x5b,
0xac, 0x6a, 0x26, 0x01,
- 0x04, 0x0b, 0x36, 0x6a,
- 0x01, 0x0b, 0x3c, 0x6a,
- 0x10, 0x0c, 0x38, 0x7a,
+ 0x04, 0x0b, 0x38, 0x6a,
+ 0x04, 0x0b, 0x3e, 0x6a,
+ 0x10, 0x0c, 0x3a, 0x7a,
0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0x3e, 0x6a,
+ 0x08, 0x93, 0x40, 0x6a,
0xdf, 0x93, 0x26, 0x09,
- 0x20, 0x93, 0x42, 0x6a,
+ 0x20, 0x93, 0x44, 0x6a,
0x12, 0x01, 0x02, 0x00,
0x00, 0x65, 0x22, 0x41,
- 0x00, 0x65, 0x78, 0x5b,
+ 0x00, 0x65, 0x8e, 0x5b,
0xff, 0x06, 0x44, 0x09,
0x00, 0x65, 0x22, 0x41,
0x10, 0x3d, 0x06, 0x00,
0xff, 0x34, 0xca, 0x08,
- 0x80, 0x65, 0x74, 0x62,
+ 0x80, 0x65, 0x76, 0x62,
0x0f, 0xa1, 0xca, 0x08,
0x07, 0xa1, 0xca, 0x08,
0x40, 0xa0, 0xc8, 0x08,
0x00, 0x65, 0xca, 0x00,
0x80, 0x65, 0xca, 0x00,
- 0x80, 0xa0, 0x64, 0x7a,
+ 0x80, 0xa0, 0x66, 0x7a,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x76, 0x42,
- 0x20, 0xa0, 0x7c, 0x7a,
+ 0x00, 0x65, 0x78, 0x42,
+ 0x20, 0xa0, 0x7e, 0x7a,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x08, 0x5c,
- 0xa0, 0x3d, 0x84, 0x62,
+ 0x00, 0x65, 0x1e, 0x5c,
+ 0xa0, 0x3d, 0x86, 0x62,
0x23, 0xa0, 0x0c, 0x08,
- 0x00, 0x65, 0x08, 0x5c,
- 0xa0, 0x3d, 0x84, 0x62,
- 0x00, 0xb9, 0x7c, 0x42,
- 0xff, 0x65, 0x7c, 0x62,
+ 0x00, 0x65, 0x1e, 0x5c,
+ 0xa0, 0x3d, 0x86, 0x62,
+ 0x00, 0xb9, 0x7e, 0x42,
+ 0xff, 0x65, 0x7e, 0x62,
0xa1, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
- 0x10, 0x51, 0x84, 0x72,
+ 0x10, 0x51, 0x86, 0x72,
0x40, 0x6a, 0x18, 0x00,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x08, 0x5c,
- 0xa0, 0x3d, 0x4e, 0x72,
+ 0x00, 0x65, 0x1e, 0x5c,
+ 0xa0, 0x3d, 0x50, 0x72,
0x40, 0x6a, 0x18, 0x00,
0xff, 0x34, 0xa6, 0x08,
- 0x80, 0x34, 0x8c, 0x62,
+ 0x80, 0x34, 0x8e, 0x62,
0x7f, 0xa0, 0x40, 0x09,
0x08, 0x6a, 0x68, 0x00,
0x00, 0x65, 0x22, 0x41,
- 0x64, 0x6a, 0x50, 0x5b,
- 0x80, 0x64, 0x00, 0x6b,
- 0x04, 0x64, 0xe2, 0x72,
- 0x02, 0x64, 0xe8, 0x72,
- 0x00, 0x6a, 0xaa, 0x72,
- 0x03, 0x64, 0xfc, 0x72,
- 0x01, 0x64, 0xde, 0x72,
- 0x07, 0x64, 0x3e, 0x73,
- 0x08, 0x64, 0xa6, 0x72,
+ 0x64, 0x6a, 0x66, 0x5b,
+ 0x80, 0x64, 0x04, 0x6b,
+ 0x04, 0x64, 0xe6, 0x72,
+ 0x02, 0x64, 0xec, 0x72,
+ 0x00, 0x6a, 0xae, 0x72,
+ 0x03, 0x64, 0x00, 0x73,
+ 0x01, 0x64, 0xe2, 0x72,
+ 0x07, 0x64, 0x42, 0x73,
+ 0x08, 0x64, 0xaa, 0x72,
+ 0x23, 0x64, 0x46, 0x73,
0x11, 0x6a, 0x22, 0x01,
- 0x07, 0x6a, 0x42, 0x5b,
+ 0x07, 0x6a, 0x58, 0x5b,
0xff, 0x06, 0xd4, 0x08,
0x00, 0x65, 0x22, 0x41,
- 0xff, 0xa8, 0xae, 0x6a,
- 0xff, 0xa2, 0xc6, 0x7a,
+ 0xff, 0xa8, 0xb2, 0x6a,
+ 0xff, 0xa2, 0xca, 0x7a,
0x01, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0x34, 0x5c,
- 0xff, 0xa2, 0xc6, 0x7a,
+ 0x00, 0xb9, 0x4a, 0x5c,
+ 0xff, 0xa2, 0xca, 0x7a,
0x71, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
- 0x40, 0x51, 0xc6, 0x62,
+ 0x40, 0x51, 0xca, 0x62,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0x34, 0x5c,
+ 0x00, 0xb9, 0x4a, 0x5c,
0xff, 0x3e, 0x74, 0x09,
0xff, 0x90, 0x7c, 0x08,
0x00, 0x65, 0x50, 0x58,
0x00, 0x65, 0x34, 0x41,
- 0x20, 0xa0, 0xce, 0x6a,
+ 0x20, 0xa0, 0xd2, 0x6a,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0x6a, 0xde, 0x5b,
- 0xff, 0x6a, 0xf4, 0x5b,
+ 0x00, 0x6a, 0xf4, 0x5b,
+ 0xff, 0x6a, 0x0a, 0x5c,
0xff, 0xf8, 0xc8, 0x08,
0xff, 0x4f, 0xc8, 0x08,
- 0x01, 0x6a, 0xde, 0x5b,
- 0x00, 0xb9, 0xf4, 0x5b,
+ 0x01, 0x6a, 0xf4, 0x5b,
+ 0x00, 0xb9, 0x0a, 0x5c,
0x01, 0x4f, 0x9e, 0x18,
0x02, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0xa2, 0x5c,
+ 0x00, 0x65, 0xb8, 0x5c,
0x00, 0x65, 0x34, 0x41,
0x41, 0x6a, 0x22, 0x01,
0x00, 0x65, 0x22, 0x41,
0x04, 0xa0, 0x40, 0x01,
- 0x00, 0x65, 0xba, 0x5c,
+ 0x00, 0x65, 0xd0, 0x5c,
0x00, 0x65, 0x34, 0x41,
- 0x10, 0x36, 0xa6, 0x7a,
+ 0x10, 0x36, 0xaa, 0x7a,
0x05, 0x38, 0x46, 0x31,
0x04, 0x14, 0x58, 0x31,
0x03, 0xa9, 0x60, 0x31,
0xa3, 0x6a, 0xcc, 0x00,
- 0x38, 0x6a, 0x1a, 0x5c,
+ 0x38, 0x6a, 0x30, 0x5c,
0xac, 0x6a, 0xcc, 0x00,
- 0x14, 0x6a, 0x1c, 0x5c,
- 0xa9, 0x6a, 0x1e, 0x5c,
- 0x00, 0x65, 0xa6, 0x42,
+ 0x14, 0x6a, 0x32, 0x5c,
+ 0xa9, 0x6a, 0x34, 0x5c,
+ 0x00, 0x65, 0xaa, 0x42,
0xef, 0x36, 0x6c, 0x08,
- 0x00, 0x65, 0xa6, 0x42,
+ 0x00, 0x65, 0xaa, 0x42,
0x0f, 0x64, 0xc8, 0x08,
0x07, 0x64, 0xc8, 0x08,
0x00, 0x37, 0x6e, 0x00,
0xff, 0x6a, 0xa4, 0x00,
- 0x00, 0x65, 0xae, 0x5b,
- 0xff, 0x51, 0x12, 0x73,
- 0x20, 0x36, 0x1c, 0x7b,
- 0x00, 0x90, 0x9c, 0x5b,
- 0x00, 0x65, 0x1e, 0x43,
+ 0x00, 0x65, 0xc4, 0x5b,
+ 0xff, 0x51, 0x16, 0x73,
+ 0x20, 0x36, 0x20, 0x7b,
+ 0x00, 0x90, 0xb2, 0x5b,
+ 0x00, 0x65, 0x22, 0x43,
0xff, 0x06, 0xd4, 0x08,
- 0x00, 0x65, 0x08, 0x5c,
- 0xe0, 0x3d, 0x38, 0x63,
- 0x20, 0x12, 0x38, 0x63,
- 0x51, 0x6a, 0x46, 0x5b,
- 0x00, 0x65, 0x96, 0x5b,
+ 0x00, 0x65, 0x1e, 0x5c,
+ 0xe0, 0x3d, 0x3c, 0x63,
+ 0x20, 0x12, 0x3c, 0x63,
+ 0x51, 0x6a, 0x5c, 0x5b,
+ 0x00, 0x65, 0xac, 0x5b,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0xa1, 0x30, 0x63,
- 0x04, 0xa0, 0x30, 0x7b,
+ 0x00, 0xa1, 0x34, 0x63,
+ 0x04, 0xa0, 0x34, 0x7b,
0xfb, 0xa0, 0x40, 0x09,
0x80, 0x36, 0x6c, 0x00,
- 0x80, 0xa0, 0xa6, 0x7a,
+ 0x80, 0xa0, 0xaa, 0x7a,
0x7f, 0xa0, 0x40, 0x09,
- 0xff, 0x6a, 0x42, 0x5b,
- 0x00, 0x65, 0xa6, 0x42,
- 0x04, 0xa0, 0x36, 0x7b,
- 0x00, 0x65, 0xba, 0x5c,
- 0x00, 0x65, 0x38, 0x43,
- 0x00, 0x65, 0xa2, 0x5c,
+ 0xff, 0x6a, 0x58, 0x5b,
+ 0x00, 0x65, 0xaa, 0x42,
+ 0x04, 0xa0, 0x3a, 0x7b,
+ 0x00, 0x65, 0xd0, 0x5c,
+ 0x00, 0x65, 0x3c, 0x43,
+ 0x00, 0x65, 0xb8, 0x5c,
0x31, 0x6a, 0x22, 0x01,
- 0x0c, 0x6a, 0x42, 0x5b,
- 0x00, 0x65, 0xa6, 0x42,
+ 0x0c, 0x6a, 0x58, 0x5b,
+ 0x00, 0x65, 0xaa, 0x42,
0x61, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0xa6, 0x42,
+ 0x00, 0x65, 0xaa, 0x42,
+ 0x51, 0x6a, 0x5c, 0x5b,
+ 0x20, 0x0d, 0xaa, 0x6a,
+ 0xff, 0xa8, 0x54, 0x6b,
+ 0xff, 0xa9, 0x54, 0x6b,
+ 0xff, 0xaa, 0x54, 0x6b,
+ 0xff, 0xab, 0x54, 0x6b,
+ 0x00, 0x65, 0xaa, 0x42,
+ 0x51, 0x6a, 0x22, 0x01,
+ 0x00, 0x65, 0xaa, 0x42,
0x10, 0x3d, 0x06, 0x00,
0xff, 0x65, 0x68, 0x0c,
0xff, 0x06, 0xd4, 0x08,
- 0x01, 0x0c, 0x48, 0x7b,
- 0x04, 0x0c, 0x48, 0x6b,
+ 0x01, 0x0c, 0x5e, 0x7b,
+ 0x04, 0x0c, 0x60, 0x6b,
0xe0, 0x03, 0x7a, 0x08,
- 0xe0, 0x3d, 0x5c, 0x63,
+ 0xe0, 0x3d, 0x72, 0x63,
0xff, 0x65, 0xcc, 0x08,
0xff, 0x12, 0xda, 0x0c,
0xff, 0x06, 0xd4, 0x0c,
0xff, 0x65, 0x0c, 0x08,
- 0x02, 0x0b, 0x58, 0x7b,
+ 0x02, 0x0b, 0x6e, 0x7b,
0xff, 0x6a, 0xd4, 0x0c,
0xd1, 0x6a, 0x22, 0x01,
0x00, 0x65, 0x22, 0x41,
0xff, 0x65, 0x26, 0x09,
- 0x01, 0x0b, 0x70, 0x6b,
- 0x10, 0x0c, 0x62, 0x7b,
- 0x04, 0x0b, 0x6a, 0x6b,
+ 0x01, 0x0b, 0x86, 0x6b,
+ 0x10, 0x0c, 0x78, 0x7b,
+ 0x04, 0x0b, 0x80, 0x6b,
0xff, 0x6a, 0xca, 0x08,
- 0x04, 0x93, 0x6e, 0x6b,
- 0x01, 0x94, 0x6c, 0x7b,
- 0x10, 0x94, 0x6e, 0x6b,
+ 0x04, 0x93, 0x84, 0x6b,
+ 0x01, 0x94, 0x82, 0x7b,
+ 0x10, 0x94, 0x84, 0x6b,
0xc7, 0x93, 0x26, 0x09,
0xff, 0x99, 0xd4, 0x08,
- 0x38, 0x93, 0x72, 0x6b,
+ 0x38, 0x93, 0x88, 0x6b,
0xff, 0x6a, 0xd4, 0x0c,
- 0x80, 0x36, 0x76, 0x6b,
+ 0x80, 0x36, 0x8c, 0x6b,
0x21, 0x6a, 0x22, 0x05,
0xff, 0x65, 0x20, 0x09,
- 0xff, 0x51, 0x84, 0x63,
+ 0xff, 0x51, 0x9a, 0x63,
0xff, 0x37, 0xc8, 0x08,
- 0xa1, 0x6a, 0x90, 0x43,
+ 0xa1, 0x6a, 0xa6, 0x43,
0xff, 0x51, 0xc8, 0x08,
- 0xb9, 0x6a, 0x90, 0x43,
+ 0xb9, 0x6a, 0xa6, 0x43,
0xff, 0x90, 0xa4, 0x08,
- 0xff, 0xba, 0x94, 0x73,
+ 0xff, 0xba, 0xaa, 0x73,
0xff, 0xba, 0x20, 0x09,
0xff, 0x65, 0xca, 0x18,
- 0x00, 0x6c, 0x88, 0x63,
+ 0x00, 0x6c, 0x9e, 0x63,
0xff, 0x90, 0xca, 0x0c,
0xff, 0x6a, 0xca, 0x04,
- 0x20, 0x36, 0xa8, 0x7b,
- 0x00, 0x90, 0x7c, 0x5b,
- 0xff, 0x65, 0xa8, 0x73,
- 0xff, 0x52, 0xa6, 0x73,
+ 0x20, 0x36, 0xbe, 0x7b,
+ 0x00, 0x90, 0x92, 0x5b,
+ 0xff, 0x65, 0xbe, 0x73,
+ 0xff, 0x52, 0xbc, 0x73,
0xff, 0xba, 0xcc, 0x08,
0xff, 0x52, 0x20, 0x09,
0xff, 0x66, 0x74, 0x09,
0xff, 0x65, 0x20, 0x0d,
0xff, 0xba, 0x7e, 0x0c,
- 0x00, 0x6a, 0xa8, 0x5c,
+ 0x00, 0x6a, 0xbe, 0x5c,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0x51, 0x34, 0x44,
- 0xff, 0x3f, 0x02, 0x74,
+ 0x00, 0x51, 0x4a, 0x44,
+ 0xff, 0x3f, 0x18, 0x74,
0xff, 0x6a, 0xa2, 0x00,
- 0x00, 0x3f, 0x7c, 0x5b,
- 0xff, 0x65, 0x02, 0x74,
+ 0x00, 0x3f, 0x92, 0x5b,
+ 0xff, 0x65, 0x18, 0x74,
0x20, 0x36, 0x6c, 0x00,
- 0x20, 0xa0, 0xbc, 0x6b,
+ 0x20, 0xa0, 0xd2, 0x6b,
0xff, 0xb9, 0xa2, 0x0c,
0xff, 0x6a, 0xa2, 0x04,
0xff, 0x65, 0xa4, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x28, 0x5c,
+ 0x45, 0x6a, 0x3e, 0x5c,
0x01, 0x6a, 0xd0, 0x01,
0x09, 0x6a, 0xd6, 0x01,
- 0x80, 0xeb, 0xc8, 0x7b,
+ 0x80, 0xeb, 0xde, 0x7b,
0x01, 0x6a, 0xd6, 0x01,
0x01, 0xe9, 0xa4, 0x34,
0x88, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x28, 0x5c,
+ 0x45, 0x6a, 0x3e, 0x5c,
0x01, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x0d, 0x6a, 0x26, 0x01,
- 0x00, 0x65, 0x9a, 0x5c,
+ 0x00, 0x65, 0xb0, 0x5c,
0xff, 0x99, 0xa4, 0x0c,
0xff, 0x65, 0xa4, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x28, 0x5c,
+ 0x45, 0x6a, 0x3e, 0x5c,
0x01, 0x6a, 0xd0, 0x01,
0x01, 0x6a, 0xdc, 0x05,
0x88, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x28, 0x5c,
+ 0x45, 0x6a, 0x3e, 0x5c,
0x01, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x01, 0x6a, 0x26, 0x05,
0x01, 0x65, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0xf8, 0x7b,
+ 0x80, 0xee, 0x0e, 0x7c,
0xff, 0x6a, 0xdc, 0x0d,
0xff, 0x65, 0x32, 0x09,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x9a, 0x44,
+ 0x00, 0x65, 0xb0, 0x44,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0x6a, 0xbe, 0x5b,
+ 0x00, 0x6a, 0xd4, 0x5b,
0xff, 0x52, 0xa2, 0x0c,
- 0x01, 0x0c, 0x08, 0x7c,
- 0x04, 0x0c, 0x08, 0x6c,
+ 0x01, 0x0c, 0x1e, 0x7c,
+ 0x04, 0x0c, 0x1e, 0x6c,
0xe0, 0x03, 0x06, 0x08,
0xe0, 0x03, 0x7a, 0x0c,
0xff, 0x8c, 0x10, 0x08,
@@ -542,29 +553,29 @@ static unsigned char seqprog[] = {
0x00, 0x6c, 0xda, 0x24,
0xff, 0x65, 0xc8, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x41, 0x6a, 0x24, 0x5c,
+ 0x41, 0x6a, 0x3a, 0x5c,
0xff, 0x90, 0xe2, 0x09,
0x20, 0x6a, 0xd0, 0x01,
- 0x04, 0x35, 0x46, 0x7c,
+ 0x04, 0x35, 0x5c, 0x7c,
0x1d, 0x6a, 0xdc, 0x01,
- 0xdc, 0xee, 0x42, 0x64,
- 0x00, 0x65, 0x52, 0x44,
+ 0xdc, 0xee, 0x58, 0x64,
+ 0x00, 0x65, 0x68, 0x44,
0x01, 0x6a, 0xdc, 0x01,
0x20, 0xa0, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0x4c, 0x7c,
+ 0x80, 0xee, 0x62, 0x7c,
0x19, 0x6a, 0xdc, 0x01,
- 0xd8, 0xee, 0x50, 0x64,
+ 0xd8, 0xee, 0x66, 0x64,
0xff, 0x6a, 0xdc, 0x09,
- 0x18, 0xee, 0x54, 0x6c,
+ 0x18, 0xee, 0x6a, 0x6c,
0xff, 0x6a, 0xd4, 0x0c,
0x88, 0x6a, 0xcc, 0x00,
- 0x41, 0x6a, 0x24, 0x5c,
+ 0x41, 0x6a, 0x3a, 0x5c,
0x20, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x35, 0x7e, 0x6c,
+ 0x04, 0x35, 0x94, 0x6c,
0xa0, 0x6a, 0xca, 0x00,
0x20, 0x65, 0xc8, 0x18,
0xff, 0x6c, 0x32, 0x09,
@@ -575,14 +586,14 @@ static unsigned char seqprog[] = {
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
- 0x00, 0x65, 0x6a, 0x64,
+ 0x00, 0x65, 0x80, 0x64,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x9a, 0x5c,
- 0x04, 0x35, 0x76, 0x7b,
- 0xa0, 0x6a, 0x8a, 0x5c,
- 0x00, 0x65, 0x8c, 0x5c,
- 0x00, 0x65, 0x8c, 0x5c,
- 0x00, 0x65, 0x8c, 0x44,
+ 0x00, 0x65, 0xb0, 0x5c,
+ 0x04, 0x35, 0x8c, 0x7b,
+ 0xa0, 0x6a, 0xa0, 0x5c,
+ 0x00, 0x65, 0xa2, 0x5c,
+ 0x00, 0x65, 0xa2, 0x5c,
+ 0x00, 0x65, 0xa2, 0x44,
0xff, 0x65, 0xcc, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
@@ -591,19 +602,19 @@ static unsigned char seqprog[] = {
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x0c,
- 0x08, 0x94, 0x9a, 0x7c,
+ 0x08, 0x94, 0xb0, 0x7c,
0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0x9e, 0x6c,
+ 0x08, 0x93, 0xb4, 0x6c,
0xff, 0x6a, 0xd4, 0x0c,
0xff, 0x40, 0x74, 0x09,
0xff, 0x90, 0x80, 0x08,
0xff, 0x6a, 0x72, 0x05,
- 0xff, 0x40, 0xb6, 0x64,
- 0xff, 0x3f, 0xae, 0x64,
+ 0xff, 0x40, 0xcc, 0x64,
+ 0xff, 0x3f, 0xc4, 0x64,
0xff, 0x6a, 0xca, 0x04,
0xff, 0x3f, 0x20, 0x09,
0x01, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0x34, 0x5c,
+ 0x00, 0xb9, 0x4a, 0x5c,
0xff, 0xba, 0x7e, 0x0c,
0xff, 0x40, 0x20, 0x09,
0xff, 0xba, 0x80, 0x0c,
@@ -761,49 +772,52 @@ struct sequencer_patch {
{ aic7xxx_patch2_func, 192, 2, 3 },
{ aic7xxx_patch8_func, 192, 1, 1 },
{ aic7xxx_patch0_func, 194, 3, 1 },
- { aic7xxx_patch10_func, 197, 2, 1 },
- { aic7xxx_patch8_func, 199, 7, 2 },
- { aic7xxx_patch0_func, 206, 1, 1 },
- { aic7xxx_patch2_func, 211, 14, 3 },
- { aic7xxx_patch10_func, 224, 1, 1 },
- { aic7xxx_patch0_func, 225, 9, 1 },
- { aic7xxx_patch8_func, 239, 2, 1 },
- { aic7xxx_patch8_func, 241, 1, 1 },
- { aic7xxx_patch10_func, 242, 6, 3 },
- { aic7xxx_patch2_func, 242, 2, 2 },
- { aic7xxx_patch0_func, 244, 4, 1 },
- { aic7xxx_patch8_func, 249, 1, 1 },
- { aic7xxx_patch8_func, 253, 19, 1 },
- { aic7xxx_patch2_func, 273, 3, 3 },
- { aic7xxx_patch10_func, 275, 1, 1 },
- { aic7xxx_patch0_func, 276, 5, 1 },
- { aic7xxx_patch10_func, 281, 1, 2 },
- { aic7xxx_patch0_func, 282, 9, 1 },
- { aic7xxx_patch11_func, 298, 1, 2 },
- { aic7xxx_patch0_func, 299, 1, 1 },
- { aic7xxx_patch5_func, 359, 1, 2 },
- { aic7xxx_patch0_func, 360, 1, 1 },
- { aic7xxx_patch3_func, 363, 1, 1 },
- { aic7xxx_patch2_func, 373, 3, 2 },
- { aic7xxx_patch0_func, 376, 5, 1 },
- { aic7xxx_patch11_func, 384, 1, 2 },
- { aic7xxx_patch0_func, 385, 1, 1 },
- { aic7xxx_patch6_func, 390, 1, 1 },
- { aic7xxx_patch1_func, 427, 3, 1 },
- { aic7xxx_patch10_func, 432, 11, 1 },
- { aic7xxx_patch2_func, 480, 7, 2 },
- { aic7xxx_patch0_func, 487, 8, 1 },
- { aic7xxx_patch2_func, 496, 4, 2 },
- { aic7xxx_patch0_func, 500, 6, 1 },
- { aic7xxx_patch2_func, 506, 4, 2 },
- { aic7xxx_patch0_func, 510, 3, 1 },
- { aic7xxx_patch12_func, 520, 10, 1 },
- { aic7xxx_patch2_func, 539, 17, 4 },
- { aic7xxx_patch13_func, 547, 4, 2 },
- { aic7xxx_patch0_func, 551, 2, 1 },
- { aic7xxx_patch0_func, 556, 33, 1 },
- { aic7xxx_patch12_func, 589, 4, 1 },
- { aic7xxx_patch6_func, 593, 2, 1 },
- { aic7xxx_patch6_func, 596, 9, 1 },
+ { aic7xxx_patch10_func, 198, 1, 2 },
+ { aic7xxx_patch0_func, 199, 1, 1 },
+ { aic7xxx_patch8_func, 200, 7, 2 },
+ { aic7xxx_patch0_func, 207, 1, 1 },
+ { aic7xxx_patch2_func, 212, 14, 3 },
+ { aic7xxx_patch10_func, 225, 1, 1 },
+ { aic7xxx_patch0_func, 226, 9, 1 },
+ { aic7xxx_patch8_func, 240, 2, 1 },
+ { aic7xxx_patch8_func, 242, 1, 1 },
+ { aic7xxx_patch10_func, 243, 6, 3 },
+ { aic7xxx_patch2_func, 243, 2, 2 },
+ { aic7xxx_patch0_func, 245, 4, 1 },
+ { aic7xxx_patch8_func, 250, 1, 1 },
+ { aic7xxx_patch8_func, 254, 19, 1 },
+ { aic7xxx_patch2_func, 274, 3, 3 },
+ { aic7xxx_patch10_func, 276, 1, 1 },
+ { aic7xxx_patch0_func, 277, 5, 1 },
+ { aic7xxx_patch10_func, 282, 1, 2 },
+ { aic7xxx_patch0_func, 283, 9, 1 },
+ { aic7xxx_patch11_func, 299, 1, 2 },
+ { aic7xxx_patch0_func, 300, 1, 1 },
+ { aic7xxx_patch5_func, 361, 1, 2 },
+ { aic7xxx_patch0_func, 362, 1, 1 },
+ { aic7xxx_patch3_func, 365, 1, 1 },
+ { aic7xxx_patch2_func, 375, 3, 2 },
+ { aic7xxx_patch0_func, 378, 5, 1 },
+ { aic7xxx_patch11_func, 386, 1, 2 },
+ { aic7xxx_patch0_func, 387, 1, 1 },
+ { aic7xxx_patch6_func, 392, 1, 1 },
+ { aic7xxx_patch8_func, 420, 1, 2 },
+ { aic7xxx_patch0_func, 421, 5, 1 },
+ { aic7xxx_patch1_func, 438, 3, 1 },
+ { aic7xxx_patch10_func, 443, 11, 1 },
+ { aic7xxx_patch2_func, 491, 7, 2 },
+ { aic7xxx_patch0_func, 498, 8, 1 },
+ { aic7xxx_patch2_func, 507, 4, 2 },
+ { aic7xxx_patch0_func, 511, 6, 1 },
+ { aic7xxx_patch2_func, 517, 4, 2 },
+ { aic7xxx_patch0_func, 521, 3, 1 },
+ { aic7xxx_patch12_func, 531, 10, 1 },
+ { aic7xxx_patch2_func, 550, 17, 4 },
+ { aic7xxx_patch13_func, 558, 4, 2 },
+ { aic7xxx_patch0_func, 562, 2, 1 },
+ { aic7xxx_patch0_func, 567, 33, 1 },
+ { aic7xxx_patch12_func, 600, 4, 1 },
+ { aic7xxx_patch6_func, 604, 2, 1 },
+ { aic7xxx_patch6_func, 607, 9, 1 },
};
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 7e9fb2ab3..849ce76c9 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -410,11 +410,13 @@ static const char *snstext[] = {
#endif
/* Print sense information */
-void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
+static
+void print_sense_internal(const char * devclass,
+ const unsigned char * sense_buffer,
+ kdev_t dev)
{
int i, s;
int sense_class, valid, code;
- unsigned char * sense_buffer = SCpnt->sense_buffer;
const char * error = NULL;
sense_class = (sense_buffer[0] >> 4) & 0x07;
@@ -423,8 +425,8 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
if (sense_class == 7) { /* extended sense data */
s = sense_buffer[7] + 8;
- if(s > sizeof(SCpnt->sense_buffer))
- s = sizeof(SCpnt->sense_buffer);
+ if(s > SCSI_SENSE_BUFFERSIZE)
+ s = SCSI_SENSE_BUFFERSIZE;
if (!valid)
printk("[valid=0] ");
@@ -455,10 +457,10 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
#if (CONSTANTS & CONST_SENSE)
printk( "%s%s: sense key %s\n", devclass,
- kdevname(SCpnt->request.rq_dev), snstext[sense_buffer[2] & 0x0f]);
+ kdevname(dev), snstext[sense_buffer[2] & 0x0f]);
#else
printk("%s%s: sns = %2x %2x\n", devclass,
- kdevname(SCpnt->request.rq_dev), sense_buffer[0], sense_buffer[2]);
+ kdevname(dev), sense_buffer[0], sense_buffer[2]);
#endif
/* Check to see if additional sense information is available */
@@ -495,11 +497,11 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
#if (CONSTANTS & CONST_SENSE)
if (sense_buffer[0] < 15)
printk("%s%s: old sense key %s\n", devclass,
- kdevname(SCpnt->request.rq_dev), snstext[sense_buffer[0] & 0x0f]);
+ kdevname(dev), snstext[sense_buffer[0] & 0x0f]);
else
#endif
printk("%s%s: sns = %2x %2x\n", devclass,
- kdevname(SCpnt->request.rq_dev), sense_buffer[0], sense_buffer[2]);
+ kdevname(dev), sense_buffer[0], sense_buffer[2]);
printk("Non-extended sense class %d code 0x%0x ", sense_class, code);
s = 4;
@@ -515,6 +517,18 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
return;
}
+void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
+{
+ print_sense_internal(devclass, SCpnt->sense_buffer,
+ SCpnt->request.rq_dev);
+}
+
+void print_req_sense(const char * devclass, Scsi_Request * SRpnt)
+{
+ print_sense_internal(devclass, SRpnt->sr_sense_buffer,
+ SRpnt->sr_request.rq_dev);
+}
+
#if (CONSTANTS & CONST_MSG)
static const char *one_byte_msgs[] = {
/* 0x00 */ "Command Complete", NULL, "Save Pointers",
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index b6a058c03..d87bf6d70 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -910,7 +910,7 @@ static inline int port_detect \
if (info.sign != EATA_SIGNATURE) return FALSE;
if (DEV2H(info.data_len) < EATA_2_0A_SIZE) {
- printk("%s: config structure size (%ld bytes) too short, detaching.\n",
+ printk("%s: config structure size (%d bytes) too short, detaching.\n",
name, DEV2H(info.data_len));
return FALSE;
}
diff --git a/drivers/scsi/eata_dma_proc.c b/drivers/scsi/eata_dma_proc.c
index dd6034561..725a70a4a 100644
--- a/drivers/scsi/eata_dma_proc.c
+++ b/drivers/scsi/eata_dma_proc.c
@@ -167,6 +167,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
cmnd[9] = 0;
scmd->cmd_len = 10;
+ scmd->sc_data_direction = DATA_READ;
/*
* Do the command and wait for it to finish.
@@ -291,6 +292,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
cmnd[9] = 0;
scmd->cmd_len = 10;
+ scmd->sc_data_direction = SCSI_DATA_READ;
/*
* Do the command and wait for it to finish.
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 61ce25c36..fccfb59c8 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.90 2000/01/28 13:42:56 jj Exp $
+/* $Id: esp.c,v 1.92 2000/02/18 13:49:58 davem Exp $
* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
*
* Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
@@ -1412,14 +1412,20 @@ static void esp_get_dmabufs(struct esp *esp, Scsi_Cmnd *sp)
sp->SCp.this_residual = sp->request_bufflen;
sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
sp->SCp.buffers_residual = 0;
- sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer,
- sp->SCp.this_residual);
- sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in);
+ if (sp->request_bufflen) {
+ sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer,
+ sp->SCp.this_residual,
+ scsi_to_sbus_dma_dir(sp->sc_data_direction));
+ sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in);
+ } else {
+ sp->SCp.ptr = NULL;
+ }
} else {
sp->SCp.buffer = (struct scatterlist *) sp->buffer;
sp->SCp.buffers_residual = sbus_map_sg(esp->sdev,
sp->SCp.buffer,
- sp->use_sg);
+ sp->use_sg,
+ scsi_to_sbus_dma_dir(sp->sc_data_direction));
sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer);
sp->SCp.ptr = (char *) ((unsigned long)sg_dma_address(sp->SCp.buffer));
}
@@ -1427,12 +1433,14 @@ static void esp_get_dmabufs(struct esp *esp, Scsi_Cmnd *sp)
static void esp_release_dmabufs(struct esp *esp, Scsi_Cmnd *sp)
{
- if (sp->use_sg == 0) {
+ if (sp->use_sg) {
+ sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg,
+ scsi_to_sbus_dma_dir(sp->sc_data_direction));
+ } else if (sp->request_bufflen) {
sbus_unmap_single(esp->sdev,
sp->SCp.have_data_in,
- sp->request_bufflen);
- } else {
- sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg);
+ sp->request_bufflen,
+ scsi_to_sbus_dma_dir(sp->sc_data_direction));
}
}
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 979f1295c..59d9f2415 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -270,10 +270,6 @@
**************************************************************************/
-#ifdef PCMCIA
-#define MODULE
-#endif
-
#include <linux/module.h>
#ifdef PCMCIA
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 500c19b09..321b783a5 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -681,6 +681,7 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
* MAX_SCSI_HOSTS here.
*/
+Scsi_Host_Name * scsi_host_no_list = NULL;
struct Scsi_Host * scsi_hostlist = NULL;
struct Scsi_Device_Template * scsi_devicelist = NULL;
@@ -690,7 +691,8 @@ int next_scsi_host = 0;
void
scsi_unregister(struct Scsi_Host * sh){
struct Scsi_Host * shpnt;
-
+ Scsi_Host_Name *shn;
+
if(scsi_hostlist == sh)
scsi_hostlist = sh->next;
else {
@@ -698,6 +700,16 @@ scsi_unregister(struct Scsi_Host * sh){
while(shpnt->next != sh) shpnt = shpnt->next;
shpnt->next = shpnt->next->next;
}
+
+ /*
+ * We have to unregister the host from the scsi_host_no_list as well.
+ * Decide by the host_no not by the name because most host drivers are
+ * able to handle more than one adapters from the same kind (or family).
+ */
+ for ( shn=scsi_host_no_list; shn && (sh->host_no != shn->host_no);
+ shn=shn->next);
+ if (shn) shn->host_registered = 0;
+ /* else {} : This should not happen, we should panic here... */
/* If we are removing the last host registered, it is safe to reuse
* its host number (this avoids "holes" at boot time) (DB)
@@ -724,16 +736,50 @@ scsi_unregister(struct Scsi_Host * sh){
struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
struct Scsi_Host * retval, *shpnt;
+ Scsi_Host_Name *shn, *shn2;
+ int new = 1;
retval = (struct Scsi_Host *)kmalloc(sizeof(struct Scsi_Host) + j,
(tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
memset(retval, 0, sizeof(struct Scsi_Host) + j);
+
+ /* trying to find a reserved entry (host_no) */
+ for (shn = scsi_host_no_list;shn;shn = shn->next)
+ if (!(shn->host_registered) && shn->loaded_as_module && tpnt->proc_dir &&
+ tpnt->proc_dir->name && !strncmp(tpnt->proc_dir->name, shn->name, strlen(tpnt->proc_dir->name))) {
+ new = 0;
+ retval->host_no = shn->host_no;
+ shn->host_registered = 1;
+ shn->loaded_as_module = scsi_loadable_module_flag;
+ break;
+ }
atomic_set(&retval->host_active,0);
retval->host_busy = 0;
retval->host_failed = 0;
if(j > 0xffff) panic("Too many extra bytes requested\n");
retval->extra_bytes = j;
retval->loaded_as_module = scsi_loadable_module_flag;
- retval->host_no = max_scsi_hosts++; /* never reuse host_no (DB) */
+ if (new) {
+ int len = 0;
+ shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC);
+ if (tpnt->proc_dir)
+ len = strlen(tpnt->proc_dir->name);
+ shn->name = kmalloc(len+1, GFP_ATOMIC);
+ if (tpnt->proc_dir)
+ strncpy(shn->name, tpnt->proc_dir->name, len);
+ shn->name[len] = 0;
+ shn->host_no = max_scsi_hosts++;
+ shn->host_registered = 1;
+ shn->loaded_as_module = scsi_loadable_module_flag;
+ shn->next = NULL;
+ if (scsi_host_no_list) {
+ for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
+ ;
+ shn2->next = shn;
+ }
+ else
+ scsi_host_no_list = shn;
+ retval->host_no = shn->host_no;
+ }
next_scsi_host++;
retval->host_queue = NULL;
init_waitqueue_head(&retval->host_wait);
@@ -747,6 +793,14 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
retval->max_id = 8;
retval->max_lun = 8;
+ /*
+ * All drivers right now should be able to handle 12 byte commands.
+ * Every so often there are requests for 16 byte commands, but individual
+ * low-level drivers need to certify that they actually do something
+ * sensible with such commands.
+ */
+ retval->max_cmd_len = 12;
+
retval->unique_id = 0;
retval->io_port = 0;
retval->hostt = tpnt;
@@ -757,6 +811,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
retval->host_blocked = FALSE;
+ retval->host_self_blocked = FALSE;
#ifdef DEBUG
printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
index 191e4469e..f1b82a5a1 100644
--- a/drivers/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -362,6 +362,17 @@ struct Scsi_Host
* initialized, as required.
*/
+ /*
+ * The maximum length of SCSI commands that this host can accept.
+ * Probably 12 for most host adapters, but could be 16 for others.
+ * For drivers that don't set this field, a value of 12 is
+ * assumed. I am leaving this as a number rather than a bit
+ * because you never know what subsequent SCSI standards might do
+ * (i.e. could there be a 20 byte or a 24-byte command a few years
+ * down the road?).
+ */
+ unsigned char max_cmd_len;
+
int this_id;
int can_queue;
short cmd_per_lun;
@@ -379,6 +390,12 @@ struct Scsi_Host
* Host has rejected a command because it was busy.
*/
unsigned host_blocked:1;
+
+ /*
+ * Host has requested that no further requests come through for the
+ * time being.
+ */
+ unsigned host_self_blocked:1;
/*
* Host uses correct SCSI ordering not PC ordering. The bit is
@@ -413,6 +430,20 @@ struct Scsi_Host
extern void scsi_free_host_dev(Scsi_Device * SDpnt);
extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt);
+extern void scsi_unblock_requests(struct Scsi_Host * SHpnt);
+extern void scsi_block_requests(struct Scsi_Host * SHpnt);
+extern void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel);
+
+typedef struct SHN
+ {
+ struct SHN * next;
+ char * name;
+ unsigned short host_no;
+ unsigned short host_registered;
+ unsigned loaded_as_module;
+ } Scsi_Host_Name;
+
+extern Scsi_Host_Name * scsi_host_no_list;
extern struct Scsi_Host * scsi_hostlist;
extern struct Scsi_Device_Template * scsi_devicelist;
@@ -504,6 +535,15 @@ extern void scsi_unregister_module(int, void *);
* tackle the character devices first, as there aren't any locking implications
* in the block device layer. The block devices will require more work.
*/
+#ifndef CONFIG_SD_EXTRA_DEVS
+#define CONFIG_SD_EXTRA_DEVS 2
+#endif
+#ifndef CONFIG_ST_EXTRA_DEVS
+#define CONFIG_ST_EXTRA_DEVS 2
+#endif
+#ifndef CONFIG_SR_EXTRA_DEVS
+#define CONFIG_SR_EXTRA_DEVS 2
+#endif
#define SD_EXTRA_DEVS CONFIG_SD_EXTRA_DEVS
#define ST_EXTRA_DEVS CONFIG_ST_EXTRA_DEVS
#define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index 036ffdf2c..99cfa7e8c 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -417,7 +417,9 @@ int mac_esp_detect(Scsi_Host_Template * tpnt)
esp->irq = IRQ_MAC_SCSI;
request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp);
+#if 0 /* conflicts with IOP ADB */
request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp);
+#endif
if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) {
esp->cfreq = 16500000;
@@ -429,8 +431,9 @@ int mac_esp_detect(Scsi_Host_Template * tpnt)
} else { /* chipnum == 1 */
esp->irq = IRQ_MAC_SCSIDRQ;
-
+#if 0 /* conflicts with IOP ADB */
request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp);
+#endif
esp->cfreq = 25000000;
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 9e5bdf2b2..11a58c478 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -78,7 +78,6 @@
#define NDEBUG (NDEBUG_ABORT)
#endif
-#define USE_WRAPPER
#define RESET_BOOT
#define DRIVER_SETUP
@@ -90,30 +89,9 @@
#undef DRIVER_SETUP
#endif
-/*
- * Need to define this to make SCSI work on RBV machines; leave undefined
- * to enable interrupts a bit more on other machines
- * Changes method of SCSI interrupt disable from software mask to VIA IER!
- * (don't know if that's essential)
- *
- * 990502 (jmt) - not needed (and won't work) on new irq architecture
- */
-/* #define RBV_HACK */
-
-#ifdef RBV_HACK
-#define ENABLE_IRQ() mac_turnon_irq( IRQ_MAC_SCSI );
-#define DISABLE_IRQ() mac_turnoff_irq( IRQ_MAC_SCSI );
-#else
#define ENABLE_IRQ() mac_enable_irq( IRQ_MAC_SCSI );
#define DISABLE_IRQ() mac_disable_irq( IRQ_MAC_SCSI );
-#endif
-
-#define mac_turnon_irq(x) mac_enable_irq(x)
-#define mac_turnoff_irq(x) mac_disable_irq(x)
-extern void via_scsi_clear(void);
-
-static void scsi_mac_intr(int irq, void *dummy, struct pt_regs *fp);
#ifdef RESET_BOOT
static void mac_scsi_reset_boot(struct Scsi_Host *instance);
#endif
@@ -253,7 +231,7 @@ int macscsi_detect(Scsi_Host_Template * tpnt)
if (macintosh_config->scsi_type != MAC_SCSI_OLD)
return( 0 );
- tpnt->proc_name = "Mac 5380 SCSI";
+ tpnt->proc_name = "mac5380";
/* setup variables */
tpnt->can_queue =
@@ -306,11 +284,7 @@ int macscsi_detect(Scsi_Host_Template * tpnt)
((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
if (instance->irq != IRQ_NONE)
-#ifdef USE_WRAPPER
- if (request_irq(instance->irq, scsi_mac_intr, IRQ_FLG_SLOW, "MacSCSI-5380", NULL)) {
-#else
- if (request_irq(instance->irq, macscsi_intr, IRQ_FLG_SLOW, "MacSCSI-5380", NULL)) {
-#endif
+ if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, "ncr5380", NCR5380_intr)) {
printk("scsi%d: IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = IRQ_NONE;
@@ -337,7 +311,7 @@ int macscsi_detect(Scsi_Host_Template * tpnt)
int macscsi_release (struct Scsi_Host *shpnt)
{
if (shpnt->irq != IRQ_NONE)
- free_irq (shpnt->irq, NULL);
+ free_irq (shpnt->irq, NCR5380_intr);
return 0;
}
@@ -362,7 +336,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
printk( "Macintosh SCSI: resetting the SCSI bus..." );
/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
- mac_turnoff_irq( IRQ_MAC_SCSI );
+ mac_disable_irq(IRQ_MAC_SCSI);
/* get in phase */
NCR5380_write( TARGET_COMMAND_REG,
@@ -380,7 +354,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
barrier();
/* switch on SCSI IRQ again */
- mac_turnon_irq( IRQ_MAC_SCSI );
+ mac_enable_irq(IRQ_MAC_SCSI);
printk( " done\n" );
}
@@ -399,49 +373,6 @@ void restore_irq(struct pt_regs *regs)
restore_flags(flags);
}
-#ifdef USE_WRAPPER
-/*
- * SCSI interrupt wrapper - just to make sure it's the proper irq, and
- * that we leave the handler in a clean state
- */
-
-static void scsi_mac_intr (int irq, void *dev_id, struct pt_regs *fp)
-{
-#ifndef RBV_HACK
- unsigned long flags;
-#endif
-
-#ifdef RBV_HACK
- mac_turnoff_irq( IRQ_MAC_SCSI );
-#else
- mac_disable_irq( IRQ_MAC_SCSI );
-#endif
-
- if ( irq == IRQ_MAC_SCSI ) {
-#ifndef RBV_HACK
- save_flags(flags);
- restore_irq(fp);
-#endif
- NCR5380_intr (irq, dev_id, fp);
-#ifndef RBV_HACK
- restore_flags(flags);
-#endif
- }
-
- /* To be sure the int is not masked */
-#ifdef RBV_HACK
- mac_turnon_irq( IRQ_MAC_SCSI );
-#else
- mac_enable_irq( IRQ_MAC_SCSI );
-#endif
-
-#if 1 /* ??? 0 worked */
- /* Clear the IRQ */
- via_scsi_clear();
-#endif
-}
-#endif
-
/*
* pseudo-DMA transfer functions, copied and modified from Russel King's
* ARM 5380 driver (cumana_1)
@@ -720,11 +651,7 @@ void scsi_mac_polled (void)
printk("SCSI poll\n");
save_flags(flags);
cli();
-#ifdef USE_WRAPPER
- scsi_mac_intr(IRQ_MAC_SCSI, instance, NULL);
-#else
- macscsi_intr(IRQ_MAC_SCSI, instance, NULL);
-#endif
+ NCR5380_intr(IRQ_MAC_SCSI, instance, NULL);
restore_flags(flags);
}
#if 0
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 0ede63b87..adafbe43e 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -253,7 +253,7 @@ mesh_detect(Scsi_Host_Template *tp)
continue;
}
mesh_host->unique_id = nmeshes;
-#if !defined(MODULE) && (defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC))
+#if !defined(MODULE)
note_scsi_host(mesh, mesh_host);
#endif
@@ -305,9 +305,7 @@ mesh_detect(Scsi_Host_Template *tp)
if (mesh_sync_period < minper)
mesh_sync_period = minper;
-#if defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)
feature_set(mesh, FEATURE_MESH_enable);
-#endif
mdelay(200);
mesh_init(ms);
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
index 71121b726..fce0871f1 100644
--- a/drivers/scsi/mvme16x.c
+++ b/drivers/scsi/mvme16x.c
@@ -40,7 +40,7 @@ int mvme16x_scsi_detect(Scsi_Host_Template *tpnt)
if (called)
return 0;
- tpnt->proc_name = "MVME16x"
+ tpnt->proc_name = "MVME16x";
options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c
index 83efa5df6..e07417b7e 100644
--- a/drivers/scsi/pci2000.c
+++ b/drivers/scsi/pci2000.c
@@ -53,7 +53,15 @@
#include "pci2000.h"
#include "psi_roy.h"
-#include <linux/spinlock.h>
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93)
+#include <linux/bios32.h>
+#endif
+
+struct proc_dir_entry Proc_Scsi_Pci2000 =
+ { PROC_SCSI_PCI2000, 7, "pci2000", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
//#define DEBUG 1
@@ -120,6 +128,28 @@ static int WaitReady (PADAPTER2000 padapter)
return TRUE;
}
/****************************************************************
+ * Name: WaitReadyLong :LOCAL
+ *
+ * Description: Wait for controller ready.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ *
+ * Returns: TRUE on not ready.
+ *
+ ****************************************************************/
+static int WaitReadyLong (PADAPTER2000 padapter)
+ {
+ ULONG z;
+
+ for ( z = 0; z < (5000 * 4); z++ )
+ {
+ if ( !inb_p (padapter->cmd) )
+ return FALSE;
+ udelay (250);
+ };
+ return TRUE;
+ }
+/****************************************************************
* Name: OpDone :LOCAL
*
* Description: Clean up operation and issue done to caller.
@@ -204,7 +234,7 @@ static int PsiRaidCmd (PADAPTER2000 padapter, char cmd)
if ( WaitReady (padapter) ) // test for command register ready
return DID_TIME_OUT;
outb_p (cmd, padapter->cmd); // issue command
- if ( WaitReady (padapter) ) // wait for adapter ready
+ if ( WaitReadyLong (padapter) ) // wait for adapter ready
return DID_TIME_OUT;
return DID_OK;
}
@@ -232,13 +262,23 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
int pun;
int bus;
int z;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ int flags;
+#else /* version >= v2.1.95 */
unsigned long flags;
+#endif /* version >= v2.1.95 */
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /* Disable interrupts, if they aren't already disabled. */
+ save_flags (flags);
+ cli ();
+#else /* version >= v2.1.95 */
/*
* Disable interrupts, if they aren't already disabled and acquire
* the I/O spinlock.
*/
spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
DEB(printk ("\npci2000 recieved interrupt "));
for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process
@@ -327,12 +367,20 @@ irqProceed:;
OpDone (SCpnt, DID_OK << 16);
irq_return:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /*
+ * Restore the original flags which will enable interrupts
+ * if and only if they were enabled on entry.
+ */
+ restore_flags (flags);
+#else /* version >= v2.1.95 */
/*
* Release the I/O spinlock and restore the original flags
* which will enable interrupts if and only if they were
* enabled on entry.
*/
spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
}
/****************************************************************
* Name: Pci2000_QueueCommand
@@ -589,21 +637,37 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
PADAPTER2000 padapter;
int z, zz;
int setirq;
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
struct pci_dev *pdev = NULL;
+#else
+ UCHAR pci_bus, pci_device_fn;
+#endif
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
if ( !pci_present () )
+#else
+ if ( !pcibios_present () )
+#endif
{
printk ("pci2000: PCI BIOS not present\n");
return 0;
}
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_ROY_1, pdev)) != NULL )
+#else
+ while ( !pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, found, &pci_bus, &pci_device_fn) )
+#endif
{
pshost = scsi_register (tpnt, sizeof(ADAPTER2000));
padapter = HOSTDATA(pshost);
- padapter->basePort = pdev->resource[1].start;
-
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ padapter->basePort = pdev->base_address[1] & 0xFFFE;
+#else
+ pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort);
+ padapter->basePort &= 0xFFFE;
+#endif
DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address
padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes
padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4;
@@ -620,7 +684,11 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
if ( WaitReady (padapter) )
goto unregister;
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
pshost->irq = pdev->irq;
+#else
+ pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
+#endif
setirq = 1;
padapter->irqOwned = 0;
for ( z = 0; z < installed; z++ ) // scan for shared interrupts
@@ -714,7 +782,11 @@ int Pci2000_Release (struct Scsi_Host *pshost)
PADAPTER2000 padapter = HOSTDATA (pshost);
if ( padapter->irqOwned )
+#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
+ free_irq (pshost->irq);
+#else /* version >= v1.3.70 */
free_irq (pshost->irq, padapter);
+#endif /* version >= v1.3.70 */
release_region (pshost->io_port, pshost->n_io_port);
scsi_unregister(pshost);
return 0;
@@ -760,4 +832,3 @@ Scsi_Host_Template driver_template = PCI2000;
#include "scsi_module.c"
#endif
-
diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
index 9b80a489b..a3daa5f76 100644
--- a/drivers/scsi/pci2000.h
+++ b/drivers/scsi/pci2000.h
@@ -200,10 +200,13 @@ int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]);
#define NULL 0
#endif
+extern struct proc_dir_entry Proc_Scsi_Pci2000;
+
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75)
#define PCI2000 { \
next: NULL, \
module: NULL, \
- proc_name: "pci2000", \
+ proc_dir: &Proc_Scsi_Pci2000, \
proc_info: NULL, /* let's not bloat the kernel */ \
name: "PCI-2000 SCSI Intelligent Disk Controller",\
detect: Pci2000_Detect, \
@@ -229,4 +232,27 @@ int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]);
use_clustering: DISABLE_CLUSTERING, \
use_new_eh_code: 0 \
}
+#else
+#define PCI2000 { NULL, NULL, \
+ &Proc_Scsi_Pci2000,/* proc_dir_entry */ \
+ NULL, \
+ "PCI-2000 SCSI Intelligent Disk Controller",\
+ Pci2000_Detect, \
+ Pci2000_Release, \
+ NULL, \
+ Pci2000_Command, \
+ Pci2000_QueueCommand, \
+ Pci2000_Abort, \
+ Pci2000_Reset, \
+ NULL, \
+ Pci2000_BiosParam, \
+ 16, \
+ -1, \
+ 16, \
+ 1, \
+ 0, \
+ 0, \
+ DISABLE_CLUSTERING }
+#endif
+
#endif
diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c
index e50ba45dc..80f58cb8e 100644
--- a/drivers/scsi/pci2220i.c
+++ b/drivers/scsi/pci2220i.c
@@ -24,8 +24,15 @@
* Revisions 1.11 Mar-26-1999
* - Fixed spinlock and PCI configuration.
*
+ * Revision 2.00 December-1-1999
+ * - Added code for the PCI-2240I controller
+ * - Added code for ATAPI devices.
+ * - Double buffer for scatter/gather support
+ *
****************************************************************************/
+//#define DEBUG 1
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -46,18 +53,22 @@
#include "scsi.h"
#include "hosts.h"
#include "pci2220i.h"
+#include "psi_dale.h"
-#include <linux/spinlock.h>
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93)
+#include <linux/bios32.h>
+#endif
-#define PCI2220I_VERSION "1.11"
-//#define READ_CMD IDE_COMMAND_READ
-//#define WRITE_CMD IDE_COMMAND_WRITE
-//#define MAX_BUS_MASTER_BLOCKS 1 // This is the maximum we can bus master
+#define PCI2220I_VERSION "2.00"
#define READ_CMD IDE_CMD_READ_MULTIPLE
#define WRITE_CMD IDE_CMD_WRITE_MULTIPLE
#define MAX_BUS_MASTER_BLOCKS SECTORSXFER // This is the maximum we can bus master
-//#define DEBUG 1
+struct proc_dir_entry Proc_Scsi_Pci2220i =
+ { PROC_SCSI_PCI2220I, 8, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
#ifdef DEBUG
#define DEB(x) x
@@ -72,10 +83,10 @@
typedef struct
{
- UCHAR device; // device code
UCHAR byte6; // device select register image
UCHAR spigot; // spigot number
- UCHAR sparebyte; // placeholder
+ UCHAR spigots[2]; // RAID spigots
+ UCHAR deviceID[2]; // device ID codes
USHORT sectors; // number of sectors per track
USHORT heads; // number of heads
USHORT cylinders; // number of cylinders for this device
@@ -85,12 +96,17 @@ typedef struct
ULONG lastsectorlba[2]; // last addressable sector on the drive
USHORT raid; // RAID active flag
USHORT mirrorRecon;
- UCHAR hotRecon;
+ UCHAR reconOn;
USHORT reconCount;
+ USHORT reconIsStarting; // indicate hot reconstruct is starting
+ UCHAR cmdDrqInt; // flag for command interrupt
+ UCHAR packet; // command packet size in bytes
} OUR_DEVICE, *POUR_DEVICE;
typedef struct
{
+ USHORT bigD; // identity is a PCI-2240I if true, otherwise a PCI-2220I
+ USHORT atapi; // this interface is for ATAPI devices only
USHORT regDmaDesc; // address of the DMA discriptor register for direction of transfer
USHORT regDmaCmdStat; // Byte #1 of DMA command status register
USHORT regDmaAddrPci; // 32 bit register for PCI address of DMA
@@ -119,16 +135,21 @@ typedef struct
USHORT timingPIO; // TRUE if PIO timing is active
ULONG timingAddress; // address to use on adapter for current timing mode
ULONG irqOwned; // owned IRQ or zero if shared
- OUR_DEVICE device[DALE_MAXDRIVES];
- DISK_MIRROR *raidData[8];
+ UCHAR numberOfDrives; // saved number of drives on this controller
+ UCHAR failRegister; // current inverted data in fail register
+ OUR_DEVICE device[BIGD_MAXDRIVES];
+ DISK_MIRROR *raidData[BIGD_MAXDRIVES];
ULONG startSector;
USHORT sectorCount;
+ ULONG readCount;
+ UCHAR *currentSgBuffer;
+ ULONG currentSgCount;
+ USHORT nextSg;
UCHAR cmd;
Scsi_Cmnd *SCpnt;
- VOID *buffer;
POUR_DEVICE pdev; // current device opearating on
+ USHORT devInReconIndex;
USHORT expectingIRQ;
- USHORT reconIsStarting; // indicate hot reconstruct is starting
USHORT reconOn; // Hot reconstruct is to be done.
USHORT reconPhase; // Hot reconstruct operation is in progress.
ULONG reconSize;
@@ -138,6 +159,9 @@ typedef struct
struct timer_list reconTimer;
struct timer_list timer;
UCHAR *kBuffer;
+ UCHAR reqSense;
+ UCHAR atapiCdb[16];
+ UCHAR atapiSpecial;
} ADAPTER2220I, *PADAPTER2220I;
#define HOSTDATA(host) ((PADAPTER2220I)&host->hostdata)
@@ -152,12 +176,41 @@ typedef struct
static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter
static int NumAdapters = 0;
+static int Installed = 0;
static SETUP DaleSetup;
-static DISK_MIRROR DiskMirror[2];
-static ULONG ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P};
+static DISK_MIRROR DiskMirror[BIGD_MAXDRIVES];
+static ULONG ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE5};
+static ULONG ModeArray2[] = {BIGD_DATA_MODE2, BIGD_DATA_MODE3, BIGD_DATA_MODE4, BIGD_DATA_MODE5};
static void ReconTimerExpiry (unsigned long data);
+/*******************************************************************************************************
+ * Name: Alarm
+ *
+ * Description: Sound the for the given device
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * device - Device number.
+ *
+ * Returns: Nothing.
+ *
+ ******************************************************************************************************/
+static void Alarm (PADAPTER2220I padapter, UCHAR device)
+ {
+ UCHAR zc;
+
+ if ( padapter->bigD )
+ {
+ zc = device | (FAIL_ANY | FAIL_AUDIBLE);
+ if ( padapter->failRegister & FAIL_ANY )
+ zc |= FAIL_MULTIPLE;
+
+ padapter->failRegister = zc;
+ outb_p (~zc, padapter->regFail);
+ }
+ else
+ outb_p (0x3C | (1 << device), padapter->regFail); // sound alarm and set fail light
+ }
/****************************************************************
* Name: MuteAlarm :LOCAL
*
@@ -172,8 +225,16 @@ static void MuteAlarm (PADAPTER2220I padapter)
{
UCHAR old;
- old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83);
- outb_p (old | 0x40, padapter->regFail);
+ if ( padapter->bigD )
+ {
+ padapter->failRegister &= ~FAIL_AUDIBLE;
+ outb_p (~padapter->failRegister, padapter->regFail);
+ }
+ else
+ {
+ old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83);
+ outb_p (old | 0x40, padapter->regFail);
+ }
}
/****************************************************************
* Name: WaitReady :LOCAL
@@ -214,17 +275,17 @@ static int WaitReadyReset (PADAPTER2220I padapter)
ULONG z;
UCHAR status;
- for ( z = 0; z < (250 * 4); z++ ) // wait up to 1/4 second
+ for ( z = 0; z < (125 * 16); z++ ) // wait up to 1/4 second
{
status = inb_p (padapter->regStatCmd);
if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY )
{
- DEB (printk ("\nPCI2220I: Reset took %ld mSec to be ready", z / 4));
+ DEB (printk ("\nPCI2220I: Reset took %ld mSec to be ready", z / 8));
return 0;
}
- udelay (250);
+ udelay (125);
}
- DEB (printk ("\nPCI2220I: Reset took more than 1 Second to come ready, Disk Failure"));
+ DEB (printk ("\nPCI2220I: Reset took more than 2 Seconds to come ready, Disk Failure"));
return status;
}
/****************************************************************
@@ -252,6 +313,52 @@ static int WaitDrq (PADAPTER2220I padapter)
return status;
}
/****************************************************************
+ * Name: AtapiWaitReady :LOCAL
+ *
+ * Description: Wait for device busy and DRQ to be cleared.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * msec - Number of milliseconds to wait.
+ *
+ * Returns: TRUE if drive does not clear busy in time.
+ *
+ ****************************************************************/
+static int AtapiWaitReady (PADAPTER2220I padapter, int msec)
+ {
+ int z;
+
+ for ( z = 0; z < (msec * 16); z++ )
+ {
+ if ( !(inb_p (padapter->regStatCmd) & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) )
+ return FALSE;
+ udelay (125);
+ }
+ return TRUE;
+ }
+/****************************************************************
+ * Name: AtapiWaitDrq :LOCAL
+ *
+ * Description: Wait for device ready for data transfer.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * msec - Number of milliseconds to wait.
+ *
+ * Returns: TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int AtapiWaitDrq (PADAPTER2220I padapter, int msec)
+ {
+ ULONG z;
+
+ for ( z = 0; z < (msec * 16); z++ )
+ {
+ if ( inb_p (padapter->regStatCmd) & IDE_STATUS_DRQ )
+ return 0;
+ udelay (128);
+ }
+ return TRUE;
+ }
+/****************************************************************
* Name: HardReset :LOCAL
*
* Description: Wait for device ready for data transfer.
@@ -265,24 +372,113 @@ static int WaitDrq (PADAPTER2220I padapter)
****************************************************************/
static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot)
{
- SelectSpigot (padapter, spigot | 0x80);
+ DEB (printk ("\npci2220i:RESET spigot = %X devices = %d, %d", spigot, pdev->deviceID[0], pdev->deviceID[1]));
+ udelay (100000); // just wait 100 mSec to let drives flush
+ SelectSpigot (padapter, spigot | SEL_IRQ_OFF);
outb_p (0x0E, padapter->regAltStat); // reset the suvivor
udelay (100); // wait a little
outb_p (0x08, padapter->regAltStat); // clear the reset
udelay (100);
- outb_p (0xA0, padapter->regLba24); //Specify drive
- outb_p (pdev->byte6, padapter->regLba24); // select the drive
+ outb_p (0xA0, padapter->regLba24); // select the master drive
if ( WaitReadyReset (padapter) )
+ {
+ DEB (printk ("\npci2220i: master not ready after reset"));
return TRUE;
+ }
+ outb_p (0xB0, padapter->regLba24); // try the slave drive
+ if ( (inb_p (padapter->regStatCmd) & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY )
+ {
+ DEB (printk ("\nPCI2220I: initializing slave drive on spigot %X", spigot));
+ outb_p (SECTORSXFER, padapter->regSectCount);
+ WriteCommand (padapter, IDE_CMD_SET_MULTIPLE);
+ if ( WaitReady (padapter) )
+ {
+ DEB (printk ("\npci2220i: slave not ready after set multiple"));
+ return TRUE;
+ }
+ }
+
+ outb_p (0xA0, padapter->regLba24); // select the drive
outb_p (SECTORSXFER, padapter->regSectCount);
WriteCommand (padapter, IDE_CMD_SET_MULTIPLE);
if ( WaitReady (padapter) )
+ {
+ DEB (printk ("\npci2220i: master not ready after set multiple"));
return TRUE;
+ }
return FALSE;
}
/****************************************************************
+ * Name: AtapiReset :LOCAL
+ *
+ * Description: Wait for device ready for data transfer.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * pdev - Pointer to device.
+ *
+ * Returns: TRUE if drive does not come ready.
+ *
+ ****************************************************************/
+static int AtapiReset (PADAPTER2220I padapter, POUR_DEVICE pdev)
+ {
+ SelectSpigot (padapter, pdev->spigot);
+ AtapiDevice (padapter, pdev->byte6);
+ AtapiCountLo (padapter, 0);
+ AtapiCountHi (padapter, 0);
+ WriteCommand (padapter, IDE_COMMAND_ATAPI_RESET);
+ udelay (125);
+ if ( AtapiWaitReady (padapter, 1000) )
+ return TRUE;
+ if ( inb_p (padapter->regStatCmd) || (inb_p (padapter->regLba8) != 0x14) || (inb_p (padapter->regLba16) != 0xEB) )
+ return TRUE;
+ return FALSE;
+ }
+/****************************************************************
+ * Name: WalkScatGath :LOCAL
+ *
+ * Description: Transfer data to/from scatter/gather buffers.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * datain - TRUE if data read.
+ * length - Number of bytes to transfer.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+static void WalkScatGath (PADAPTER2220I padapter, UCHAR datain, ULONG length)
+ {
+ ULONG count;
+ UCHAR *buffer = padapter->kBuffer;
+
+ while ( length )
+ {
+ count = ( length > padapter->currentSgCount ) ? padapter->currentSgCount : length;
+
+ if ( datain )
+ memcpy (padapter->currentSgBuffer, buffer, count);
+ else
+ memcpy (buffer, padapter->currentSgBuffer, count);
+
+ padapter->currentSgCount -= count;
+ if ( !padapter->currentSgCount )
+ {
+ if ( padapter->nextSg < padapter->SCpnt->use_sg )
+ {
+ padapter->currentSgBuffer = ((struct scatterlist *)padapter->SCpnt->request_buffer)[padapter->nextSg].address;
+ padapter->currentSgCount = ((struct scatterlist *)padapter->SCpnt->request_buffer)[padapter->nextSg].length;
+ padapter->nextSg++;
+ }
+ }
+ else
+ padapter->currentSgBuffer += count;
+
+ length -= count;
+ buffer += count;
+ }
+ }
+/****************************************************************
* Name: BusMaster :LOCAL
*
* Description: Do a bus master I/O.
@@ -291,34 +487,84 @@ static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot)
* datain - TRUE if data read.
* irq - TRUE if bus master interrupt expected.
*
- * Returns: TRUE if drive does not assert DRQ in time.
+ * Returns: Nothing.
*
****************************************************************/
static void BusMaster (PADAPTER2220I padapter, UCHAR datain, UCHAR irq)
{
ULONG zl;
- outl (padapter->timingAddress, padapter->regDmaAddrLoc);
- outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci);
- zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
+ zl = ( padapter->sectorCount > MAX_BUS_MASTER_BLOCKS ) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
padapter->sectorCount -= zl;
zl *= (ULONG)BYTES_PER_SECTOR;
- padapter->buffer += zl;
- outl (zl, padapter->regDmaCount);
+
if ( datain )
{
- outb_p (8, padapter->regDmaDesc); // read operation
- if ( irq && !padapter->sectorCount )
- outb_p (5, padapter->regDmaMode); // interrupt on
+ padapter->readCount = zl;
+ outb_p (8, padapter->regDmaDesc); // read operation
+ if ( padapter->bigD )
+ {
+ if ( irq && !padapter->sectorCount )
+ outb_p (0x0C, padapter->regDmaMode); // interrupt on
+ else
+ outb_p (0x08, padapter->regDmaMode); // no interrupt
+ }
+ else
+ {
+ if ( irq && !padapter->sectorCount )
+ outb_p (0x05, padapter->regDmaMode); // interrupt on
+ else
+ outb_p (0x01, padapter->regDmaMode); // no interrupt
+ }
+ }
+ else
+ {
+ outb_p (0x00, padapter->regDmaDesc); // write operation
+ if ( padapter->bigD )
+ outb_p (0x08, padapter->regDmaMode); // no interrupt
else
- outb_p (1, padapter->regDmaMode); // no interrupt
+ outb_p (0x01, padapter->regDmaMode); // no interrupt
+ WalkScatGath (padapter, FALSE, zl);
+ }
+
+ outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+ outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
+ outl (zl, padapter->regDmaCount);
+ outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
+ }
+/****************************************************************
+ * Name: AtapiBusMaster :LOCAL
+ *
+ * Description: Do a bus master I/O.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * datain - TRUE if data read.
+ * length - Number of bytes to transfer.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+static void AtapiBusMaster (PADAPTER2220I padapter, UCHAR datain, ULONG length)
+ {
+ outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+ outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
+ outl (length, padapter->regDmaCount);
+ if ( datain )
+ {
+ if ( padapter->readCount )
+ WalkScatGath (padapter, TRUE, padapter->readCount);
+ outb_p (0x08, padapter->regDmaDesc); // read operation
+ outb_p (0x08, padapter->regDmaMode); // no interrupt
+ padapter->readCount = length;
}
else
{
- outb_p (0, padapter->regDmaDesc); // write operation
- outb_p (1, padapter->regDmaMode); // no interrupt
+ outb_p (0x00, padapter->regDmaDesc); // write operation
+ outb_p (0x08, padapter->regDmaMode); // no interrupt
+ if ( !padapter->atapiSpecial )
+ WalkScatGath (padapter, FALSE, length);
}
- outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
+ outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
}
/****************************************************************
* Name: WriteData :LOCAL
@@ -339,9 +585,9 @@ static int WriteData (PADAPTER2220I padapter)
if ( padapter->timingPIO )
{
zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
- outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
+ WalkScatGath (padapter, FALSE, zl * BYTES_PER_SECTOR);
+ outsw (padapter->regData, padapter->kBuffer, zl * (BYTES_PER_SECTOR / 2));
padapter->sectorCount -= zl;
- padapter->buffer += zl * BYTES_PER_SECTOR;
}
else
BusMaster (padapter, 0, 0);
@@ -355,31 +601,32 @@ static int WriteData (PADAPTER2220I padapter)
*
* Description: Write data to device.
*
- * Parameters: padapter - Pointer adapter data structure.
+ * Parameters: padapter - Pointer to adapter structure.
+ * pdev - Pointer to device structure
*
- * Returns: TRUE if drive does not assert DRQ in time.
+ * Returns: Index + 1 of drive not failed or zero for OK.
*
****************************************************************/
-static int WriteDataBoth (PADAPTER2220I padapter)
+static int WriteDataBoth (PADAPTER2220I padapter, POUR_DEVICE pdev)
{
ULONG zl;
UCHAR status0, status1;
- SelectSpigot (padapter, 1);
+ SelectSpigot (padapter, pdev->spigots[0]);
status0 = WaitDrq (padapter);
if ( !status0 )
{
- SelectSpigot (padapter, 2);
+ SelectSpigot (padapter, pdev->spigots[1]);
status1 = WaitDrq (padapter);
if ( !status1 )
{
- SelectSpigot (padapter, 3);
+ SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1] | padapter->bigD);
if ( padapter->timingPIO )
{
zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
- outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
+ WalkScatGath (padapter, FALSE, zl * BYTES_PER_SECTOR);
+ outsw (padapter->regData, padapter->kBuffer, zl * (BYTES_PER_SECTOR / 2));
padapter->sectorCount -= zl;
- padapter->buffer += zl * BYTES_PER_SECTOR;
}
else
BusMaster (padapter, 0, 0);
@@ -388,8 +635,8 @@ static int WriteDataBoth (PADAPTER2220I padapter)
}
padapter->cmd = 0; // null out the command byte
if ( status0 )
- return 1;
- return 2;
+ return 2;
+ return 1;
}
/****************************************************************
* Name: IdeCmd :LOCAL
@@ -406,7 +653,7 @@ static UCHAR IdeCmd (PADAPTER2220I padapter, POUR_DEVICE pdev)
{
UCHAR status;
- SelectSpigot (padapter, pdev->spigot); // select the spigot
+ SelectSpigot (padapter, pdev->spigot | padapter->bigD); // select the spigot
outb_p (pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24); // select the drive
status = WaitReady (padapter);
if ( !status )
@@ -429,26 +676,27 @@ static UCHAR IdeCmd (PADAPTER2220I padapter, POUR_DEVICE pdev)
* Description: Process an IDE command to both drivers.
*
* Parameters: padapter - Pointer adapter data structure.
+ * pdev - Pointer to device structure
*
- * Returns: Zero if no error or spigot of error.
+ * Returns: Index + 1 of drive not failed or zero for OK.
*
****************************************************************/
-static UCHAR IdeCmdBoth (PADAPTER2220I padapter)
+static UCHAR IdeCmdBoth (PADAPTER2220I padapter, POUR_DEVICE pdev)
{
UCHAR status0;
UCHAR status1;
- SelectSpigot (padapter, 3); // select the spigots
+ SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]); // select the spigots
outb_p (padapter->pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24);// select the drive
- SelectSpigot (padapter, 1);
+ SelectSpigot (padapter, pdev->spigots[0]);
status0 = WaitReady (padapter);
if ( !status0 )
{
- SelectSpigot (padapter, 2);
+ SelectSpigot (padapter, pdev->spigots[1]);
status1 = WaitReady (padapter);
if ( !status1 )
{
- SelectSpigot (padapter, 3);
+ SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1] | padapter->bigD);
outb_p (padapter->sectorCount, padapter->regSectCount);
outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0);
outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8);
@@ -460,8 +708,8 @@ static UCHAR IdeCmdBoth (PADAPTER2220I padapter)
}
padapter->cmd = 0; // null out the command byte
if ( status0 )
- return 1;
- return 2;
+ return 2;
+ return 1;
}
/****************************************************************
* Name: OpDone :LOCAL
@@ -498,6 +746,7 @@ static void OpDone (PADAPTER2220I padapter, ULONG result)
{
padapter->cmd = 0;
padapter->SCpnt = NULL;
+ padapter->pdev = NULL;
SCpnt->result = result;
SCpnt->scsi_done (SCpnt);
if ( padapter->reconOn && !padapter->reconTimer.data )
@@ -524,8 +773,8 @@ static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device)
{
PIDENTIFY_DATA pid = (PIDENTIFY_DATA)padapter->kBuffer;
- SelectSpigot (padapter, spigot | 0x80); // select the spigot
- outb_p (device << 4, padapter->regLba24); // select the drive
+ SelectSpigot (padapter, spigot | SEL_IRQ_OFF); // select the spigot
+ outb_p ((device << 4) | 0xA0, padapter->regLba24); // select the drive
if ( WaitReady (padapter) )
return 0;
WriteCommand (padapter, IDE_COMMAND_IDENTIFY);
@@ -535,6 +784,192 @@ static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device)
return (pid->LBATotalSectors - 1);
}
/****************************************************************
+ * Name: AtapiIdentify :LOCAL
+ *
+ * Description: Do an intline inquiry on a drive.
+ *
+ * Parameters: padapter - Pointer to host data block.
+ * pdev - Pointer to device table.
+ *
+ * Returns: TRUE on error.
+ *
+ ****************************************************************/
+static ULONG AtapiIdentify (PADAPTER2220I padapter, POUR_DEVICE pdev)
+ {
+ ATAPI_GENERAL_0 ag0;
+ USHORT zs;
+ int z;
+
+ AtapiDevice (padapter, pdev->byte6);
+ WriteCommand (padapter, IDE_COMMAND_ATAPI_IDENTIFY);
+ if ( AtapiWaitDrq (padapter, 3000) )
+ return TRUE;
+
+ *(USHORT *)&ag0 = inw_p (padapter->regData);
+ for ( z = 0; z < 255; z++ )
+ zs = inw_p (padapter->regData);
+
+ if ( ag0.ProtocolType == 2 )
+ {
+ if ( ag0.CmdDrqType == 1 )
+ pdev->cmdDrqInt = TRUE;
+ switch ( ag0.CmdPacketSize )
+ {
+ case 0:
+ pdev->packet = 6;
+ break;
+ case 1:
+ pdev->packet = 8;
+ break;
+ default:
+ pdev->packet = 6;
+ break;
+ }
+ return FALSE;
+ }
+ return TRUE;
+ }
+/****************************************************************
+ * Name: Atapi2Scsi
+ *
+ * Description: Convert ATAPI data to SCSI data.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * SCpnt - Pointer to SCSI command structure.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+void Atapi2Scsi (PADAPTER2220I padapter, Scsi_Cmnd *SCpnt)
+ {
+ UCHAR *buff = padapter->currentSgBuffer;
+
+ switch ( SCpnt->cmnd[0] )
+ {
+ case SCSIOP_MODE_SENSE:
+ buff[0] = padapter->kBuffer[1];
+ buff[1] = padapter->kBuffer[2];
+ buff[2] = padapter->kBuffer[3];
+ buff[3] = padapter->kBuffer[7];
+ memcpy (&buff[4], &padapter->kBuffer[8], padapter->atapiCdb[8] - 8);
+ break;
+ case SCSIOP_INQUIRY:
+ padapter->kBuffer[2] = 2;
+ memcpy (buff, padapter->kBuffer, padapter->currentSgCount);
+ break;
+ default:
+ if ( padapter->readCount )
+ WalkScatGath (padapter, TRUE, padapter->readCount);
+ break;
+ }
+ }
+/****************************************************************
+ * Name: Scsi2Atapi
+ *
+ * Description: Convert SCSI packet command to Atapi packet command.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * SCpnt - Pointer to SCSI command structure.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+static void Scsi2Atapi (PADAPTER2220I padapter, Scsi_Cmnd *SCpnt)
+ {
+ UCHAR *cdb = SCpnt->cmnd;
+ UCHAR *buff = padapter->currentSgBuffer;
+
+ switch (cdb[0])
+ {
+ case SCSIOP_READ6:
+ padapter->atapiCdb[0] = SCSIOP_READ;
+ padapter->atapiCdb[1] = cdb[1] & 0xE0;
+ padapter->atapiCdb[3] = cdb[1] & 0x1F;
+ padapter->atapiCdb[4] = cdb[2];
+ padapter->atapiCdb[5] = cdb[3];
+ padapter->atapiCdb[8] = cdb[4];
+ padapter->atapiCdb[9] = cdb[5];
+ break;
+ case SCSIOP_WRITE6:
+ padapter->atapiCdb[0] = SCSIOP_WRITE;
+ padapter->atapiCdb[1] = cdb[1] & 0xE0;
+ padapter->atapiCdb[3] = cdb[1] & 0x1F;
+ padapter->atapiCdb[4] = cdb[2];
+ padapter->atapiCdb[5] = cdb[3];
+ padapter->atapiCdb[8] = cdb[4];
+ padapter->atapiCdb[9] = cdb[5];
+ break;
+ case SCSIOP_MODE_SENSE:
+ padapter->atapiCdb[0] = SCSIOP_MODE_SENSE10;
+ padapter->atapiCdb[2] = cdb[2];
+ padapter->atapiCdb[8] = cdb[4] + 4;
+ break;
+
+ case SCSIOP_MODE_SELECT:
+ padapter->atapiSpecial = TRUE;
+ padapter->atapiCdb[0] = SCSIOP_MODE_SELECT10;
+ padapter->atapiCdb[1] = cdb[1] | 0x10;
+ memcpy (padapter->kBuffer, buff, 4);
+ padapter->kBuffer[4] = padapter->kBuffer[5] = 0;
+ padapter->kBuffer[6] = padapter->kBuffer[7] = 0;
+ memcpy (&padapter->kBuffer[8], &buff[4], cdb[4] - 4);
+ padapter->atapiCdb[8] = cdb[4] + 4;
+ break;
+ }
+ }
+/****************************************************************
+ * Name: AtapiSendCdb
+ *
+ * Description: Send the CDB packet to the device.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * pdev - Pointer to device.
+ * cdb - Pointer to 16 byte SCSI cdb.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+static void AtapiSendCdb (PADAPTER2220I padapter, POUR_DEVICE pdev, CHAR *cdb)
+ {
+ DEB (printk ("\nPCI2242I: CDB: %X %X %X %X %X %X %X %X %X %X %X %X", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]));
+ outsw (padapter->regData, cdb, pdev->packet);
+ }
+/****************************************************************
+ * Name: AtapiRequestSense
+ *
+ * Description: Send the CDB packet to the device.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * pdev - Pointer to device.
+ * SCpnt - Pointer to SCSI command structure.
+ * pass - If true then this is the second pass to send cdb.
+ *
+ * Returns: TRUE on error.
+ *
+ ****************************************************************/
+static int AtapiRequestSense (PADAPTER2220I padapter, POUR_DEVICE pdev, Scsi_Cmnd *SCpnt, UCHAR pass)
+ {
+ UCHAR cdb[16] = {SCSIOP_REQUEST_SENSE,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0};
+
+ DEB (printk ("\nPCI2242I: AUTO REQUEST SENSE"));
+ cdb[4] = (UCHAR)(sizeof (SCpnt->sense_buffer));
+ if ( !pass )
+ {
+ padapter->reqSense = TRUE;
+ AtapiCountLo (padapter, cdb[4]);
+ AtapiCountHi (padapter, 0);
+ outb_p (0, padapter->regError);
+ WriteCommand (padapter, IDE_COMMAND_ATAPI_PACKET);
+ if ( pdev->cmdDrqInt )
+ return FALSE;
+
+ if ( AtapiWaitDrq (padapter, 500) )
+ return TRUE;
+ }
+ AtapiSendCdb (padapter, pdev, cdb);
+ return FALSE;
+ }
+/****************************************************************
* Name: InlineReadSignature :LOCAL
*
* Description: Do an inline read RAID sigature.
@@ -549,10 +984,9 @@ static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device)
static UCHAR InlineReadSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, int index)
{
UCHAR status;
- UCHAR spigot = 1 << index;
ULONG zl = pdev->lastsectorlba[index];
- SelectSpigot (padapter, spigot | 0x80); // select the spigot without interrupts
+ SelectSpigot (padapter, pdev->spigots[index] | SEL_IRQ_OFF); // select the spigot without interrupts
outb_p (pdev->byte6 | ((UCHAR *)&zl)[3], padapter->regLba24);
status = WaitReady (padapter);
if ( !status )
@@ -591,6 +1025,10 @@ static ULONG DecodeError (PADAPTER2220I padapter, UCHAR status)
UCHAR error;
padapter->expectingIRQ = 0;
+#ifdef DEBUG
+ printk (" @@@@@@ status: %X @@@@@@@ ", status);
+ STOP_HERE();
+#endif
if ( status & IDE_STATUS_WRITE_FAULT )
{
return DID_PARITY << 16;
@@ -678,25 +1116,33 @@ static int WriteSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigo
******************************************************************************************************/
static int InitFailover (PADAPTER2220I padapter, POUR_DEVICE pdev)
{
- UCHAR spigot;
+ UCHAR spigot;
- DEB (printk ("\npci2220i: Initialize failover process - survivor = %d", padapter->survivor));
+ DEB (printk ("\npci2220i: Initialize failover process - survivor = %d", pdev->deviceID[padapter->survivor]));
pdev->raid = FALSE; //initializes system for non raid mode
- pdev->hotRecon = 0;
- padapter->reconOn = FALSE;
- spigot = (padapter->survivor) ? 2 : 1;
+ pdev->reconOn = FALSE;
+ spigot = pdev->spigots[padapter->survivor];
if ( pdev->DiskMirror[padapter->survivor].status & UCBF_REBUILD )
- return (TRUE);
+ {
+ DEB (printk ("\n failed, is survivor"));
+ return (TRUE);
+ }
if ( HardReset (padapter, pdev, spigot) )
+ {
+ DEB (printk ("\n failed, reset"));
return TRUE;
+ }
- outb_p (0x3C | spigot, padapter->regFail); // sound alarm and set fail light
+ Alarm (padapter, pdev->deviceID[padapter->survivor ^ 1]);
pdev->DiskMirror[padapter->survivor].status = UCBF_MIRRORED | UCBF_SURVIVOR; //clear present status
if ( WriteSignature (padapter, pdev, spigot, padapter->survivor) )
+ {
+ DEB (printk ("\n failed, write signature"));
return TRUE;
+ }
padapter->failinprog = TRUE;
return FALSE;
}
@@ -716,13 +1162,23 @@ static void TimerExpiry (unsigned long data)
POUR_DEVICE pdev = padapter->pdev;
UCHAR status = IDE_STATUS_BUSY;
UCHAR temp, temp1;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ int flags;
+#else /* version >= v2.1.95 */
unsigned long flags;
+#endif /* version >= v2.1.95 */
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /* Disable interrupts, if they aren't already disabled. */
+ save_flags (flags);
+ cli ();
+#else /* version >= v2.1.95 */
/*
* Disable interrupts, if they aren't already disabled and acquire
* the I/O spinlock.
*/
spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
DEB (printk ("\nPCI2220I: Timeout expired "));
if ( padapter->failinprog )
@@ -739,7 +1195,7 @@ static void TimerExpiry (unsigned long data)
{
case RECON_PHASE_MARKING:
case RECON_PHASE_LAST:
- padapter->survivor = (pdev->spigot ^ 3) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
DEB (printk ("\npci2220i: FAILURE 1"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DID_ERROR << 16);
@@ -750,7 +1206,7 @@ static void TimerExpiry (unsigned long data)
goto timerExpiryDone;
case RECON_PHASE_COPY:
- padapter->survivor = (pdev->spigot) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 2"));
DEB (printk ("\n spig/stat = %X", inb_p (padapter->regStatSel));
if ( InitFailover (padapter, pdev) )
@@ -758,14 +1214,14 @@ static void TimerExpiry (unsigned long data)
goto timerExpiryDone;
case RECON_PHASE_UPDATE:
- padapter->survivor = (pdev->spigot) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 3")));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DID_ERROR << 16);
goto timerExpiryDone;
case RECON_PHASE_END:
- padapter->survivor = (pdev->spigot) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 4"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DID_ERROR << 16);
@@ -784,17 +1240,21 @@ static void TimerExpiry (unsigned long data)
if ( padapter->cmd == WRITE_CMD )
{
DEB (printk ("in RAID write operation"));
- if ( inb_p (padapter->regStatSel) & 1 )
+ temp = ( pdev->spigot & (SEL_1 | SEL_2) ) ? SEL_1 : SEL_3;
+ if ( inb_p (padapter->regStatSel) & temp )
{
- SelectSpigot (padapter, 0x81 ); // Masking the interrupt during spigot select
+ DEB (printk ("\npci2220i: Determined A OK"));
+ SelectSpigot (padapter, temp | SEL_IRQ_OFF); // Masking the interrupt during spigot select
temp = inb_p (padapter->regStatCmd);
}
else
temp = IDE_STATUS_BUSY;
- if ( inb (padapter->regStatSel) & 2 )
+ temp1 = ( pdev->spigot & (SEL_1 | SEL_2) ) ? SEL_2 : SEL_4;
+ if ( inb (padapter->regStatSel) & temp1 )
{
- SelectSpigot (padapter, 0x82 ); // Masking the interrupt during spigot select
+ DEB (printk ("\npci2220i: Determined B OK"));
+ SelectSpigot (padapter, temp1 | SEL_IRQ_OFF); // Masking the interrupt during spigot select
temp1 = inb_p (padapter->regStatCmd);
}
else
@@ -802,6 +1262,7 @@ static void TimerExpiry (unsigned long data)
if ( (temp & IDE_STATUS_BUSY) || (temp1 & IDE_STATUS_BUSY) )
{
+ DEB (printk ("\npci2220i: Status A: %X B: %X", temp & 0xFF, temp1 & 0xFF));
if ( (temp & IDE_STATUS_BUSY) && (temp1 & IDE_STATUS_BUSY) )
{
status = temp;
@@ -809,11 +1270,10 @@ static void TimerExpiry (unsigned long data)
}
else
{
- if (temp & IDE_STATUS_BUSY)
+ if ( temp & IDE_STATUS_BUSY )
padapter->survivor = 1;
else
padapter->survivor = 0;
- DEB (printk ("\npci2220i: FAILURE 5"));
if ( InitFailover (padapter, pdev) )
{
status = inb_p (padapter->regStatCmd);
@@ -826,7 +1286,7 @@ static void TimerExpiry (unsigned long data)
else
{
DEB (printk ("in RAID read operation"));
- padapter->survivor = (pdev->spigot ^ 3) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 6"));
if ( InitFailover (padapter, pdev) )
{
@@ -847,12 +1307,20 @@ static void TimerExpiry (unsigned long data)
OpDone (padapter, DecodeError (padapter, status));
timerExpiryDone:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /*
+ * Restore the original flags which will enable interrupts
+ * if and only if they were enabled on entry.
+ */
+ restore_flags (flags);
+#else /* version >= v2.1.95 */
/*
* Release the I/O spinlock and restore the original flags
* which will enable interrupts if and only if they were
* enabled on entry.
*/
spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
}
/****************************************************************
* Name: SetReconstruct :LOCAL
@@ -871,7 +1339,6 @@ static LONG SetReconstruct (POUR_DEVICE pdev, int index)
pdev->DiskMirror[index ^ 1].status = UCBF_MIRRORED | UCBF_REBUILD;
pdev->DiskMirror[index ^ 1].reconstructPoint = 0; // start the reconstruct
pdev->reconCount = 1990; // mark target drive early
- pdev->hotRecon = 1 >> index;
return pdev->DiskMirror[index].reconstructPoint;
}
/****************************************************************
@@ -893,35 +1360,66 @@ static void ReconTimerExpiry (unsigned long data)
USHORT minmode;
ULONG zl;
UCHAR zc;
+ USHORT z;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ int flags;
+#else /* version >= v2.1.95 */
unsigned long flags;
+#endif /* version >= v2.1.95 */
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /* Disable interrupts, if they aren't already disabled. */
+ save_flags (flags);
+ cli ();
+#else /* version >= v2.1.95 */
/*
* Disable interrupts, if they aren't already disabled and acquire
* the I/O spinlock.
*/
spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
padapter = (PADAPTER2220I)data;
if ( padapter->SCpnt )
goto reconTimerExpiry;
- pdev = padapter->device;
- pid = (PIDENTIFY_DATA)padapter->kBuffer;
padapter->reconTimer.data = 0;
+ for ( z = padapter->devInReconIndex + 1; z < BIGD_MAXDRIVES; z++ )
+ {
+ if ( padapter->device[z].reconOn )
+ break;
+ }
+ if ( z < BIGD_MAXDRIVES )
+ pdev = &padapter->device[z];
+ else
+ {
+ for ( z = 0; z < BIGD_MAXDRIVES; z++ )
+ {
+ if ( padapter->device[z].reconOn )
+ break;
+ }
+ if ( z < BIGD_MAXDRIVES )
+ pdev = &padapter->device[z];
+ else
+ {
+ padapter->reconOn = FALSE;
+ goto reconTimerExpiry;
+ }
+ }
+
+ padapter->devInReconIndex = z;
+ pid = (PIDENTIFY_DATA)padapter->kBuffer;
padapter->pdev = pdev;
- if ( padapter->reconIsStarting )
+ if ( pdev->reconIsStarting )
{
- padapter->reconIsStarting = FALSE;
- padapter->reconOn = FALSE;
- pdev->hotRecon = FALSE;
+ pdev->reconIsStarting = FALSE;
+ pdev->reconOn = FALSE;
- if ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) &&
+ while ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) &&
(pdev->DiskMirror[0].pairIdentifier == (pdev->DiskMirror[1].pairIdentifier ^ 1)) )
{
if ( (pdev->DiskMirror[0].status & UCBF_MATCHED) && (pdev->DiskMirror[1].status & UCBF_MATCHED) )
- {
- goto reconTimerExpiry;
- }
+ break;;
if ( pdev->DiskMirror[0].status & UCBF_SURVIVOR ) // is first drive survivor?
testsize = SetReconstruct (pdev, 0);
@@ -932,33 +1430,38 @@ static void ReconTimerExpiry (unsigned long data)
if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
{
if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
- {
- pdev->hotRecon = 1;
pdev->mirrorRecon = 0;
- }
else
- {
- pdev->hotRecon = 2;
pdev->mirrorRecon = 1;
- }
+ pdev->reconOn = TRUE;
}
+ break;
}
- if ( !pdev->hotRecon )
+ if ( !pdev->reconOn )
goto reconTimerExpiry;
- zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83; // mute the alarm
- outb_p (zc | pdev->hotRecon | 0x40, padapter->regFail);
+ if ( padapter->bigD )
+ {
+ padapter->failRegister = 0;
+ outb_p (~padapter->failRegister, padapter->regFail);
+ }
+ else
+ {
+ zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83; // mute the alarm
+ outb_p (0xFF, padapter->regFail);
+ }
while ( 1 )
{
- if ( HardReset (padapter, pdev, pdev->hotRecon) )
+ DEB (printk ("\npci2220i: hard reset issue"));
+ if ( HardReset (padapter, pdev, pdev->spigots[pdev->mirrorRecon]) )
{
DEB (printk ("\npci2220i: sub 1"));
break;
}
- pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->hotRecon, 0);
+ pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->spigots[pdev->mirrorRecon], pdev->deviceID[pdev->mirrorRecon] & 1);
if ( pdev->lastsectorlba[pdev->mirrorRecon] < testsize )
{
@@ -1014,12 +1517,11 @@ static void ReconTimerExpiry (unsigned long data)
break;
}
- if ( !padapter->reconOn )
+ if ( !pdev->reconOn )
{
- pdev->hotRecon = FALSE;
padapter->survivor = pdev->mirrorRecon ^ 1;
padapter->reconPhase = RECON_PHASE_FAILOVER;
- DEB (printk ("\npci2220i: FAILURE 7"));
+ DEB (printk ("\npci2220i: FAILURE 7"));
InitFailover (padapter, pdev);
goto reconTimerExpiry;
}
@@ -1038,11 +1540,11 @@ static void ReconTimerExpiry (unsigned long data)
if ( pdev->reconCount++ > 2000 )
{
pdev->reconCount = 0;
- if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) )
+ if ( WriteSignature (padapter, pdev, pdev->spigots[pdev->mirrorRecon], pdev->mirrorRecon) )
{
padapter->survivor = pdev->mirrorRecon ^ 1;
padapter->reconPhase = RECON_PHASE_FAILOVER;
- DEB (printk ("\npci2220i: FAILURE 8"));
+ DEB (printk ("\npci2220i: FAILURE 8"));
InitFailover (padapter, pdev);
goto reconTimerExpiry;
}
@@ -1057,30 +1559,30 @@ static void ReconTimerExpiry (unsigned long data)
if ( padapter->reconSize )
{
- SelectSpigot (padapter, 3); // select the spigots
- outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24);// select the drive
+ SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]); // select the spigots
+ outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24); // select the drive
SelectSpigot (padapter, pdev->spigot);
if ( WaitReady (padapter) )
goto reconTimerExpiry;
- SelectSpigot (padapter, pdev->hotRecon);
+ SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
if ( WaitReady (padapter) )
{
padapter->survivor = pdev->mirrorRecon ^ 1;
padapter->reconPhase = RECON_PHASE_FAILOVER;
- DEB (printk ("\npci2220i: FAILURE 9"));
+ DEB (printk ("\npci2220i: FAILURE 9"));
InitFailover (padapter, pdev);
goto reconTimerExpiry;
}
- SelectSpigot (padapter, 3);
+ SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]);
outb_p (padapter->reconSize & 0xFF, padapter->regSectCount);
outb_p (((UCHAR *)(&zl))[0], padapter->regLba0);
outb_p (((UCHAR *)(&zl))[1], padapter->regLba8);
outb_p (((UCHAR *)(&zl))[2], padapter->regLba16);
padapter->expectingIRQ = TRUE;
padapter->reconPhase = RECON_PHASE_READY;
- SelectSpigot (padapter, pdev->hotRecon);
+ SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
WriteCommand (padapter, WRITE_CMD);
StartTimer (padapter);
SelectSpigot (padapter, pdev->spigot);
@@ -1095,12 +1597,20 @@ static void ReconTimerExpiry (unsigned long data)
padapter->reconPhase = RECON_PHASE_LAST;
reconTimerExpiry:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /*
+ * Restore the original flags which will enable interrupts
+ * if and only if they were enabled on entry.
+ */
+ restore_flags (flags);
+#else /* version >= v2.1.95 */
/*
* Release the I/O spinlock and restore the original flags
* which will enable interrupts if and only if they were
* enabled on entry.
*/
spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
}
/****************************************************************
* Name: Irq_Handler :LOCAL
@@ -1122,15 +1632,28 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
Scsi_Cmnd *SCpnt;
UCHAR status;
UCHAR status1;
+ ATAPI_STATUS statusa;
+ ATAPI_REASON reasona;
+ ATAPI_ERROR errora;
int z;
ULONG zl;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ int flags;
+#else /* version >= v2.1.95 */
unsigned long flags;
+#endif /* version >= v2.1.95 */
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /* Disable interrupts, if they aren't already disabled. */
+ save_flags (flags);
+ cli ();
+#else /* version >= v2.1.95 */
/*
* Disable interrupts, if they aren't already disabled and acquire
* the I/O spinlock.
*/
spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
// DEB (printk ("\npci2220i recieved interrupt\n"));
@@ -1155,7 +1678,70 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
padapter = HOSTDATA(shost);
pdev = padapter->pdev;
SCpnt = padapter->SCpnt;
+ outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine
+ if ( padapter->atapi && SCpnt )
+ {
+ *(char *)&statusa = inb_p (padapter->regStatCmd); // read the device status
+ *(char *)&reasona = inb_p (padapter->regSectCount); // read the device interrupt reason
+
+ if ( !statusa.bsy )
+ {
+ if ( statusa.drq ) // test for transfer phase
+ {
+ if ( !reasona.cod ) // test for data phase
+ {
+ z = (ULONG)inb_p (padapter->regLba8) | (ULONG)(inb_p (padapter->regLba16) << 8);
+ if ( padapter->reqSense )
+ insw (padapter->regData, SCpnt->sense_buffer, z / 2);
+ else
+ AtapiBusMaster (padapter, reasona.io, z);
+ goto irq_return;
+ }
+ if ( reasona.cod && !reasona.io ) // test for command packet phase
+ {
+ if ( padapter->reqSense )
+ AtapiRequestSense (padapter, pdev, SCpnt, TRUE);
+ else
+ AtapiSendCdb (padapter, pdev, padapter->atapiCdb);
+ goto irq_return;
+ }
+ }
+ else
+ {
+ if ( reasona.io && statusa.drdy ) // test for status phase
+ {
+ Atapi2Scsi (padapter, SCpnt);
+ if ( statusa.check )
+ {
+ *(UCHAR *)&errora = inb_p (padapter->regError); // read the device error
+ if ( errora.senseKey )
+ {
+ if ( padapter->reqSense || AtapiRequestSense (padapter, pdev, SCpnt, FALSE) )
+ OpDone (padapter, DID_ERROR << 16);
+ }
+ else
+ {
+ if ( errora.ili || errora.abort )
+ OpDone (padapter, DID_ERROR << 16);
+ else
+ OpDone (padapter, DID_OK << 16);
+ }
+ }
+ else
+ if ( padapter->reqSense )
+ {
+ DEB (printk ("PCI2242I: Sense codes - %X %X %X ", ((UCHAR *)SCpnt->sense_buffer)[0], ((UCHAR *)SCpnt->sense_buffer)[12], ((UCHAR *)SCpnt->sense_buffer)[13]));
+ OpDone (padapter, (DRIVER_SENSE << 24) | (DID_OK << 16) | 2);
+ }
+ else
+ OpDone (padapter, DID_OK << 16);
+ }
+ }
+ }
+ goto irq_return;
+ }
+
if ( !padapter->expectingIRQ || !(SCpnt || padapter->reconPhase) )
{
DEB(printk ("\npci2220i Unsolicited interrupt\n"));
@@ -1163,7 +1749,6 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
goto irq_return;
}
padapter->expectingIRQ = 0;
- outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine
if ( padapter->failinprog )
{
@@ -1178,7 +1763,7 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
else
{
DEB (printk ("\npci2220i: restarting failed opertation."));
- pdev->spigot = (padapter->survivor) ? 2 : 1;
+ pdev->spigot = (padapter->survivor) ? pdev->spigots[1] : pdev->spigots[0];
del_timer (&padapter->timer);
if ( padapter->reconPhase )
OpDone (padapter, DID_OK << 16);
@@ -1200,15 +1785,15 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
{
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
- padapter->survivor = (pdev->spigot ^ 3) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
DEB (printk ("\npci2220i: FAILURE 10"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
goto irq_return;
}
- if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) )
+ if ( WriteSignature (padapter, pdev, pdev->spigots[pdev->mirrorRecon], pdev->mirrorRecon) )
{
- padapter->survivor = (pdev->spigot) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 11"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
@@ -1228,17 +1813,17 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
OpDone (padapter, DecodeError (padapter, status));
goto irq_return;
}
- SelectSpigot (padapter, pdev->hotRecon);
+ SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
if ( WaitDrq (padapter) )
{
del_timer (&padapter->timer);
- padapter->survivor = (pdev->spigot) >> 1;
- DEB (printk ("\npci2220i: FAILURE 12"));
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+ DEB (printk ("\npci2220i: FAILURE 12"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
goto irq_return;
}
- SelectSpigot (padapter, pdev->spigot | 0x40);
+ SelectSpigot (padapter, pdev->spigot | SEL_COPY | padapter->bigD);
padapter->reconPhase = RECON_PHASE_COPY;
padapter->expectingIRQ = TRUE;
if ( padapter->timingPIO )
@@ -1247,11 +1832,22 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
}
else
{
- outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+ if ( (padapter->timingMode > 3) )
+ {
+ if ( padapter->bigD )
+ outl (BIGD_DATA_MODE3, padapter->regDmaAddrLoc);
+ else
+ outl (DALE_DATA_MODE3, padapter->regDmaAddrLoc);
+ }
+ else
+ outl (padapter->timingAddress, padapter->regDmaAddrLoc);
outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
outl (padapter->reconSize * BYTES_PER_SECTOR, padapter->regDmaCount);
outb_p (8, padapter->regDmaDesc); // read operation
- outb_p (1, padapter->regDmaMode); // no interrupt
+ if ( padapter->bigD )
+ outb_p (8, padapter->regDmaMode); // no interrupt
+ else
+ outb_p (1, padapter->regDmaMode); // no interrupt
outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
}
goto irq_return;
@@ -1260,13 +1856,14 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint += padapter->reconSize;
case RECON_PHASE_UPDATE:
- SelectSpigot (padapter, pdev->hotRecon | 0x80);
+ SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon] | SEL_IRQ_OFF);
status = inb_p (padapter->regStatCmd); // read the device status
del_timer (&padapter->timer);
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
- padapter->survivor = (pdev->spigot) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 13"));
+ DEB (printk ("\n status register = %X error = %X", status, inb_p (padapter->regError)));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
goto irq_return;
@@ -1279,14 +1876,29 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
del_timer (&padapter->timer);
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
- padapter->survivor = (pdev->spigot) >> 1;
- DEB (printk ("\npci2220i: FAILURE 14"));
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+ DEB (printk ("\npci2220i: FAILURE 14"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
goto irq_return;
}
- padapter->reconOn = FALSE;
- pdev->hotRecon = 0;
+ pdev->reconOn = 0;
+ if ( padapter->bigD )
+ {
+ for ( z = 0; z < padapter->numberOfDrives; z++ )
+ {
+ if ( padapter->device[z].DiskMirror[0].status & UCBF_SURVIVOR )
+ {
+ Alarm (padapter, padapter->device[z].deviceID[0] ^ 2);
+ MuteAlarm (padapter);
+ }
+ if ( padapter->device[z].DiskMirror[1].status & UCBF_SURVIVOR )
+ {
+ Alarm (padapter, padapter->device[z].deviceID[1] ^ 2);
+ MuteAlarm (padapter);
+ }
+ }
+ }
OpDone (padapter, DID_OK << 16);
goto irq_return;
@@ -1305,9 +1917,9 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
{
if ( pdev->raid )
{
- padapter->survivor = (pdev->spigot ^ 3) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
del_timer (&padapter->timer);
- DEB (printk ("\npci2220i: FAILURE 15"));
+ DEB (printk ("\npci2220i: FAILURE 15"));
if ( !InitFailover (padapter, pdev) )
goto irq_return;
}
@@ -1315,10 +1927,9 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
}
if ( padapter->timingPIO )
{
- zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
- insw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
- padapter->sectorCount -= zl;
- padapter->buffer += zl * BYTES_PER_SECTOR;
+ insw (padapter->regData, padapter->kBuffer, padapter->readCount / 2);
+ padapter->sectorCount -= padapter->readCount / BYTES_PER_SECTOR;
+ WalkScatGath (padapter, TRUE, padapter->readCount);
if ( !padapter->sectorCount )
{
status = 0;
@@ -1326,32 +1937,40 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
}
}
else
+ {
+ if ( padapter->readCount )
+ WalkScatGath (padapter, TRUE, padapter->readCount);
BusMaster (padapter, 1, 1);
+ }
padapter->expectingIRQ = TRUE;
goto irq_return;
}
+ if ( padapter->readCount && !padapter->timingPIO )
+ WalkScatGath (padapter, TRUE, padapter->readCount);
status = 0;
break;
case WRITE_CMD:
- SelectSpigot (padapter, pdev->spigot | 0x80);
- status = inb_p (padapter->regStatCmd); // read the device status
if ( pdev->raid )
{
- SelectSpigot (padapter, (pdev->spigot ^ 3) | 0x80);
- status1 = inb_p (padapter->regStatCmd); // read the device status
+ SelectSpigot (padapter, pdev->spigots[0] | SEL_IRQ_OFF);
+ status = inb_p (padapter->regStatCmd); // read the device status
+ SelectSpigot (padapter, pdev->spigots[1] | SEL_IRQ_OFF);
+ status1 = inb_p (padapter->regStatCmd); // read the device status
}
else
+ SelectSpigot (padapter, pdev->spigot | SEL_IRQ_OFF);
+ status = inb_p (padapter->regStatCmd); // read the device status
status1 = 0;
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
if ( pdev->raid && !(status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT)) )
{
- padapter->survivor = (pdev->spigot ^ 3) >> 1;
+ padapter->survivor = 1;
del_timer (&padapter->timer);
- SelectSpigot (padapter, pdev->spigot | 0x80);
- DEB (printk ("\npci2220i: FAILURE 16 status = %X error = %X", status, inb_p (padapter->regError)));
+ SelectSpigot (padapter, pdev->spigot | SEL_IRQ_OFF);
+ DEB (printk ("\npci2220i: FAILURE 16 status = %X error = %X", status, inb_p (padapter->regError)));
if ( !InitFailover (padapter, pdev) )
goto irq_return;
}
@@ -1361,9 +1980,9 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
{
if ( status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
- padapter->survivor = pdev->spigot >> 1;
+ padapter->survivor = 0;
del_timer (&padapter->timer);
- DEB (printk ("\npci2220i: FAILURE 17 status = %X error = %X", status1, inb_p (padapter->regError)));
+ DEB (printk ("\npci2220i: FAILURE 17 status = %X error = %X", status1, inb_p (padapter->regError)));
if ( !InitFailover (padapter, pdev) )
goto irq_return;
status = status1;
@@ -1371,15 +1990,15 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
}
if ( padapter->sectorCount )
{
- status = WriteDataBoth (padapter);
+ status = WriteDataBoth (padapter, pdev);
if ( status )
{
- padapter->survivor = (status ^ 3) >> 1;
+ padapter->survivor = status >> 1;
del_timer (&padapter->timer);
- DEB (printk ("\npci2220i: FAILURE 18"));
+ DEB (printk ("\npci2220i: FAILURE 18"));
if ( !InitFailover (padapter, pdev) )
goto irq_return;
- SelectSpigot (padapter, status | 0x80);
+ SelectSpigot (padapter, pdev->spigots[status] | SEL_IRQ_OFF);
status = inb_p (padapter->regStatCmd); // read the device status
break;
}
@@ -1391,7 +2010,7 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
}
if ( padapter->sectorCount )
{
- SelectSpigot (padapter, pdev->spigot);
+ SelectSpigot (padapter, pdev->spigot | padapter->bigD);
status = WriteData (padapter);
if ( status )
break;
@@ -1458,12 +2077,20 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
OpDone (padapter, zl);
irq_return:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /*
+ * Restore the original flags which will enable interrupts
+ * if and only if they were enabled on entry.
+ */
+ restore_flags (flags);
+#else /* version >= v2.1.95 */
/*
* Release the I/O spinlock and restore the original flags
* which will enable interrupts if and only if they were
* enabled on entry.
*/
spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
}
/****************************************************************
* Name: Pci2220i_QueueCommand
@@ -1486,14 +2113,88 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
PDEVICE_RAID1 pdr;
SCpnt->scsi_done = done;
- padapter->buffer = SCpnt->request_buffer;
padapter->SCpnt = SCpnt; // Save this command data
+ padapter->readCount = 0;
+
+ if ( SCpnt->use_sg )
+ {
+ padapter->currentSgBuffer = ((struct scatterlist *)SCpnt->request_buffer)[0].address;
+ padapter->currentSgCount = ((struct scatterlist *)SCpnt->request_buffer)[0].length;
+ }
+ else
+ {
+ padapter->currentSgBuffer = SCpnt->request_buffer;
+ padapter->currentSgCount = SCpnt->request_bufflen;
+ }
+ padapter->nextSg = 1;
+
if ( !done )
{
printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb);
return 0;
}
+ if ( padapter->atapi )
+ {
+ UCHAR zlo, zhi;
+
+ DEB (printk ("\nPCI2242I: ID %d, LUN %d opcode %X ", SCpnt->target, SCpnt->lun, *cdb));
+ padapter->pdev = pdev;
+ if ( !pdev->byte6 || SCpnt->lun )
+ {
+ OpDone (padapter, DID_BAD_TARGET << 16);
+ return 0;
+ }
+
+ padapter->atapiSpecial = FALSE;
+ padapter->reqSense = FALSE;
+ memset (padapter->atapiCdb, 0, 16);
+ SelectSpigot (padapter, pdev->spigot); // select the spigot
+ AtapiDevice (padapter, pdev->byte6); // select the drive
+ if ( AtapiWaitReady (padapter, 100) )
+ {
+ OpDone (padapter, DID_NO_CONNECT << 16);
+ return 0;
+ }
+
+ switch ( cdb[0] )
+ {
+ case SCSIOP_MODE_SENSE:
+ case SCSIOP_MODE_SELECT:
+ Scsi2Atapi (padapter, SCpnt);
+ z = SCpnt->request_bufflen + 4;
+ break;
+ case SCSIOP_READ6:
+ case SCSIOP_WRITE6:
+ Scsi2Atapi (padapter, SCpnt);
+ z = SCpnt->request_bufflen;
+ break;
+ default:
+ memcpy (padapter->atapiCdb, cdb, SCpnt->cmd_len);
+ z = SCpnt->request_bufflen;
+ break;
+ }
+ if ( z > ATAPI_TRANSFER )
+ z = ATAPI_TRANSFER;
+ zlo = (UCHAR)(z & 0xFF);
+ zhi = (UCHAR)(z >> 8);
+
+ AtapiCountLo (padapter, zlo);
+ AtapiCountHi (padapter, zhi);
+ outb_p (0, padapter->regError);
+ WriteCommand (padapter, IDE_COMMAND_ATAPI_PACKET);
+ if ( pdev->cmdDrqInt )
+ return 0;
+
+ if ( AtapiWaitDrq (padapter, 500) )
+ {
+ OpDone (padapter, DID_ERROR << 16);
+ return 0;
+ }
+ AtapiSendCdb (padapter, pdev, padapter->atapiCdb);
+ return 0;
+ }
+
if ( padapter->reconPhase )
return 0;
if ( padapter->reconTimer.data )
@@ -1502,12 +2203,11 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
padapter->reconTimer.data = 0;
}
- if ( !pdev->device || SCpnt->lun )
+ if ( (SCpnt->target >= padapter->numberOfDrives) || SCpnt->lun )
{
OpDone (padapter, DID_BAD_TARGET << 16);
return 0;
}
-
switch ( *cdb )
{
@@ -1518,7 +2218,15 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
switch ( cdb[3] )
{
case MY_SCSI_REBUILD:
- padapter->reconOn = padapter->reconIsStarting = TRUE;
+ for ( z = 0; z < padapter->numberOfDrives; z++ )
+ {
+ pdev = &padapter->device[z];
+ if ( ((pdev->DiskMirror[0].status & UCBF_SURVIVOR) && (pdev->DiskMirror[1].status & UCBF_MIRRORED)) ||
+ ((pdev->DiskMirror[1].status & UCBF_SURVIVOR) && (pdev->DiskMirror[0].status & UCBF_MIRRORED)) )
+ {
+ padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+ }
+ }
OpDone (padapter, DID_OK << 16);
break;
case MY_SCSI_ALARMMUTE:
@@ -1535,7 +2243,10 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
if ( padapter->raidData[z] )
{
memcpy (&pdr->DiskRaid1, padapter->raidData[z], sizeof (DISK_MIRROR));
- pdr->TotalSectors = padapter->device[0].blocks;
+ if ( padapter->raidData[z]->reconstructPoint > padapter->raidData[z ^ 2]->reconstructPoint )
+ pdr->TotalSectors = padapter->raidData[z]->reconstructPoint;
+ else
+ pdr->TotalSectors = padapter->raidData[z ^ 2]->reconstructPoint;
}
else
memset (pdr, 0, sizeof (DEVICE_RAID1));
@@ -1598,6 +2309,7 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
while ( padapter->demoFail )
{
+ pdev = padapter->pdev = &padapter->device[0];
padapter->demoFail = FALSE;
if ( !pdev->raid ||
(pdev->DiskMirror[0].status & UCBF_SURVIVOR) ||
@@ -1610,7 +2322,7 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
else
padapter->survivor = 0;
DEB (printk ("\npci2220i: FAILURE 19"));
- if ( InitFailover (padapter, pdev ) )
+ if ( InitFailover (padapter, pdev) )
break;
return 0;
}
@@ -1618,14 +2330,14 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
StartTimer (padapter);
if ( pdev->raid && (padapter->cmd == WRITE_CMD) )
{
- rc = IdeCmdBoth (padapter);
+ rc = IdeCmdBoth (padapter, pdev);
if ( !rc )
- rc = WriteDataBoth (padapter);
+ rc = WriteDataBoth (padapter, pdev);
if ( rc )
{
del_timer (&padapter->timer);
padapter->expectingIRQ = 0;
- padapter->survivor = (rc ^ 3) >> 1;
+ padapter->survivor = rc >> 1;
DEB (printk ("\npci2220i: FAILURE 20"));
if ( InitFailover (padapter, pdev) )
{
@@ -1656,7 +2368,6 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
}
return 0;
}
-
static void internal_done(Scsi_Cmnd *SCpnt)
{
SCpnt->SCp.Status++;
@@ -1692,25 +2403,192 @@ int Pci2220i_Command (Scsi_Cmnd *SCpnt)
* Returns: Nothing.
*
****************************************************************/
-VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length)
+static VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length)
{
ULONG oldremap;
UCHAR olddesc;
ULONG z;
UCHAR *pd = (UCHAR *)pdata;
- oldremap = inl (padapter->regRemap); // save values to restore later
+ oldremap = inl (padapter->regRemap); // save values to restore later
olddesc = inb_p (padapter->regDesc);
- outl (base | 1, padapter->regRemap); // remap to Flash space as specified
- outb_p (0x40, padapter->regDesc); // describe remap region as 8 bit
- for ( z = 0; z < length; z++) // get "length" data count
- *pd++ = inb_p (padapter->regBase + z); // read in the data
+ outl (base | 1, padapter->regRemap); // remap to Flash space as specified
+ outb_p (0x40, padapter->regDesc); // describe remap region as 8 bit
+ for ( z = 0; z < length; z++) // get "length" data count
+ *pd++ = inb_p (padapter->regBase + z); // read in the data
- outl (oldremap, padapter->regRemap); // restore remap register values
+ outl (oldremap, padapter->regRemap); // restore remap register values
outb_p (olddesc, padapter->regDesc);
}
/****************************************************************
+ * Name: GetRegs
+ *
+ * Description: Initialize the regester information.
+ *
+ * Parameters: pshost - Pointer to SCSI host data structure.
+ * bigd - PCI-2240I identifier
+ * pcidev - Pointer to device data structure.
+ * pci_bus - PCI bus number.
+ * pci_device_fn - PCI device and function number.
+ *
+ * Returns: TRUE if failure to install.
+ *
+ ****************************************************************/
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, struct pci_dev *pcidev)
+#else
+static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, UCHAR pci_bus, UCHAR pci_device_fn)
+#endif
+ {
+ PADAPTER2220I padapter;
+ int setirq;
+ int z;
+ USHORT zr, zl;
+
+ padapter = HOSTDATA(pshost);
+ memset (padapter, 0, sizeof (ADAPTER2220I));
+ memset (&DaleSetup, 0, sizeof (DaleSetup));
+ memset (DiskMirror, 0, sizeof (DiskMirror));
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ zr = pcidev->base_address[1] & 0xFFFE;
+ zl = pcidev->base_address[2] & 0xFFFE;
+#else
+ pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &zr);
+ zr &= 0xFFFE;
+ pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &zl);
+ zl &= 0xFFFE;
+#endif
+ padapter->basePort = zr;
+ padapter->regRemap = zr + RTR_LOCAL_REMAP; // 32 bit local space remap
+ padapter->regDesc = zr + RTR_REGIONS; // 32 bit local region descriptor
+ padapter->regRange = zr + RTR_LOCAL_RANGE; // 32 bit local range
+ padapter->regIrqControl = zr + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status
+ padapter->regScratchPad = zr + RTR_MAILBOX; // 16 byte scratchpad I/O base address
+
+ padapter->regBase = zl;
+ padapter->regData = zl + REG_DATA; // data register I/O address
+ padapter->regError = zl + REG_ERROR; // error register I/O address
+ padapter->regSectCount = zl + REG_SECTOR_COUNT; // sector count register I/O address
+ padapter->regLba0 = zl + REG_LBA_0; // least significant byte of LBA
+ padapter->regLba8 = zl + REG_LBA_8; // next least significant byte of LBA
+ padapter->regLba16 = zl + REG_LBA_16; // next most significan byte of LBA
+ padapter->regLba24 = zl + REG_LBA_24; // head and most 4 significant bits of LBA
+ padapter->regStatCmd = zl + REG_STAT_CMD; // status on read and command on write register
+ padapter->regStatSel = zl + REG_STAT_SEL; // board status on read and spigot select on write register
+ padapter->regFail = zl + REG_FAIL;
+ padapter->regAltStat = zl + REG_ALT_STAT;
+
+ if ( bigd )
+ {
+ padapter->regDmaDesc = zr + RTR_DMA0_DESC_PTR; // address of the DMA discriptor register for direction of transfer
+ padapter->regDmaCmdStat = zr + RTR_DMA_COMMAND_STATUS; // Byte #0 of DMA command status register
+ padapter->regDmaAddrPci = zr + RTR_DMA0_PCI_ADDR; // 32 bit register for PCI address of DMA
+ padapter->regDmaAddrLoc = zr + RTR_DMA0_LOCAL_ADDR; // 32 bit register for local bus address of DMA
+ padapter->regDmaCount = zr + RTR_DMA0_COUNT; // 32 bit register for DMA transfer count
+ padapter->regDmaMode = zr + RTR_DMA0_MODE + 1; // 32 bit register for DMA mode control
+ padapter->bigD = SEL_NEW_SPEED_1; // set spigot speed control bit
+ }
+ else
+ {
+ padapter->regDmaDesc = zl + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer
+ padapter->regDmaCmdStat = zl + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register
+ padapter->regDmaAddrPci = zl + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA
+ padapter->regDmaAddrLoc = zl + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA
+ padapter->regDmaCount = zl + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count
+ padapter->regDmaMode = zl + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control
+ }
+
+ padapter->numberOfDrives = inb_p (padapter->regScratchPad + BIGD_NUM_DRIVES);
+ if ( !bigd && !padapter->numberOfDrives ) // if no devices on this board
+ return TRUE;
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ pshost->irq = pcidev->irq;
+#else
+ pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
+#endif
+ setirq = 1;
+ for ( z = 0; z < Installed; z++ ) // scan for shared interrupts
+ {
+ if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
+ setirq = 0;
+ }
+ if ( setirq ) // if not shared, posses
+ {
+ if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2220i", padapter) < 0 )
+ {
+ if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2220i", padapter) < 0 )
+ {
+ printk ("Unable to allocate IRQ for PCI-2220I controller.\n");
+ return TRUE;
+ }
+ }
+ padapter->irqOwned = pshost->irq; // set IRQ as owned
+ }
+ if ( padapter->numberOfDrives )
+ padapter->kBuffer = kmalloc (SECTORSXFER * BYTES_PER_SECTOR, GFP_DMA | GFP_ATOMIC);
+ else
+ padapter->kBuffer = kmalloc (ATAPI_TRANSFER, GFP_DMA | GFP_ATOMIC);
+ if ( !padapter->kBuffer )
+ {
+ printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n");
+#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
+ free_irq (pshost->irq);
+#else /* version >= v1.3.70 */
+ free_irq (pshost->irq, padapter);
+#endif /* version >= v1.3.70 */
+ return TRUE;
+ }
+
+ PsiHost[Installed] = pshost; // save SCSI_HOST pointer
+
+ pshost->io_port = padapter->basePort;
+ pshost->n_io_port = 0xFF;
+ pshost->unique_id = padapter->regBase;
+
+ outb_p (0x01, padapter->regRange); // fix our range register because other drivers want to tromp on it
+
+ padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE);
+ if ( padapter->timingMode >= 2 )
+ {
+ if ( bigd )
+ padapter->timingAddress = ModeArray2[padapter->timingMode - 2];
+ else
+ padapter->timingAddress = ModeArray[padapter->timingMode - 2];
+ }
+ else
+ padapter->timingPIO = TRUE;
+
+ ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP));
+ ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror));
+
+ return FALSE;
+ }
+/****************************************************************
+ * Name: SetupFinish
+ *
+ * Description: Complete the driver initialization process for a card
+ *
+ * Parameters: padapter - Pointer to SCSI host data structure.
+ * str - Pointer to board type string.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+VOID SetupFinish (PADAPTER2220I padapter, char *str, int irq)
+ {
+ init_timer (&padapter->timer);
+ padapter->timer.function = TimerExpiry;
+ padapter->timer.data = (unsigned long)padapter;
+ init_timer (&padapter->reconTimer);
+ padapter->reconTimer.function = ReconTimerExpiry;
+ padapter->reconTimer.data = (unsigned long)padapter;
+ printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", str, padapter->basePort, padapter->regBase, irq);
+ printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__);
+ }
+/****************************************************************
* Name: Pci2220i_Detect
*
* Description: Detect and initialize our boards.
@@ -1722,204 +2600,284 @@ VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length)
****************************************************************/
int Pci2220i_Detect (Scsi_Host_Template *tpnt)
{
- int found = 0;
- int installed = 0;
struct Scsi_Host *pshost;
PADAPTER2220I padapter;
+ POUR_DEVICE pdev;
int unit;
int z;
- USHORT zs;
- USHORT raidon = FALSE;
- int setirq;
- UCHAR spigot1 = FALSE;
- UCHAR spigot2 = FALSE;
- struct pci_dev *pdev = NULL;
+ USHORT raidon;
+ UCHAR spigot1, spigot2;
+ UCHAR device;
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ struct pci_dev *pcidev = NULL;
+#else
+ int found;
+ UCHAR pci_bus, pci_device_fn;
+#endif
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
if ( !pci_present () )
+#else
+ if ( !pcibios_present () )
+#endif
{
printk ("pci2220i: PCI BIOS not present\n");
return 0;
}
- while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pdev)) != NULL )
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pcidev)) != NULL )
+#else
+ found = 0;
+ while ( !pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, found++, &pci_bus, &pci_device_fn) )
+#endif
{
pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
padapter = HOSTDATA(pshost);
- memset (padapter, 0, sizeof (ADAPTER2220I));
-
- zs = pdev->resource[1].start;
- padapter->basePort = zs;
- padapter->regRemap = zs + RTR_LOCAL_REMAP; // 32 bit local space remap
- padapter->regDesc = zs + RTR_REGIONS; // 32 bit local region descriptor
- padapter->regRange = zs + RTR_LOCAL_RANGE; // 32 bit local range
- padapter->regIrqControl = zs + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status
- padapter->regScratchPad = zs + RTR_MAILBOX; // 16 byte scratchpad I/O base address
-
- zs = pdev->resource[2].start;
- padapter->regBase = zs;
- padapter->regData = zs + REG_DATA; // data register I/O address
- padapter->regError = zs + REG_ERROR; // error register I/O address
- padapter->regSectCount = zs + REG_SECTOR_COUNT; // sector count register I/O address
- padapter->regLba0 = zs + REG_LBA_0; // least significant byte of LBA
- padapter->regLba8 = zs + REG_LBA_8; // next least significant byte of LBA
- padapter->regLba16 = zs + REG_LBA_16; // next most significan byte of LBA
- padapter->regLba24 = zs + REG_LBA_24; // head and most 4 significant bits of LBA
- padapter->regStatCmd = zs + REG_STAT_CMD; // status on read and command on write register
- padapter->regStatSel = zs + REG_STAT_SEL; // board status on read and spigot select on write register
- padapter->regFail = zs + REG_FAIL;
- padapter->regAltStat = zs + REG_ALT_STAT;
-
- padapter->regDmaDesc = zs + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer
- padapter->regDmaCmdStat = zs + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register
- padapter->regDmaAddrPci = zs + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA
- padapter->regDmaAddrLoc = zs + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA
- padapter->regDmaCount = zs + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count
- padapter->regDmaMode = zs + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control
-
- if ( !inb_p (padapter->regScratchPad + DALE_NUM_DRIVES) ) // if no devices on this board
- goto unregister;
- pshost->irq = pdev->irq;
- setirq = 1;
- for ( z = 0; z < installed; z++ ) // scan for shared interrupts
- {
- if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
- setirq = 0;
- }
- if ( setirq ) // if not shared, posses
- {
- if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2220i", padapter) < 0 )
- {
- if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2220i", padapter) < 0 )
- {
- printk ("Unable to allocate IRQ for PCI-2220I controller.\n");
- goto unregister;
- }
- }
- padapter->irqOwned = pshost->irq; // set IRQ as owned
- }
- padapter->kBuffer = kmalloc (SECTORSXFER * BYTES_PER_SECTOR, GFP_DMA | GFP_ATOMIC);
- if ( !padapter->kBuffer )
- {
- printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n");
- free_irq (pshost->irq, padapter);
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ if ( GetRegs (pshost, FALSE, pcidev) )
+#else
+ if ( GetRegs (pshost, FALSE, pci_bus, pci_device_fn) )
+#endif
goto unregister;
- }
- PsiHost[installed] = pshost; // save SCSI_HOST pointer
-
- pshost->io_port = padapter->basePort;
- pshost->n_io_port = 0xFF;
- pshost->unique_id = padapter->regBase;
- pshost->max_id = 4;
-
- outb_p (0x01, padapter->regRange); // fix our range register because other drivers want to tromp on it
- padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE);
- if ( padapter->timingMode >= 2 )
- padapter->timingAddress = ModeArray[padapter->timingMode - 2];
- else
- padapter->timingPIO = TRUE;
-
- ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP));
- for ( z = 0; z < inb_p (padapter->regScratchPad + DALE_NUM_DRIVES); ++z )
+ pshost->max_id = padapter->numberOfDrives;
+ for ( z = 0; z < padapter->numberOfDrives; z++ )
{
unit = inb_p (padapter->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F;
- padapter->device[z].device = inb_p (padapter->regScratchPad + DALE_SCRATH_DEVICE_0 + unit);
- padapter->device[z].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0);
- padapter->device[z].spigot = (UCHAR)(1 << (unit >> 1));
- padapter->device[z].sectors = DaleSetup.setupDevice[unit].sectors;
- padapter->device[z].heads = DaleSetup.setupDevice[unit].heads;
- padapter->device[z].cylinders = DaleSetup.setupDevice[unit].cylinders;
- padapter->device[z].blocks = DaleSetup.setupDevice[unit].blocks;
+ pdev = &padapter->device[z];
+ pdev->byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0);
+ pdev->spigot = (UCHAR)(1 << (unit >> 1));
+ pdev->sectors = DaleSetup.setupDevice[unit].sectors;
+ pdev->heads = DaleSetup.setupDevice[unit].heads;
+ pdev->cylinders = DaleSetup.setupDevice[unit].cylinders;
+ pdev->blocks = DaleSetup.setupDevice[unit].blocks;
if ( !z )
{
- ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror));
DiskMirror[0].status = inb_p (padapter->regScratchPad + DALE_RAID_0_STATUS);
DiskMirror[1].status = inb_p (padapter->regScratchPad + DALE_RAID_1_STATUS);
if ( (DiskMirror[0].signature == SIGNATURE) && (DiskMirror[1].signature == SIGNATURE) &&
(DiskMirror[0].pairIdentifier == (DiskMirror[1].pairIdentifier ^ 1)) )
{
raidon = TRUE;
+ if ( unit > (unit ^ 2) )
+ unit = unit ^ 2;
}
+ else
+ raidon = FALSE;
- memcpy (padapter->device[z].DiskMirror, DiskMirror, sizeof (DiskMirror));
- padapter->raidData[0] = &padapter->device[z].DiskMirror[0];
- padapter->raidData[2] = &padapter->device[z].DiskMirror[1];
+ memcpy (pdev->DiskMirror, DiskMirror, sizeof (DiskMirror));
+ padapter->raidData[0] = &pdev->DiskMirror[0];
+ padapter->raidData[2] = &pdev->DiskMirror[1];
- if ( raidon )
- {
- padapter->device[z].lastsectorlba[0] = InlineIdentify (padapter, 1, 0);
- padapter->device[z].lastsectorlba[1] = InlineIdentify (padapter, 2, 0);
+ spigot1 = spigot2 = FALSE;
+ pdev->spigots[0] = 1;
+ pdev->spigots[1] = 2;
+ pdev->lastsectorlba[0] = InlineIdentify (padapter, 1, 0);
+ pdev->lastsectorlba[1] = InlineIdentify (padapter, 2, 0);
- if ( !(DiskMirror[1].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[0] )
- spigot1 = TRUE;
- if ( !(DiskMirror[0].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[1] )
- spigot2 = TRUE;
- if ( DiskMirror[0].status & UCBF_SURVIVOR & DiskMirror[1].status & UCBF_SURVIVOR )
- spigot1 = TRUE;
-
- if ( spigot1 && (DiskMirror[0].status & UCBF_REBUILD) )
- InlineReadSignature (padapter, &padapter->device[z], 0);
- if ( spigot2 && (DiskMirror[1].status & UCBF_REBUILD) )
- InlineReadSignature (padapter, &padapter->device[z], 1);
-
- if ( spigot1 && spigot2 )
+ if ( !(pdev->DiskMirror[1].status & UCBF_SURVIVOR) && pdev->lastsectorlba[0] )
+ spigot1 = TRUE;
+ if ( !(pdev->DiskMirror[0].status & UCBF_SURVIVOR) && pdev->lastsectorlba[1] )
+ spigot2 = TRUE;
+ if ( pdev->DiskMirror[0].status & DiskMirror[1].status & UCBF_SURVIVOR )
+ spigot1 = TRUE;
+
+ if ( spigot1 && (pdev->DiskMirror[0].status & UCBF_REBUILD) )
+ InlineReadSignature (padapter, pdev, 0);
+ if ( spigot2 && (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+ InlineReadSignature (padapter, pdev, 1);
+
+ if ( spigot1 && spigot2 && raidon )
+ {
+ pdev->raid = 1;
+ if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+ pdev->spigot = 2;
+ else
+ pdev->spigot = 1;
+ if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+ padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+ }
+ else
+ {
+ if ( spigot1 )
{
- padapter->device[z].raid = 1;
- if ( DiskMirror[0].status & UCBF_REBUILD )
- padapter->device[z].spigot = 2;
- else
- padapter->device[z].spigot = 1;
- if ( (DiskMirror[0].status & UCBF_REBUILD) || (DiskMirror[1].status & UCBF_REBUILD) )
- {
- padapter->reconOn = padapter->reconIsStarting = TRUE;
- }
+ if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+ goto unregister;
+ pdev->DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+ pdev->spigot = 1;
}
else
{
- if ( spigot1 )
- {
- if ( DiskMirror[0].status & UCBF_REBUILD )
- goto unregister;
- DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
- padapter->device[z].spigot = 1;
- }
- else
+ if ( pdev->DiskMirror[1].status & UCBF_REBUILD )
+ goto unregister;
+ pdev->DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+ pdev->spigot = 2;
+ }
+ if ( DaleSetup.rebootRebuild && raidon )
+ padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+ }
+
+ if ( raidon )
+ break;
+ }
+ }
+
+ SetupFinish (padapter, "2220", pshost->irq);
+
+ if ( ++Installed < MAXADAPTER )
+ continue;
+ break;;
+unregister:;
+ scsi_unregister (pshost);
+ }
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_BIGD_1, pcidev)) != NULL )
+#else
+ found = 0;
+ while ( !pcibios_find_device (VENDOR_PSI, DEVICE_BIGD_1, found++, &pci_bus, &pci_device_fn) )
+#endif
+ {
+ pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
+ padapter = HOSTDATA(pshost);
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ if ( GetRegs (pshost, TRUE, pcidev) )
+#else
+ if ( GetRegs (pshost, TRUE, pci_bus, pci_device_fn) )
+#endif
+ goto unregister1;
+
+ for ( z = 0; z < BIGD_MAXDRIVES; z++ )
+ DiskMirror[z].status = inb_p (padapter->regScratchPad + BIGD_RAID_0_STATUS + z);
+
+ pshost->max_id = padapter->numberOfDrives;
+ padapter->failRegister = inb_p (padapter->regScratchPad + BIGD_ALARM_IMAGE);
+ for ( z = 0; z < padapter->numberOfDrives; z++ )
+ {
+ unit = inb_p (padapter->regScratchPad + BIGD_DEVICE_0 + z);
+ pdev = &padapter->device[z];
+ pdev->byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0);
+ pdev->spigot = (UCHAR)(1 << (unit >> 1));
+ pdev->sectors = DaleSetup.setupDevice[unit].sectors;
+ pdev->heads = DaleSetup.setupDevice[unit].heads;
+ pdev->cylinders = DaleSetup.setupDevice[unit].cylinders;
+ pdev->blocks = DaleSetup.setupDevice[unit].blocks;
+
+ if ( (DiskMirror[unit].signature == SIGNATURE) && (DiskMirror[unit ^ 2].signature == SIGNATURE) &&
+ (DiskMirror[unit].pairIdentifier == (DiskMirror[unit ^ 2].pairIdentifier ^ 1)) )
+ {
+ raidon = TRUE;
+ if ( unit > (unit ^ 2) )
+ unit = unit ^ 2;
+ }
+ else
+ raidon = FALSE;
+
+ spigot1 = spigot2 = FALSE;
+ memcpy (&pdev->DiskMirror[0], &DiskMirror[unit], sizeof (DISK_MIRROR));
+ memcpy (&pdev->DiskMirror[1], &DiskMirror[unit ^ 2], sizeof (DISK_MIRROR));
+ padapter->raidData[unit] = &pdev->DiskMirror[0];
+ padapter->raidData[unit ^ 2] = &pdev->DiskMirror[1];
+ pdev->spigots[0] = 1 << (unit >> 1);
+ pdev->spigots[1] = 1 << ((unit ^ 2) >> 1);
+ pdev->deviceID[0] = unit;
+ pdev->deviceID[1] = unit ^ 2;
+ pdev->lastsectorlba[0] = InlineIdentify (padapter, pdev->spigots[0], unit & 1);
+ pdev->lastsectorlba[1] = InlineIdentify (padapter, pdev->spigots[1], unit & 1);
+
+ if ( !(pdev->DiskMirror[1].status & UCBF_SURVIVOR) && pdev->lastsectorlba[0] )
+ spigot1 = TRUE;
+ if ( !(pdev->DiskMirror[0].status & UCBF_SURVIVOR) && pdev->lastsectorlba[1] )
+ spigot2 = TRUE;
+ if ( pdev->DiskMirror[0].status & pdev->DiskMirror[1].status & UCBF_SURVIVOR )
+ spigot1 = TRUE;
+
+ if ( spigot1 && (pdev->DiskMirror[0].status & UCBF_REBUILD) )
+ InlineReadSignature (padapter, pdev, 0);
+ if ( spigot2 && (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+ InlineReadSignature (padapter, pdev, 1);
+
+ if ( spigot1 && spigot2 && raidon )
+ {
+ pdev->raid = 1;
+ if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+ pdev->spigot = pdev->spigots[1];
+ else
+ pdev->spigot = pdev->spigots[0];
+ if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+ padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+ }
+ else
+ {
+ if ( spigot1 )
+ {
+ if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+ goto unregister1;
+ pdev->DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+ pdev->spigot = pdev->spigots[0];
+ }
+ else
+ {
+ if ( pdev->DiskMirror[1].status & UCBF_REBUILD )
+ goto unregister;
+ pdev->DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+ pdev->spigot = pdev->spigots[1];
+ }
+ if ( DaleSetup.rebootRebuild && raidon )
+ padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+ }
+ }
+
+ if ( !padapter->numberOfDrives ) // If no ATA devices then scan ATAPI
+ {
+ unit = 0;
+ for ( spigot1 = 0; spigot1 < 4; spigot1++ )
+ {
+ for ( device = 0; device < 2; device++ )
+ {
+ DEB (printk ("\nPCI2242I: scanning for ID %d ", (spigot1 * 2) + device));
+ pdev = &(padapter->device[(spigot1 * 2) + device]);
+ pdev->byte6 = 0x0A | (device << 4);
+ pdev->spigot = 1 << spigot1;
+ if ( !AtapiReset (padapter, pdev) )
+ {
+ DEB (printk (" Device found "));
+ if ( !AtapiIdentify (padapter, pdev) )
{
- if ( DiskMirror[1].status & UCBF_REBUILD )
- goto unregister;
- DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
- padapter->device[z].spigot = 2;
+ DEB (printk (" Device verified"));
+ unit++;
+ continue;
}
- if ( DaleSetup.rebootRebuil )
- padapter->reconOn = padapter->reconIsStarting = TRUE;
}
-
- break;
+ pdev->spigot = pdev->byte6 = 0;
}
}
+
+ if ( unit )
+ {
+ padapter->atapi = TRUE;
+ padapter->timingAddress = DALE_DATA_MODE3;
+ outw_p (0x0900, padapter->regIrqControl); // Turn our interrupts on
+ outw_p (0x0C41, padapter->regDmaMode - 1); // setup for 16 bits, ready enabled, done IRQ enabled, no incriment
+ outb_p (0xFF, padapter->regFail); // all fail lights and alarm off
+ pshost->max_id = 8;
+ }
}
-
- init_timer (&padapter->timer);
- padapter->timer.function = TimerExpiry;
- padapter->timer.data = (unsigned long)padapter;
- init_timer (&padapter->reconTimer);
- padapter->reconTimer.function = ReconTimerExpiry;
- padapter->reconTimer.data = (unsigned long)padapter;
- printk("\nPCI-2220I EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", padapter->basePort, padapter->regBase, pshost->irq);
- printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__);
- found++;
- if ( ++installed < MAXADAPTER )
+ SetupFinish (padapter, "2240", pshost->irq);
+
+ if ( ++Installed < MAXADAPTER )
continue;
break;;
-unregister:;
+unregister1:;
scsi_unregister (pshost);
- found++;
}
-
- NumAdapters = installed;
- return installed;
+
+ NumAdapters = Installed;
+ return Installed;
}
/****************************************************************
* Name: Pci2220i_Abort
@@ -1933,6 +2891,19 @@ unregister:;
****************************************************************/
int Pci2220i_Abort (Scsi_Cmnd *SCpnt)
{
+ PADAPTER2220I padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure
+ POUR_DEVICE pdev = &padapter->device[SCpnt->target];// Pointer to device information
+
+ if ( !padapter->SCpnt )
+ return SCSI_ABORT_NOT_RUNNING;
+
+ if ( padapter->atapi )
+ {
+ if ( AtapiReset (padapter, pdev) )
+ return SCSI_ABORT_ERROR;
+ OpDone (padapter, DID_ABORT << 16);
+ return SCSI_ABORT_SUCCESS;
+ }
return SCSI_ABORT_SNOOZE;
}
/****************************************************************
@@ -1952,6 +2923,15 @@ int Pci2220i_Abort (Scsi_Cmnd *SCpnt)
****************************************************************/
int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
{
+ PADAPTER2220I padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure
+ POUR_DEVICE pdev = &padapter->device[SCpnt->target];// Pointer to device information
+
+ if ( padapter->atapi )
+ {
+ if ( AtapiReset (padapter, pdev) )
+ return SCSI_RESET_ERROR;
+ return SCSI_RESET_SUCCESS;
+ }
return SCSI_RESET_PUNT;
}
/****************************************************************
@@ -1967,6 +2947,7 @@ int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
int Pci2220i_Release (struct Scsi_Host *pshost)
{
PADAPTER2220I padapter = HOSTDATA (pshost);
+ USHORT z;
if ( padapter->reconOn )
{
@@ -1981,11 +2962,29 @@ int Pci2220i_Release (struct Scsi_Host *pshost)
}
// save RAID status on the board
- outb_p (DiskMirror[0].status, padapter->regScratchPad + DALE_RAID_0_STATUS);
- outb_p (DiskMirror[1].status, padapter->regScratchPad + DALE_RAID_1_STATUS);
+ if ( padapter->bigD )
+ {
+ outb_p (padapter->failRegister, padapter->regScratchPad + BIGD_ALARM_IMAGE);
+ for ( z = 0; z < BIGD_MAXDRIVES; z++ )
+ {
+ if ( padapter->raidData )
+ outb_p (padapter->raidData[z]->status, padapter->regScratchPad + BIGD_RAID_0_STATUS + z);
+ else
+ outb_p (0, padapter->regScratchPad + BIGD_RAID_0_STATUS);
+ }
+ }
+ else
+ {
+ outb_p (padapter->device[0].DiskMirror[0].status, padapter->regScratchPad + DALE_RAID_0_STATUS);
+ outb_p (padapter->device[0].DiskMirror[1].status, padapter->regScratchPad + DALE_RAID_1_STATUS);
+ }
if ( padapter->irqOwned )
+#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
+ free_irq (pshost->irq);
+#else /* version >= v1.3.70 */
free_irq (pshost->irq, padapter);
+#endif /* version >= v1.3.70 */
release_region (pshost->io_port, pshost->n_io_port);
kfree (padapter->kBuffer);
scsi_unregister(pshost);
@@ -2011,11 +3010,14 @@ int Pci2220i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
{
POUR_DEVICE pdev;
- pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]);
+ if ( !(HOSTDATA(disk->device->host))->atapi )
+ {
+ pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]);
- geom[0] = pdev->heads;
- geom[1] = pdev->sectors;
- geom[2] = pdev->cylinders;
+ geom[0] = pdev->heads;
+ geom[1] = pdev->sectors;
+ geom[2] = pdev->cylinders;
+ }
return 0;
}
diff --git a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h
index 1c75c8c3b..aaa8457fc 100644
--- a/drivers/scsi/pci2220i.h
+++ b/drivers/scsi/pci2220i.h
@@ -21,265 +21,11 @@
#ifndef _PCI2220I_H
#define _PCI2220I_H
-#ifndef PSI_EIDE_SCSIOP
-#define PSI_EIDE_SCSIOP 1
-
#ifndef LINUX_VERSION_CODE
#include <linux/version.h>
#endif
#define LINUXVERSION(v,p,s) (((v)<<16) + ((p)<<8) + (s))
-/************************************************/
-/* Some defines that we like */
-/************************************************/
-#define CHAR char
-#define UCHAR unsigned char
-#define SHORT short
-#define USHORT unsigned short
-#define BOOL unsigned short
-#define LONG long
-#define ULONG unsigned long
-#define VOID void
-
-#include "psi_dale.h"
-
-/************************************************/
-/* Timeout konstants */
-/************************************************/
-#define TIMEOUT_READY 100 // 100 mSec
-#define TIMEOUT_DRQ 300 // 300 mSec
-#define TIMEOUT_DATA (3 * HZ) // 3 seconds
-
-/************************************************/
-/* Misc. macros */
-/************************************************/
-#define ANY2SCSI(up, p) \
-((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \
-((UCHAR *)up)[1] = ((ULONG)(p));
-
-#define SCSI2LONG(up) \
-( (((long)*(((UCHAR *)up))) << 16) \
-+ (((long)(((UCHAR *)up)[1])) << 8) \
-+ ((long)(((UCHAR *)up)[2])) )
-
-#define XANY2SCSI(up, p) \
-((UCHAR *)up)[0] = ((long)(p)) >> 24; \
-((UCHAR *)up)[1] = ((long)(p)) >> 16; \
-((UCHAR *)up)[2] = ((long)(p)) >> 8; \
-((UCHAR *)up)[3] = ((long)(p));
-
-#define XSCSI2LONG(up) \
-( (((long)(((UCHAR *)up)[0])) << 24) \
-+ (((long)(((UCHAR *)up)[1])) << 16) \
-+ (((long)(((UCHAR *)up)[2])) << 8) \
-+ ((long)(((UCHAR *)up)[3])) )
-
-#define SelectSpigot(padapter,spigot) outb_p (spigot, padapter->regStatSel)
-#define WriteCommand(padapter,cmd) outb_p (cmd, padapter->regStatCmd)
-
-/************************************************/
-/* SCSI CDB operation codes */
-/************************************************/
-#define SCSIOP_TEST_UNIT_READY 0x00
-#define SCSIOP_REZERO_UNIT 0x01
-#define SCSIOP_REWIND 0x01
-#define SCSIOP_REQUEST_BLOCK_ADDR 0x02
-#define SCSIOP_REQUEST_SENSE 0x03
-#define SCSIOP_FORMAT_UNIT 0x04
-#define SCSIOP_READ_BLOCK_LIMITS 0x05
-#define SCSIOP_REASSIGN_BLOCKS 0x07
-#define SCSIOP_READ6 0x08
-#define SCSIOP_RECEIVE 0x08
-#define SCSIOP_WRITE6 0x0A
-#define SCSIOP_PRINT 0x0A
-#define SCSIOP_SEND 0x0A
-#define SCSIOP_SEEK6 0x0B
-#define SCSIOP_TRACK_SELECT 0x0B
-#define SCSIOP_SLEW_PRINT 0x0B
-#define SCSIOP_SEEK_BLOCK 0x0C
-#define SCSIOP_PARTITION 0x0D
-#define SCSIOP_READ_REVERSE 0x0F
-#define SCSIOP_WRITE_FILEMARKS 0x10
-#define SCSIOP_FLUSH_BUFFER 0x10
-#define SCSIOP_SPACE 0x11
-#define SCSIOP_INQUIRY 0x12
-#define SCSIOP_VERIFY6 0x13
-#define SCSIOP_RECOVER_BUF_DATA 0x14
-#define SCSIOP_MODE_SELECT 0x15
-#define SCSIOP_RESERVE_UNIT 0x16
-#define SCSIOP_RELEASE_UNIT 0x17
-#define SCSIOP_COPY 0x18
-#define SCSIOP_ERASE 0x19
-#define SCSIOP_MODE_SENSE 0x1A
-#define SCSIOP_START_STOP_UNIT 0x1B
-#define SCSIOP_STOP_PRINT 0x1B
-#define SCSIOP_LOAD_UNLOAD 0x1B
-#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C
-#define SCSIOP_SEND_DIAGNOSTIC 0x1D
-#define SCSIOP_MEDIUM_REMOVAL 0x1E
-#define SCSIOP_READ_CAPACITY 0x25
-#define SCSIOP_READ 0x28
-#define SCSIOP_WRITE 0x2A
-#define SCSIOP_SEEK 0x2B
-#define SCSIOP_LOCATE 0x2B
-#define SCSIOP_WRITE_VERIFY 0x2E
-#define SCSIOP_VERIFY 0x2F
-#define SCSIOP_SEARCH_DATA_HIGH 0x30
-#define SCSIOP_SEARCH_DATA_EQUAL 0x31
-#define SCSIOP_SEARCH_DATA_LOW 0x32
-#define SCSIOP_SET_LIMITS 0x33
-#define SCSIOP_READ_POSITION 0x34
-#define SCSIOP_SYNCHRONIZE_CACHE 0x35
-#define SCSIOP_COMPARE 0x39
-#define SCSIOP_COPY_COMPARE 0x3A
-#define SCSIOP_WRITE_DATA_BUFF 0x3B
-#define SCSIOP_READ_DATA_BUFF 0x3C
-#define SCSIOP_CHANGE_DEFINITION 0x40
-#define SCSIOP_READ_SUB_CHANNEL 0x42
-#define SCSIOP_READ_TOC 0x43
-#define SCSIOP_READ_HEADER 0x44
-#define SCSIOP_PLAY_AUDIO 0x45
-#define SCSIOP_PLAY_AUDIO_MSF 0x47
-#define SCSIOP_PLAY_TRACK_INDEX 0x48
-#define SCSIOP_PLAY_TRACK_RELATIVE 0x49
-#define SCSIOP_PAUSE_RESUME 0x4B
-#define SCSIOP_LOG_SELECT 0x4C
-#define SCSIOP_LOG_SENSE 0x4D
-#define SCSIOP_MODE_SELECT10 0x55
-#define SCSIOP_MODE_SENSE10 0x5A
-#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6
-#define SCSIOP_MECHANISM_STATUS 0xBD
-#define SCSIOP_READ_CD 0xBE
-
-// IDE command definitions
-#define IDE_COMMAND_ATAPI_RESET 0x08
-#define IDE_COMMAND_READ 0x20
-#define IDE_COMMAND_WRITE 0x30
-#define IDE_COMMAND_RECALIBRATE 0x10
-#define IDE_COMMAND_SEEK 0x70
-#define IDE_COMMAND_SET_PARAMETERS 0x91
-#define IDE_COMMAND_VERIFY 0x40
-#define IDE_COMMAND_ATAPI_PACKET 0xA0
-#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1
-#define IDE_CMD_READ_MULTIPLE 0xC4
-#define IDE_CMD_WRITE_MULTIPLE 0xC5
-#define IDE_CMD_SET_MULTIPLE 0xC6
-#define IDE_COMMAND_IDENTIFY 0xEC
-
-// IDE status definitions
-#define IDE_STATUS_ERROR 0x01
-#define IDE_STATUS_INDEX 0x02
-#define IDE_STATUS_CORRECTED_ERROR 0x04
-#define IDE_STATUS_DRQ 0x08
-#define IDE_STATUS_DSC 0x10
-#define IDE_STATUS_WRITE_FAULT 0x20
-#define IDE_STATUS_DRDY 0x40
-#define IDE_STATUS_BUSY 0x80
-
-// IDE error definitions
-#define IDE_ERROR_AMNF 0x01
-#define IDE_ERROR_TKONF 0x02
-#define IDE_ERROR_ABRT 0x04
-#define IDE_ERROR_MCR 0x08
-#define IDE_ERROR_IDFN 0x10
-#define IDE_ERROR_MC 0x20
-#define IDE_ERROR_UNC 0x40
-#define IDE_ERROR_BBK 0x80
-
-// SCSI read capacity structure
-typedef struct _READ_CAPACITY_DATA
- {
- ULONG blks; /* total blocks (converted to little endian) */
- ULONG blksiz; /* size of each (converted to little endian) */
- } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
-
-// SCSI inquiry data
-typedef struct _INQUIRYDATA
- {
- UCHAR DeviceType :5;
- UCHAR DeviceTypeQualifier :3;
- UCHAR DeviceTypeModifier :7;
- UCHAR RemovableMedia :1;
- UCHAR Versions;
- UCHAR ResponseDataFormat;
- UCHAR AdditionalLength;
- UCHAR Reserved[2];
- UCHAR SoftReset :1;
- UCHAR CommandQueue :1;
- UCHAR Reserved2 :1;
- UCHAR LinkedCommands :1;
- UCHAR Synchronous :1;
- UCHAR Wide16Bit :1;
- UCHAR Wide32Bit :1;
- UCHAR RelativeAddressing :1;
- UCHAR VendorId[8];
- UCHAR ProductId[16];
- UCHAR ProductRevisionLevel[4];
- UCHAR VendorSpecific[20];
- UCHAR Reserved3[40];
- } INQUIRYDATA, *PINQUIRYDATA;
-
-// IDE IDENTIFY data
-#pragma pack (1)
-#pragma align 1
-typedef struct _IDENTIFY_DATA
- {
- USHORT GeneralConfiguration; // 0
- USHORT NumberOfCylinders; // 1
- USHORT Reserved1; // 2
- USHORT NumberOfHeads; // 3
- USHORT UnformattedBytesPerTrack; // 4
- USHORT UnformattedBytesPerSector; // 5
- USHORT SectorsPerTrack; // 6
- USHORT NumBytesISG; // 7 Byte Len - inter-sector gap
- USHORT NumBytesSync; // 8 - sync field
- USHORT NumWordsVUS; // 9 Len - Vendor Unique Info
- USHORT SerialNumber[10]; // 10
- USHORT BufferType; // 20
- USHORT BufferSectorSize; // 21
- USHORT NumberOfEccBytes; // 22
- USHORT FirmwareRevision[4]; // 23
- USHORT ModelNumber[20]; // 27
- USHORT NumSectorsPerInt :8; // 47 Multiple Mode - Sec/Blk
- USHORT Reserved2 :8; // 47
- USHORT DoubleWordMode; // 48 flag for double word mode capable
- USHORT VendorUnique1 :8; // 49
- USHORT SupportDMA :1; // 49 DMA supported
- USHORT SupportLBA :1; // 49 LBA supported
- USHORT SupportIORDYDisable :1; // 49 IORDY can be disabled
- USHORT SupportIORDY :1; // 49 IORDY supported
- USHORT ReservedPseudoDMA :1; // 49 reserved for pseudo DMA mode support
- USHORT Reserved3 :3; // 49
- USHORT Reserved4; // 50
- USHORT Reserved5 :8; // 51 Transfer Cycle Timing - PIO
- USHORT PIOCycleTime :8; // 51 Transfer Cycle Timing - PIO
- USHORT Reserved6 :8; // 52 - DMA
- USHORT DMACycleTime :8; // 52 - DMA
- USHORT Valid_54_58 :1; // 53 words 54 - 58 are vaild
- USHORT Valid_64_70 :1; // 53 words 64 - 70 are valid
- USHORT Reserved7 :14; // 53
- USHORT LogNumCyl; // 54 Current Translation - Num Cyl
- USHORT LogNumHeads; // 55 Num Heads
- USHORT LogSectorsPerTrack; // 56 Sec/Trk
- ULONG LogTotalSectors; // 57 Total Sec
- USHORT CurrentNumSecPerInt :8; // 59 current setting for number of sectors per interrupt
- USHORT ValidNumSecPerInt :1; // 59 Current setting is valid for number of sectors per interrupt
- USHORT Reserved8 :7; // 59
- ULONG LBATotalSectors; // 60 LBA Mode - Sectors
- USHORT DMASWordFlags; // 62
- USHORT DMAMWordFlags; // 63
- USHORT AdvancedPIOSupport :8; // 64 Flow control PIO transfer modes supported
- USHORT Reserved9 :8; // 64
- USHORT MinMultiDMACycle; // 65 minimum multiword DMA transfer cycle time per word
- USHORT RecomendDMACycle; // 66 Manufacturer's recommende multiword DMA transfer cycle time
- USHORT MinPIOCycleWithoutFlow; // 67 Minimum PIO transfer cycle time without flow control
- USHORT MinPIOCylceWithFlow; // 68 Minimum PIO transfer cycle time with IORDY flow control
- USHORT ReservedSpace[256-69]; // 69
- } IDENTIFY_DATA, *PIDENTIFY_DATA;
-#pragma pack ()
-#pragma align 0
-#endif // PSI_EIDE_SCSIOP
-
// function prototypes
int Pci2220i_Detect (Scsi_Host_Template *tpnt);
int Pci2220i_Command (Scsi_Cmnd *SCpnt);
@@ -293,12 +39,15 @@ int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]);
#define NULL 0
#endif
+extern struct proc_dir_entry Proc_Scsi_Pci2220i;
+
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75)
#define PCI2220I { \
next: NULL, \
module: NULL, \
- proc_name: "pci2220i", \
+ proc_dir: &Proc_Scsi_Pci2220i, \
proc_info: NULL, /* let's not bloat the kernel */\
- name: "PCI-2220I EIDE Disk Controller", \
+ name: "PCI-2220I/PCI-2240I", \
detect: Pci2220i_Detect, \
release: Pci2220i_Release, \
info: NULL, /* let's not bloat the kernel */\
@@ -315,11 +64,34 @@ int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]);
bios_param: Pci2220i_BiosParam, \
can_queue: 1, \
this_id: -1, \
- sg_tablesize: SG_NONE, \
+ sg_tablesize: SG_ALL, \
cmd_per_lun: 1, \
present: 0, \
unchecked_isa_dma: 0, \
use_clustering: DISABLE_CLUSTERING, \
use_new_eh_code: 0 \
}
+#else
+#define PCI2220I { NULL, NULL, \
+ &Proc_Scsi_Pci2220i,/* proc_dir_entry */\
+ NULL, \
+ "PCI-2220I/PCI-2240I", \
+ Pci2220i_Detect, \
+ Pci2220i_Release, \
+ NULL, \
+ Pci2220i_Command, \
+ Pci2220i_QueueCommand, \
+ Pci2220i_Abort, \
+ Pci2220i_Reset, \
+ NULL, \
+ Pci2220i_BiosParam, \
+ 1, \
+ -1, \
+ SG_ALL, \
+ 1, \
+ 0, \
+ 0, \
+ DISABLE_CLUSTERING }
+#endif
+
#endif
diff --git a/drivers/scsi/pcmcia/.cvsignore b/drivers/scsi/pcmcia/.cvsignore
new file mode 100644
index 000000000..f7cf9ab27
--- /dev/null
+++ b/drivers/scsi/pcmcia/.cvsignore
@@ -0,0 +1,10 @@
+! RCS SCCS CVS CVS.adm
+RCSLOG cvslog.*
+tags TAGS
+.make.state .nse_depinfo
+*~ #* .#* ,* _$* *$
+*.old *.bak *.BAK *.orig *.rej .del-*
+*.a *.olb *.o *.obj *.so *.exe
+*.Z *.elc *.ln
+.depend
+.*.flags
diff --git a/drivers/scsi/pcmcia/Config.in b/drivers/scsi/pcmcia/Config.in
new file mode 100644
index 000000000..5416bdef2
--- /dev/null
+++ b/drivers/scsi/pcmcia/Config.in
@@ -0,0 +1,23 @@
+#
+# PCMCIA SCSI adapter configuration
+#
+
+mainmenu_option next_comment
+comment 'PCMCIA SCSI adapter support'
+
+bool 'PCMCIA SCSI adapter support' CONFIG_SCSI_PCMCIA
+if [ "$CONFIG_SCSI_PCMCIA" = "y" ]; then
+ dep_tristate ' Adaptec AHA152X PCMCIA support' CONFIG_PCMCIA_AHA152X m
+ dep_tristate ' Qlogic PCMCIA support' CONFIG_PCMCIA_QLOGIC m
+ dep_tristate ' Future Domain PCMCIA support' CONFIG_PCMCIA_FDOMAIN m
+ if [ "$CONFIG_CARDBUS" = "y" ]; then
+ dep_tristate ' Adaptec APA1480 CardBus support' CONFIG_PCMCIA_APA1480 m
+ fi
+fi
+
+if [ "$CONFIG_PCMCIA_QLOGIC" = "y" -o "$CONFIG_PCMCIA_AHA152X" = "y" -o \
+ "$CONFIG_PCMCIA_FDOMAIN" = "y" -o "$CONFIG_PCMCIA_APA1480" = "y" ]; then
+ define_bool CONFIG_PCMCIA_SCSICARD y
+fi
+
+endmenu
diff --git a/drivers/scsi/pcmcia/Makefile b/drivers/scsi/pcmcia/Makefile
new file mode 100644
index 000000000..d37c6fc5f
--- /dev/null
+++ b/drivers/scsi/pcmcia/Makefile
@@ -0,0 +1,67 @@
+#
+# drivers/scsi/pcmcia/Makefile
+#
+# Makefile for the Linux PCMCIA SCSI drivers.
+#
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+MOD_LIST_NAME := PCMCIA_SCSI_MODULES
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+vpath %c ..
+
+CFLAGS_aha152x.o = -DPCMCIA -D__NO_VERSION__ -DAHA152X_STAT
+CFLAGS_aic7xxx.o = -DPCMCIA -D__NO_VERSION__
+CFLAGS_fdomain.o = -DPCMCIA -D__NO_VERSION__
+CFLAGS_qlogicfas.o = -DPCMCIA -D__NO_VERSION__
+
+# 16-bit client drivers
+obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o
+obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o
+obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o
+
+# Cardbus client drivers
+obj-$(CONFIG_PCMCIA_APA1480) += apa1480_cb.o
+
+list-multi := qlogic_cs.o fdomain_cs.o aha152x_cs.o apa1480_cb.o
+aha152x-objs := aha152x_stub.o aha152x.o
+apa1480-objs := apa1480_stub.o aic7xxx.o
+fdomain-objs := fdomain_stub.o fdomain.o
+qlogic-objs := qlogic_stub.o qlogicfas.o
+
+# Extract lists of the multi-part drivers.
+
+multi-y := $(filter $(list-multi), $(obj-y))
+multi-m := $(filter $(list-multi), $(obj-m))
+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Translate to Rules.make lists.
+
+O_OBJS := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS := $(filter $(export-objs), $(obj-y))
+M_OBJS := $(filter-out $(export-objs), $(obj-m))
+MX_OBJS := $(filter $(export-objs), $(obj-m))
+MI_OBJS := $(filter-out $(export-objs), $(int-m))
+MIX_OBJS := $(filter $(export-objs), $(int-m))
+
+include $(TOPDIR)/Rules.make
+
+aha152x_cs.o: $(aha152x-objs)
+ $(LD) -r -o $@ $(aha152x-objs)
+
+apa1480_cb.o: $(apa1480-objs)
+ $(LD) -r -o $@ $(apa1480-objs)
+
+fdomain_cs.o: $(fdomain-objs)
+ $(LD) -r -o $@ $(fdomain-objs)
+
+qlogic_cs.o: $(qlogic-objs)
+ $(LD) -r -o $@ $(qlogic-objs)
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
new file mode 100644
index 000000000..7450470a1
--- /dev/null
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -0,0 +1,437 @@
+/*======================================================================
+
+ A driver for Adaptec AHA152X-compatible PCMCIA SCSI cards.
+
+ This driver supports the Adaptec AHA-1460, the New Media Bus
+ Toaster, and the New Media Toast & Jam.
+
+ aha152x_cs.c 1.52 2000/01/11 01:04:31
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+#include <../drivers/scsi/aha152x.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"aha152x_cs.c 1.52 2000/01/11 01:04:31 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* SCSI bus setup options */
+static int host_id = 7;
+static int reconnect = 1;
+static int parity = 1;
+static int synchronous = 0;
+static int reset_delay = 100;
+static int ext_trans = 0;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(host_id, "i");
+MODULE_PARM(reconnect, "i");
+MODULE_PARM(parity, "i");
+MODULE_PARM(synchronous, "i");
+MODULE_PARM(reset_delay, "i");
+MODULE_PARM(ext_trans, "i");
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+ dev_link_t link;
+ struct Scsi_Host *host;
+ int ndev;
+ dev_node_t node[8];
+} scsi_info_t;
+
+extern void aha152x_setup(char *str, int *ints);
+
+static void aha152x_release_cs(u_long arg);
+static int aha152x_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+static dev_link_t *aha152x_attach(void);
+static void aha152x_detach(dev_link_t *);
+
+static Scsi_Host_Template driver_template = AHA152X;
+
+static dev_link_t *dev_list = NULL;
+
+static dev_info_t dev_info = "aha152x_cs";
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static dev_link_t *aha152x_attach(void)
+{
+ scsi_info_t *info;
+ client_reg_t client_reg;
+ dev_link_t *link;
+ int i, ret;
+
+ DEBUG(0, "aha152x_attach()\n");
+
+ /* Create new SCSI device */
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) return NULL;
+ memset(info, 0, sizeof(*info));
+ link = &info->link; link->priv = info;
+ link->release.function = &aha152x_release_cs;
+ link->release.data = (u_long)link;
+
+ link->io.NumPorts1 = 0x20;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->io.IOAddrLines = 10;
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+ if (irq_list[0] == -1)
+ link->irq.IRQInfo2 = irq_mask;
+ else
+ for (i = 0; i < 4; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.Present = PRESENT_OPTION;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.event_handler = &aha152x_event;
+ client_reg.EventMask =
+ CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ aha152x_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* aha152x_attach */
+
+/*====================================================================*/
+
+static void aha152x_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+
+ DEBUG(0, "aha152x_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ if (link->state & DEV_CONFIG) {
+ aha152x_release_cs((u_long)link);
+ if (link->state & DEV_STALE_CONFIG) {
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+ }
+
+ if (link->handle)
+ CardServices(DeregisterClient, link->handle);
+
+ /* Unlink device structure, free bits */
+ *linkp = link->next;
+ kfree(link->priv);
+
+} /* aha152x_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void aha152x_config_cs(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ scsi_info_t *info = link->priv;
+ tuple_t tuple;
+ cisparse_t parse;
+ int i, last_ret, last_fn, ints[8];
+ u_char tuple_data[64];
+ Scsi_Device *dev;
+ dev_node_t *node, **tail;
+ struct Scsi_Host *host;
+
+ DEBUG(0, "aha152x_config(0x%p)\n", link);
+
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.TupleData = tuple_data;
+ tuple.TupleDataMax = 64;
+ tuple.TupleOffset = 0;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ CS_CHECK(GetTupleData, handle, &tuple);
+ CS_CHECK(ParseTuple, handle, &tuple, &parse);
+ link->conf.ConfigBase = parse.config.base;
+
+ /* Configure card */
+ driver_template.module = &__this_module;
+ link->state |= DEV_CONFIG;
+
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ while (1) {
+ CFG_CHECK(GetTupleData, handle, &tuple);
+ CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+ /* For New Media T&J, look for a SCSI window */
+ if (parse.cftable_entry.io.win[0].len >= 0x20)
+ link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+ else if ((parse.cftable_entry.io.nwin > 1) &&
+ (parse.cftable_entry.io.win[1].len >= 0x20))
+ link->io.BasePort1 = parse.cftable_entry.io.win[1].base;
+ if ((parse.cftable_entry.io.nwin > 0) &&
+ (link->io.BasePort1 < 0xffff)) {
+ link->conf.ConfigIndex = parse.cftable_entry.index;
+ i = CardServices(RequestIO, handle, &link->io);
+ if (i == CS_SUCCESS) break;
+ }
+ next_entry:
+ CS_CHECK(GetNextTuple, handle, &tuple);
+ }
+
+ CS_CHECK(RequestIRQ, handle, &link->irq);
+ CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+ /* A bad hack... */
+ release_region(link->io.BasePort1, link->io.NumPorts1);
+
+ /* Set configuration options for the aha152x driver */
+ ints[0] = 7;
+ ints[1] = link->io.BasePort1;
+ ints[2] = link->irq.AssignedIRQ;
+ ints[3] = host_id;
+ ints[4] = reconnect;
+ ints[5] = parity;
+ ints[6] = synchronous;
+ ints[7] = reset_delay;
+ if (ext_trans) {
+ ints[8] = ext_trans; ints[0] = 8;
+ }
+ aha152x_setup("PCMCIA setup", ints);
+
+ scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+ tail = &link->dev;
+ info->ndev = 0;
+ for (host = scsi_hostlist; host; host = host->next)
+ if (host->hostt == &driver_template)
+ for (dev = host->host_queue; dev; dev = dev->next) {
+ u_long arg[2], id;
+ kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+ id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+ ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+ node = &info->node[info->ndev];
+ node->minor = 0;
+ switch (dev->type) {
+ case TYPE_TAPE:
+ node->major = SCSI_TAPE_MAJOR;
+ sprintf(node->dev_name, "st#%04lx", id);
+ break;
+ case TYPE_DISK:
+ case TYPE_MOD:
+ node->major = SCSI_DISK0_MAJOR;
+ sprintf(node->dev_name, "sd#%04lx", id);
+ break;
+ case TYPE_ROM:
+ case TYPE_WORM:
+ node->major = SCSI_CDROM_MAJOR;
+ sprintf(node->dev_name, "sr#%04lx", id);
+ break;
+ default:
+ node->major = SCSI_GENERIC_MAJOR;
+ sprintf(node->dev_name, "sg#%04lx", id);
+ break;
+ }
+ *tail = node; tail = &node->next;
+ info->ndev++;
+ info->host = dev->host;
+ }
+ *tail = NULL;
+ if (info->ndev == 0)
+ printk(KERN_INFO "aha152x_cs: no SCSI devices found\n");
+
+ link->state &= ~DEV_CONFIG_PENDING;
+ return;
+
+cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ aha152x_release_cs((u_long)link);
+ return;
+
+} /* aha152x_config_cs */
+
+/*====================================================================*/
+
+static void aha152x_release_cs(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+
+ DEBUG(0, "aha152x_release_cs(0x%p)\n", link);
+
+ if (GET_USE_COUNT(driver_template.module) != 0) {
+ DEBUG(1, "aha152x_cs: release postponed, "
+ "device still open\n");
+ link->state |= DEV_STALE_CONFIG;
+ return;
+ }
+
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ link->dev = NULL;
+
+ CardServices(ReleaseConfiguration, link->handle);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+ link->state &= ~DEV_CONFIG;
+ if (link->state & DEV_STALE_LINK)
+ aha152x_detach(link);
+
+} /* aha152x_release_cs */
+
+/*====================================================================*/
+
+static int aha152x_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+ scsi_info_t *info = link->priv;
+
+ DEBUG(0, "aha152x_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ link->release.expires = jiffies + HZ/20;
+ add_timer(&link->release);
+ }
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ aha152x_config_cs(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG)
+ CardServices(ReleaseConfiguration, link->handle);
+ break;
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG) {
+ Scsi_Cmnd tmp;
+ CardServices(RequestConfiguration, link->handle, &link->conf);
+ tmp.host = info->host;
+ aha152x_host_reset(&tmp);
+ }
+ break;
+ }
+ return 0;
+} /* aha152x_event */
+
+/*====================================================================*/
+
+static int __init init_aha152x_cs(void) {
+ servinfo_t serv;
+ DEBUG(0, "%s\n", version);
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "aha152x_cs: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ register_pccard_driver(&dev_info, &aha152x_attach, &aha152x_detach);
+ return 0;
+}
+
+static void __exit exit_aha152x_cs(void) {
+ DEBUG(0, "aha152x_cs: unloading\n");
+ unregister_pccard_driver(&dev_info);
+ while (dev_list != NULL)
+ aha152x_detach(dev_list);
+}
+
+module_init(init_aha152x_cs);
+module_exit(exit_aha152x_cs);
+
diff --git a/drivers/scsi/pcmcia/apa1480_stub.c b/drivers/scsi/pcmcia/apa1480_stub.c
new file mode 100644
index 000000000..a6419f194
--- /dev/null
+++ b/drivers/scsi/pcmcia/apa1480_stub.c
@@ -0,0 +1,174 @@
+/*======================================================================
+
+ A driver for the Adaptec APA1480 CardBus SCSI Host Adapter
+
+ apa1480_cb.c 1.19 2000/02/14 22:39:25
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+#include <../drivers/scsi/aic7xxx.h>
+
+#include <pcmcia/driver_ops.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"apa1480_cb.c 1.19 2000/02/14 22:39:25 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+static int reset = 1;
+static int ultra = 0;
+
+MODULE_PARM(reset, "i");
+MODULE_PARM(ultra, "i");
+
+/*====================================================================*/
+
+static Scsi_Host_Template driver_template = AIC7XXX;
+
+extern void aic7xxx_setup(char *, int *);
+
+static dev_node_t *apa1480_attach(dev_locator_t *loc);
+static void apa1480_detach(dev_node_t *node);
+
+struct driver_operations apa1480_ops = {
+ "apa1480_cb", apa1480_attach, NULL, NULL, apa1480_detach
+};
+
+/*====================================================================*/
+
+static dev_node_t *apa1480_attach(dev_locator_t *loc)
+{
+ u_char bus, devfn;
+ Scsi_Device *dev;
+ dev_node_t *node;
+ char s[60];
+ int n = 0;
+ struct Scsi_Host *host;
+
+ if (loc->bus != LOC_PCI) return NULL;
+ bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+ printk(KERN_INFO "apa1480_attach(bus %d, function %d)\n",
+ bus, devfn);
+
+ driver_template.module = &__this_module;
+
+ sprintf(s, "no_probe:1,no_reset:%d,ultra:%d",
+ (reset==0), (ultra!=0));
+ aic7xxx_setup(s, NULL);
+ scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+ node = kmalloc(7 * sizeof(dev_node_t), GFP_KERNEL);
+ for (host = scsi_hostlist; host; host = host->next)
+ if (host->hostt == &driver_template)
+ for (dev = host->host_queue; dev; dev = dev->next) {
+ u_long arg[2], id;
+ kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+ id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+ ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+ node[n].minor = 0;
+ switch (dev->type) {
+ case TYPE_TAPE:
+ node[n].major = SCSI_TAPE_MAJOR;
+ sprintf(node[n].dev_name, "st#%04lx", id);
+ break;
+ case TYPE_DISK:
+ case TYPE_MOD:
+ node[n].major = SCSI_DISK0_MAJOR;
+ sprintf(node[n].dev_name, "sd#%04lx", id);
+ break;
+ case TYPE_ROM:
+ case TYPE_WORM:
+ node[n].major = SCSI_CDROM_MAJOR;
+ sprintf(node[n].dev_name, "sr#%04lx", id);
+ break;
+ default:
+ node[n].major = SCSI_GENERIC_MAJOR;
+ sprintf(node[n].dev_name, "sg#%04lx", id);
+ break;
+ }
+ if (n) node[n-1].next = &node[n];
+ n++;
+ }
+ if (n == 0) {
+ printk(KERN_INFO "apa1480_cs: no SCSI devices found\n");
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ kfree(node);
+ return NULL;
+ } else
+ node[n-1].next = NULL;
+
+ MOD_INC_USE_COUNT;
+ return node;
+}
+
+static void apa1480_detach(dev_node_t *node)
+{
+ MOD_DEC_USE_COUNT;
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ kfree(node);
+}
+
+/*====================================================================*/
+
+static int __init init_apa1480_cb(void) {
+ DEBUG(0, "%s\n", version);
+ register_driver(&apa1480_ops);
+ return 0;
+}
+
+static void __exit exit_apa1480_cb(void) {
+ DEBUG(0, "apa1480_cs: unloading\n");
+ unregister_driver(&apa1480_ops);
+}
+
+module_init(init_apa1480_cb);
+module_exit(exit_apa1480_cb);
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
new file mode 100644
index 000000000..558bf3317
--- /dev/null
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -0,0 +1,398 @@
+/*======================================================================
+
+ A driver for Future Domain-compatible PCMCIA SCSI cards
+
+ fdomain_cs.c 1.41 1999/11/15 06:05:48
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+#include <../drivers/scsi/fdomain.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"fdomain_cs.c 1.41 1999/11/15 06:05:48 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+ dev_link_t link;
+ int ndev;
+ dev_node_t node[8];
+} scsi_info_t;
+
+extern void fdomain_setup(char *str, int *ints);
+
+static void fdomain_release(u_long arg);
+static int fdomain_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+static dev_link_t *fdomain_attach(void);
+static void fdomain_detach(dev_link_t *);
+
+static Scsi_Host_Template driver_template = FDOMAIN_16X0;
+
+static dev_link_t *dev_list = NULL;
+
+static dev_info_t dev_info = "fdomain_cs";
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static dev_link_t *fdomain_attach(void)
+{
+ scsi_info_t *info;
+ client_reg_t client_reg;
+ dev_link_t *link;
+ int i, ret;
+
+ DEBUG(0, "fdomain_attach()\n");
+
+ /* Create new SCSI device */
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) return NULL;
+ memset(info, 0, sizeof(*info));
+ link = &info->link; link->priv = info;
+ link->release.function = &fdomain_release;
+ link->release.data = (u_long)link;
+
+ link->io.NumPorts1 = 0x10;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->io.IOAddrLines = 10;
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+ if (irq_list[0] == -1)
+ link->irq.IRQInfo2 = irq_mask;
+ else
+ for (i = 0; i < 4; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.Present = PRESENT_OPTION;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.event_handler = &fdomain_event;
+ client_reg.EventMask =
+ CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ fdomain_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* fdomain_attach */
+
+/*====================================================================*/
+
+static void fdomain_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+
+ DEBUG(0, "fdomain_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ if (link->state & DEV_CONFIG) {
+ fdomain_release((u_long)link);
+ if (link->state & DEV_STALE_CONFIG) {
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+ }
+
+ if (link->handle)
+ CardServices(DeregisterClient, link->handle);
+
+ /* Unlink device structure, free bits */
+ *linkp = link->next;
+ kfree(link->priv);
+
+} /* fdomain_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void fdomain_config(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ scsi_info_t *info = link->priv;
+ tuple_t tuple;
+ cisparse_t parse;
+ int i, last_ret, last_fn, ints[3];
+ u_char tuple_data[64];
+ Scsi_Device *dev;
+ dev_node_t *node, **tail;
+ struct Scsi_Host *host;
+
+ DEBUG(0, "fdomain_config(0x%p)\n", link);
+
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.TupleData = tuple_data;
+ tuple.TupleDataMax = 64;
+ tuple.TupleOffset = 0;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ CS_CHECK(GetTupleData, handle, &tuple);
+ CS_CHECK(ParseTuple, handle, &tuple, &parse);
+ link->conf.ConfigBase = parse.config.base;
+
+ /* Configure card */
+ driver_template.module = &__this_module;
+ link->state |= DEV_CONFIG;
+
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ while (1) {
+ CFG_CHECK(GetTupleData, handle, &tuple);
+ CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+ link->conf.ConfigIndex = parse.cftable_entry.index;
+ link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+ i = CardServices(RequestIO, handle, &link->io);
+ if (i == CS_SUCCESS) break;
+ next_entry:
+ CS_CHECK(GetNextTuple, handle, &tuple);
+ }
+
+ CS_CHECK(RequestIRQ, handle, &link->irq);
+ CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+ /* A bad hack... */
+ release_region(link->io.BasePort1, link->io.NumPorts1);
+
+ /* Set configuration options for the fdomain driver */
+ ints[0] = 2;
+ ints[1] = link->io.BasePort1;
+ ints[2] = link->irq.AssignedIRQ;
+ fdomain_setup("PCMCIA setup", ints);
+
+ scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+ tail = &link->dev;
+ info->ndev = 0;
+ for (host = scsi_hostlist; host; host = host->next)
+ if (host->hostt == &driver_template)
+ for (dev = host->host_queue; dev; dev = dev->next) {
+ u_long arg[2], id;
+ kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+ id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+ ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+ node = &info->node[info->ndev];
+ node->minor = 0;
+ switch (dev->type) {
+ case TYPE_TAPE:
+ node->major = SCSI_TAPE_MAJOR;
+ sprintf(node->dev_name, "st#%04lx", id);
+ break;
+ case TYPE_DISK:
+ case TYPE_MOD:
+ node->major = SCSI_DISK0_MAJOR;
+ sprintf(node->dev_name, "sd#%04lx", id);
+ break;
+ case TYPE_ROM:
+ case TYPE_WORM:
+ node->major = SCSI_CDROM_MAJOR;
+ sprintf(node->dev_name, "sr#%04lx", id);
+ break;
+ default:
+ node->major = SCSI_GENERIC_MAJOR;
+ sprintf(node->dev_name, "sg#%04lx", id);
+ break;
+ }
+ *tail = node; tail = &node->next;
+ info->ndev++;
+ }
+ *tail = NULL;
+ if (info->ndev == 0)
+ printk(KERN_INFO "fdomain_cs: no SCSI devices found\n");
+
+ link->state &= ~DEV_CONFIG_PENDING;
+ return;
+
+cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ fdomain_release((u_long)link);
+ return;
+
+} /* fdomain_config */
+
+/*====================================================================*/
+
+static void fdomain_release(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+
+ DEBUG(0, "fdomain_release(0x%p)\n", link);
+
+ if (GET_USE_COUNT(&__this_module) != 0) {
+ DEBUG(1, "fdomain_cs: release postponed, "
+ "device still open\n");
+ link->state |= DEV_STALE_CONFIG;
+ return;
+ }
+
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ link->dev = NULL;
+
+ CardServices(ReleaseConfiguration, link->handle);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+ link->state &= ~DEV_CONFIG;
+ if (link->state & DEV_STALE_LINK)
+ fdomain_detach(link);
+
+} /* fdomain_release */
+
+/*====================================================================*/
+
+static int fdomain_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+
+ DEBUG(1, "fdomain_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ link->release.expires = jiffies + HZ/20;
+ add_timer(&link->release);
+ }
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ fdomain_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG)
+ CardServices(ReleaseConfiguration, link->handle);
+ break;
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG) {
+ CardServices(RequestConfiguration, link->handle, &link->conf);
+ fdomain_16x0_reset(NULL, 0);
+ }
+ break;
+ }
+ return 0;
+} /* fdomain_event */
+
+/*====================================================================*/
+
+static int __init init_fdomain_cs(void) {
+ servinfo_t serv;
+ DEBUG(0, "%s\n", version);
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "fdomain_cs: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ register_pccard_driver(&dev_info, &fdomain_attach, &fdomain_detach);
+ return 0;
+}
+
+static void __exit exit_fdomain_cs(void) {
+ DEBUG(0, "fdomain_cs: unloading\n");
+ unregister_pccard_driver(&dev_info);
+ while (dev_list != NULL)
+ fdomain_detach(dev_list);
+}
+
+module_init(init_fdomain_cs);
+module_exit(exit_fdomain_cs);
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
new file mode 100644
index 000000000..c3f1d03a5
--- /dev/null
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -0,0 +1,428 @@
+/*======================================================================
+
+ A driver for the Qlogic SCSI card
+
+ qlogic_cs.c 1.77 2000/02/01 19:08:09
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+
+#include <../drivers/scsi/qlogicfas.h>
+
+#define qlogic_reset(h) qlogicfas_reset(h, 0)
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ciscode.h>
+
+extern void qlogicfas_preset(int port, int irq);
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"qlogic_cs.c 1.77 2000/02/01 19:08:09 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+ dev_link_t link;
+ u_short manf_id;
+ int ndev;
+ dev_node_t node[8];
+} scsi_info_t;
+
+static void qlogic_release(u_long arg);
+static int qlogic_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+static dev_link_t *qlogic_attach(void);
+static void qlogic_detach(dev_link_t *);
+
+static Scsi_Host_Template driver_template = QLOGICFAS;
+
+static dev_link_t *dev_list = NULL;
+
+static dev_info_t dev_info = "qlogic_cs";
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static dev_link_t *qlogic_attach(void)
+{
+ scsi_info_t *info;
+ client_reg_t client_reg;
+ dev_link_t *link;
+ int i, ret;
+
+ DEBUG(0, "qlogic_attach()\n");
+
+ /* Create new SCSI device */
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) return NULL;
+ memset(info, 0, sizeof(*info));
+ link = &info->link; link->priv = info;
+ link->release.function = &qlogic_release;
+ link->release.data = (u_long)link;
+
+ link->io.NumPorts1 = 16;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->io.IOAddrLines = 10;
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+ if (irq_list[0] == -1)
+ link->irq.IRQInfo2 = irq_mask;
+ else
+ for (i = 0; i < 4; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.Present = PRESENT_OPTION;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.event_handler = &qlogic_event;
+ client_reg.EventMask =
+ CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ qlogic_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* qlogic_attach */
+
+/*====================================================================*/
+
+static void qlogic_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+
+ DEBUG(0, "qlogic_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ if (link->state & DEV_CONFIG) {
+ qlogic_release((u_long)link);
+ if (link->state & DEV_STALE_CONFIG) {
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+ }
+
+ if (link->handle)
+ CardServices(DeregisterClient, link->handle);
+
+ /* Unlink device structure, free bits */
+ *linkp = link->next;
+ kfree(link->priv);
+
+} /* qlogic_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void qlogic_config(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ scsi_info_t *info = link->priv;
+ tuple_t tuple;
+ cisparse_t parse;
+ int i, last_ret, last_fn;
+ u_short tuple_data[32];
+ Scsi_Device *dev;
+ dev_node_t **tail, *node;
+ struct Scsi_Host *host;
+
+ DEBUG(0, "qlogic_config(0x%p)\n", link);
+
+ tuple.TupleData = (cisdata_t *)tuple_data;
+ tuple.TupleDataMax = 64;
+ tuple.TupleOffset = 0;
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ CS_CHECK(GetTupleData, handle, &tuple);
+ CS_CHECK(ParseTuple, handle, &tuple, &parse);
+ link->conf.ConfigBase = parse.config.base;
+
+ tuple.DesiredTuple = CISTPL_MANFID;
+ if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) &&
+ (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS))
+ info->manf_id = le16_to_cpu(tuple.TupleData[0]);
+
+ /* Configure card */
+ driver_template.module = &__this_module;
+ link->state |= DEV_CONFIG;
+
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ while (1) {
+ CFG_CHECK(GetTupleData, handle, &tuple);
+ CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+ link->conf.ConfigIndex = parse.cftable_entry.index;
+ link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+ link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+ if (link->io.BasePort1 != 0) {
+ i = CardServices(RequestIO, handle, &link->io);
+ if (i == CS_SUCCESS) break;
+ }
+ next_entry:
+ CS_CHECK(GetNextTuple, handle, &tuple);
+ }
+
+ CS_CHECK(RequestIRQ, handle, &link->irq);
+ CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+ if ((info->manf_id == MANFID_MACNICA) ||
+ (info->manf_id == MANFID_PIONEER) ||
+ (info->manf_id == 0x0098)) {
+ /* set ATAcmd */
+ outb(0xb4, link->io.BasePort1+0xd);
+ outb(0x24, link->io.BasePort1+0x9);
+ outb(0x04, link->io.BasePort1+0xd);
+ }
+
+ /* A bad hack... */
+ release_region(link->io.BasePort1, link->io.NumPorts1);
+
+ /* The KXL-810AN has a bigger IO port window */
+ if (link->io.NumPorts1 == 32)
+ qlogicfas_preset(link->io.BasePort1+16, link->irq.AssignedIRQ);
+ else
+ qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ);
+
+ scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+ tail = &link->dev;
+ info->ndev = 0;
+ for (host = scsi_hostlist; host; host = host->next)
+ if (host->hostt == &driver_template)
+ for (dev = host->host_queue; dev; dev = dev->next) {
+ u_long arg[2], id;
+ kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+ id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+ ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+ node = &info->node[info->ndev];
+ node->minor = 0;
+ switch (dev->type) {
+ case TYPE_TAPE:
+ node->major = SCSI_TAPE_MAJOR;
+ sprintf(node->dev_name, "st#%04lx", id);
+ break;
+ case TYPE_DISK:
+ case TYPE_MOD:
+ node->major = SCSI_DISK0_MAJOR;
+ sprintf(node->dev_name, "sd#%04lx", id);
+ break;
+ case TYPE_ROM:
+ case TYPE_WORM:
+ node->major = SCSI_CDROM_MAJOR;
+ sprintf(node->dev_name, "sr#%04lx", id);
+ break;
+ default:
+ node->major = SCSI_GENERIC_MAJOR;
+ sprintf(node->dev_name, "sg#%04lx", id);
+ break;
+ }
+ *tail = node; tail = &node->next;
+ info->ndev++;
+ }
+ *tail = NULL;
+ if (info->ndev == 0)
+ printk(KERN_INFO "qlogic_cs: no SCSI devices found\n");
+
+ link->state &= ~DEV_CONFIG_PENDING;
+ return;
+
+cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ qlogic_release((u_long)link);
+ return;
+
+} /* qlogic_config */
+
+/*====================================================================*/
+
+static void qlogic_release(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+
+ DEBUG(0, "qlogic_release(0x%p)\n", link);
+
+ if (GET_USE_COUNT(&__this_module) != 0) {
+ DEBUG(0, "qlogic_cs: release postponed, device still open\n");
+ link->state |= DEV_STALE_CONFIG;
+ return;
+ }
+
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ link->dev = NULL;
+
+ CardServices(ReleaseConfiguration, link->handle);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+ link->state &= ~DEV_CONFIG;
+ if (link->state & DEV_STALE_LINK)
+ qlogic_detach(link);
+
+} /* qlogic_release */
+
+/*====================================================================*/
+
+static int qlogic_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+
+ DEBUG(1, "qlogic_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ link->release.expires = jiffies + HZ/20;
+ add_timer(&link->release);
+ }
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ qlogic_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG)
+ CardServices(ReleaseConfiguration, link->handle);
+ break;
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG) {
+ scsi_info_t *info = link->priv;
+ CardServices(RequestConfiguration, link->handle, &link->conf);
+ if ((info->manf_id == MANFID_MACNICA) ||
+ (info->manf_id == MANFID_PIONEER) ||
+ (info->manf_id == 0x0098)) {
+ outb( 0x80, link->io.BasePort1+0xd);
+ outb( 0x24, link->io.BasePort1+0x9);
+ outb( 0x04, link->io.BasePort1+0xd);
+ }
+ qlogic_reset(NULL);
+ }
+ break;
+ }
+ return 0;
+} /* qlogic_event */
+
+/*====================================================================*/
+
+static int __init init_qlogic_cs(void) {
+ servinfo_t serv;
+ DEBUG(0, "%s\n", version);
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "qlogic_cs: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ register_pccard_driver(&dev_info, &qlogic_attach, &qlogic_detach);
+ return 0;
+}
+
+static void __exit exit_qlogic_cs(void) {
+ DEBUG(0, "qlogic_cs: unloading\n");
+ unregister_pccard_driver(&dev_info);
+ while (dev_list != NULL)
+ qlogic_detach(dev_list);
+}
+
+module_init(init_qlogic_cs);
+module_exit(exit_qlogic_cs);
diff --git a/drivers/scsi/psi_dale.h b/drivers/scsi/psi_dale.h
index bb7c8006b..03da4c3b8 100644
--- a/drivers/scsi/psi_dale.h
+++ b/drivers/scsi/psi_dale.h
@@ -20,16 +20,32 @@
****************************************************************************/
/************************************************/
+/* Some defines that we like */
+/************************************************/
+#define CHAR char
+#define UCHAR unsigned char
+#define SHORT short
+#define USHORT unsigned short
+#define BOOL unsigned short
+#define LONG long
+#define ULONG unsigned long
+#define VOID void
+
+/************************************************/
/* Dale PCI setup */
/************************************************/
#define VENDOR_PSI 0x1256
#define DEVICE_DALE_1 0x4401 /* 'D1' */
+#define DEVICE_BIGD_1 0x4201 /* 'B1' */
+#define DEVICE_BIGD_2 0x4202 /* 'B2' */
/************************************************/
/* Misc konstants */
/************************************************/
#define DALE_MAXDRIVES 4
+#define BIGD_MAXDRIVES 8
#define SECTORSXFER 8
+#define ATAPI_TRANSFER 8192
#define BYTES_PER_SECTOR 512
#define DEFAULT_TIMING_MODE 5
@@ -49,90 +65,136 @@
/************************************************/
/* DALE Register address offsets */
/************************************************/
-#define REG_DATA 0x80
-#define REG_ERROR 0x84
-#define REG_SECTOR_COUNT 0x88
-#define REG_LBA_0 0x8C
-#define REG_LBA_8 0x90
-#define REG_LBA_16 0x94
-#define REG_LBA_24 0x98
-#define REG_STAT_CMD 0x9C
-#define REG_STAT_SEL 0xA0
-#define REG_FAIL 0xB0
-#define REG_ALT_STAT 0xB8
-#define REG_DRIVE_ADRS 0xBC
-
-#define DALE_DATA_SLOW 0x00040000L
-#define DALE_DATA_MODE2 0x00040000L
-#define DALE_DATA_MODE3 0x00050000L
-#define DALE_DATA_MODE4 0x00060000L
-#define DALE_DATA_MODE4P 0x00070000L
-
-#define RTR_LOCAL_RANGE 0x000
-#define RTR_LOCAL_REMAP 0x004
-#define RTR_EXP_RANGE 0x010
-#define RTR_EXP_REMAP 0x014
-#define RTR_REGIONS 0x018
-#define RTR_DM_MASK 0x01C
-#define RTR_DM_LOCAL_BASE 0x020
-#define RTR_DM_IO_BASE 0x024
-#define RTR_DM_PCI_REMAP 0x028
-#define RTR_DM_IO_CONFIG 0x02C
-#define RTR_MAILBOX 0x040
-#define RTR_LOCAL_DOORBELL 0x060
-#define RTR_PCI_DOORBELL 0x064
-#define RTR_INT_CONTROL_STATUS 0x068
-#define RTR_EEPROM_CONTROL_STATUS 0x06C
-
-#define RTL_DMA0_MODE 0x00
-#define RTL_DMA0_PCI_ADDR 0x04
-#define RTL_DMA0_LOCAL_ADDR 0x08
-#define RTL_DMA0_COUNT 0x0C
-#define RTL_DMA0_DESC_PTR 0x10
-#define RTL_DMA1_MODE 0x14
-#define RTL_DMA1_PCI_ADDR 0x18
-#define RTL_DMA1_LOCAL_ADDR 0x1C
-#define RTL_DMA1_COUNT 0x20
-#define RTL_DMA1_DESC_PTR 0x24
-#define RTL_DMA_COMMAND_STATUS 0x28
-#define RTL_DMA_ARB0 0x2C
-#define RTL_DMA_ARB1 0x30
+#define REG_DATA 0x80
+#define REG_ERROR 0x84
+#define REG_SECTOR_COUNT 0x88
+#define REG_LBA_0 0x8C
+#define REG_LBA_8 0x90
+#define REG_LBA_16 0x94
+#define REG_LBA_24 0x98
+#define REG_STAT_CMD 0x9C
+#define REG_STAT_SEL 0xA0
+#define REG_FAIL 0xB0
+#define REG_ALT_STAT 0xB8
+#define REG_DRIVE_ADRS 0xBC
+
+#define DALE_DATA_SLOW 0x00040000L
+#define DALE_DATA_MODE2 0x00040000L
+#define DALE_DATA_MODE3 0x00050000L
+#define DALE_DATA_MODE4 0x00060000L
+#define DALE_DATA_MODE5 0x00070000L
+
+#define BIGD_DATA_SLOW 0x00000000L
+#define BIGD_DATA_MODE0 0x00000000L
+#define BIGD_DATA_MODE2 0x00000000L
+#define BIGD_DATA_MODE3 0x00000008L
+#define BIGD_DATA_MODE4 0x00000010L
+#define BIGD_DATA_MODE5 0x00000020L
+
+#define RTR_LOCAL_RANGE 0x000
+#define RTR_LOCAL_REMAP 0x004
+#define RTR_EXP_RANGE 0x010
+#define RTR_EXP_REMAP 0x014
+#define RTR_REGIONS 0x018
+#define RTR_DM_MASK 0x01C
+#define RTR_DM_LOCAL_BASE 0x020
+#define RTR_DM_IO_BASE 0x024
+#define RTR_DM_PCI_REMAP 0x028
+#define RTR_DM_IO_CONFIG 0x02C
+#define RTR_MAILBOX 0x040
+#define RTR_LOCAL_DOORBELL 0x060
+#define RTR_PCI_DOORBELL 0x064
+#define RTR_INT_CONTROL_STATUS 0x068
+#define RTR_EEPROM_CONTROL_STATUS 0x06C
+
+#define RTR_DMA0_MODE 0x0080
+#define RTR_DMA0_PCI_ADDR 0x0084
+#define RTR_DMA0_LOCAL_ADDR 0x0088
+#define RTR_DMA0_COUNT 0x008C
+#define RTR_DMA0_DESC_PTR 0x0090
+#define RTR_DMA1_MODE 0x0094
+#define RTR_DMA1_PCI_ADDR 0x0098
+#define RTR_DMA1_LOCAL_ADDR 0x009C
+#define RTR_DMA1_COUNT 0x00A0
+#define RTR_DMA1_DESC_PTR 0x00A4
+#define RTR_DMA_COMMAND_STATUS 0x00A8
+#define RTR_DMA_ARB0 0x00AC
+#define RTR_DMA_ARB1 0x00B0
+
+#define RTL_DMA0_MODE 0x00
+#define RTL_DMA0_PCI_ADDR 0x04
+#define RTL_DMA0_LOCAL_ADDR 0x08
+#define RTL_DMA0_COUNT 0x0C
+#define RTL_DMA0_DESC_PTR 0x10
+#define RTL_DMA1_MODE 0x14
+#define RTL_DMA1_PCI_ADDR 0x18
+#define RTL_DMA1_LOCAL_ADDR 0x1C
+#define RTL_DMA1_COUNT 0x20
+#define RTL_DMA1_DESC_PTR 0x24
+#define RTL_DMA_COMMAND_STATUS 0x28
+#define RTL_DMA_ARB0 0x2C
+#define RTL_DMA_ARB1 0x30
/************************************************/
/* Dale Scratchpad locations */
/************************************************/
-#define DALE_CHANNEL_DEVICE_0 0 // device channel locations
-#define DALE_CHANNEL_DEVICE_1 1
-#define DALE_CHANNEL_DEVICE_2 2
-#define DALE_CHANNEL_DEVICE_3 3
+#define DALE_CHANNEL_DEVICE_0 0 // device channel locations
+#define DALE_CHANNEL_DEVICE_1 1
+#define DALE_CHANNEL_DEVICE_2 2
+#define DALE_CHANNEL_DEVICE_3 3
-#define DALE_SCRATH_DEVICE_0 4 // device type codes
-#define DALE_SCRATH_DEVICE_1 5
-#define DALE_SCRATH_DEVICE_2 6
-#define DALE_SCRATH_DEVICE_3 7
+#define DALE_SCRATCH_DEVICE_0 4 // device type codes
+#define DALE_SCRATCH_DEVICE_1 5
+#define DALE_SCRATCH_DEVICE_2 6
+#define DALE_SCRATCH_DEVICE_3 7
-#define DALE_RAID_0_STATUS 8
-#define DALE_RAID_1_STATUS 9
+#define DALE_RAID_0_STATUS 8
+#define DALE_RAID_1_STATUS 9
-#define DALE_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5)
-#define DALE_NUM_DRIVES 13 // number of addressable drives on this board
-#define DALE_RAID_ON 14 // RAID status On
-#define DALE_LAST_ERROR 15 // Last error code from BIOS
+#define DALE_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5)
+#define DALE_NUM_DRIVES 13 // number of addressable drives on this board
+#define DALE_RAID_ON 14 // RAID status On
+#define DALE_LAST_ERROR 15 // Last error code from BIOS
/************************************************/
-/* Dale cable select bits */
+/* BigD Scratchpad locations */
/************************************************/
-#define SEL_NONE 0x00
-#define SEL_1 0x01
-#define SEL_2 0x02
+#define BIGD_DEVICE_0 0 // device channel locations
+#define BIGD_DEVICE_1 1
+#define BIGD_DEVICE_2 2
+#define BIGD_DEVICE_3 3
+
+#define BIGD_DEVICE_4 4 // device type codes
+#define BIGD_DEVICE_5 5
+#define BIGD_DEVICE_6 6
+#define BIGD_DEVICE_7 7
+
+#define BIGD_ALARM_IMAGE 11 // ~image of alarm fail register
+#define BIGD_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5)
+#define BIGD_NUM_DRIVES 13 // number of addressable drives on this board
+#define BIGD_RAID_ON 14 // RAID status is on for the whole board
+#define BIGD_LAST_ERROR 15 // Last error code from BIOS
+
+#define BIGD_RAID_0_STATUS 16
+#define BIGD_RAID_1_STATUS 17
+#define BIGD_RAID_2_STATUS 18
+#define BIGD_RAID_3_STATUS 19
+#define BIGD_RAID_4_STATUS 20
+#define BIGD_RAID_5_STATUS 21
+#define BIGD_RAID_6_STATUS 22
+#define BIGD_RAID_7_STATUS 23
/************************************************/
-/* Programmable Interrupt Controller */
+/* Dale cable select bits */
/************************************************/
-#define PIC1 0x20 // first 8259 base port address
-#define PIC2 0xA0 // second 8259 base port address
-#define INT_OCW1 1 // Operation Control Word 1: IRQ mask
-#define EOI 0x20 // non-specific end-of-interrupt
+#define SEL_NONE 0x00
+#define SEL_1 0x01
+#define SEL_2 0x02
+#define SEL_3 0x04
+#define SEL_4 0x08
+#define SEL_NEW_SPEED_1 0x20
+#define SEL_COPY 0x40
+#define SEL_IRQ_OFF 0x80
/************************************************/
/* Device/Geometry controls */
@@ -149,6 +211,18 @@
#define DEVICE_DASD_LBA 0x4 // LBA compatible device
/************************************************/
+/* BigD fail register bits */
+/************************************************/
+#define FAIL_NONE 0x00
+#define FAIL_0 0x01
+#define FAIL_1 0x02
+#define FAIL_2 0x04
+#define FAIL_MULTIPLE 0x08
+#define FAIL_GOOD 0x20
+#define FAIL_AUDIBLE 0x40
+#define FAIL_ANY 0x80
+
+/************************************************/
/* Setup Structure Definitions */
/************************************************/
typedef struct // device setup parameters
@@ -168,11 +242,11 @@ typedef struct // master setup structure
BOOL promptBIOS;
BOOL fastFormat;
BOOL shareInterrupt;
- BOOL rebootRebuil;
+ BOOL rebootRebuild;
USHORT timingMode;
USHORT spare5;
USHORT spare6;
- SETUP_DEVICE setupDevice[4];
+ SETUP_DEVICE setupDevice[BIGD_MAXDRIVES];
} SETUP, *PSETUP;
/************************************************/
@@ -210,3 +284,281 @@ typedef struct DEVICE_RAID1
#define MY_SCSI_REBUILD 0x40 // byte 1 subcommand to reconstruct a mirrored pair
#define MY_SCSI_DEMOFAIL 0x54 // byte 1 subcommand for RAID failure demonstration
#define MY_SCSI_ALARMMUTE 0x60 // byte 1 subcommand to mute any alarm currently on
+
+/************************************************/
+/* Timeout konstants */
+/************************************************/
+#define TIMEOUT_READY 100 // 100 mSec
+#define TIMEOUT_DRQ 300 // 300 mSec
+#define TIMEOUT_DATA (3 * HZ) // 3 seconds
+
+/************************************************/
+/* Misc. macros */
+/************************************************/
+#define ANY2SCSI(up, p) \
+((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \
+((UCHAR *)up)[1] = ((ULONG)(p));
+
+#define SCSI2LONG(up) \
+( (((long)*(((UCHAR *)up))) << 16) \
++ (((long)(((UCHAR *)up)[1])) << 8) \
++ ((long)(((UCHAR *)up)[2])) )
+
+#define XANY2SCSI(up, p) \
+((UCHAR *)up)[0] = ((long)(p)) >> 24; \
+((UCHAR *)up)[1] = ((long)(p)) >> 16; \
+((UCHAR *)up)[2] = ((long)(p)) >> 8; \
+((UCHAR *)up)[3] = ((long)(p));
+
+#define XSCSI2LONG(up) \
+( (((long)(((UCHAR *)up)[0])) << 24) \
++ (((long)(((UCHAR *)up)[1])) << 16) \
++ (((long)(((UCHAR *)up)[2])) << 8) \
++ ((long)(((UCHAR *)up)[3])) )
+
+#define SelectSpigot(padapter,spigot) outb_p (spigot, padapter->regStatSel)
+#define WriteCommand(padapter,cmd) outb_p (cmd, padapter->regStatCmd)
+#define AtapiDevice(padapter,b) outb_p (b, padapter->regLba24);
+#define AtapiCountLo(padapter,b) outb_p (b, padapter->regLba8)
+#define AtapiCountHi(padapter,b) outb_p (b, padapter->regLba16)
+
+/************************************************/
+/* SCSI CDB operation codes */
+/************************************************/
+#define SCSIOP_TEST_UNIT_READY 0x00
+#define SCSIOP_REZERO_UNIT 0x01
+#define SCSIOP_REWIND 0x01
+#define SCSIOP_REQUEST_BLOCK_ADDR 0x02
+#define SCSIOP_REQUEST_SENSE 0x03
+#define SCSIOP_FORMAT_UNIT 0x04
+#define SCSIOP_READ_BLOCK_LIMITS 0x05
+#define SCSIOP_REASSIGN_BLOCKS 0x07
+#define SCSIOP_READ6 0x08
+#define SCSIOP_RECEIVE 0x08
+#define SCSIOP_WRITE6 0x0A
+#define SCSIOP_PRINT 0x0A
+#define SCSIOP_SEND 0x0A
+#define SCSIOP_SEEK6 0x0B
+#define SCSIOP_TRACK_SELECT 0x0B
+#define SCSIOP_SLEW_PRINT 0x0B
+#define SCSIOP_SEEK_BLOCK 0x0C
+#define SCSIOP_PARTITION 0x0D
+#define SCSIOP_READ_REVERSE 0x0F
+#define SCSIOP_WRITE_FILEMARKS 0x10
+#define SCSIOP_FLUSH_BUFFER 0x10
+#define SCSIOP_SPACE 0x11
+#define SCSIOP_INQUIRY 0x12
+#define SCSIOP_VERIFY6 0x13
+#define SCSIOP_RECOVER_BUF_DATA 0x14
+#define SCSIOP_MODE_SELECT 0x15
+#define SCSIOP_RESERVE_UNIT 0x16
+#define SCSIOP_RELEASE_UNIT 0x17
+#define SCSIOP_COPY 0x18
+#define SCSIOP_ERASE 0x19
+#define SCSIOP_MODE_SENSE 0x1A
+#define SCSIOP_START_STOP_UNIT 0x1B
+#define SCSIOP_STOP_PRINT 0x1B
+#define SCSIOP_LOAD_UNLOAD 0x1B
+#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C
+#define SCSIOP_SEND_DIAGNOSTIC 0x1D
+#define SCSIOP_MEDIUM_REMOVAL 0x1E
+#define SCSIOP_READ_CAPACITY 0x25
+#define SCSIOP_READ 0x28
+#define SCSIOP_WRITE 0x2A
+#define SCSIOP_SEEK 0x2B
+#define SCSIOP_LOCATE 0x2B
+#define SCSIOP_WRITE_VERIFY 0x2E
+#define SCSIOP_VERIFY 0x2F
+#define SCSIOP_SEARCH_DATA_HIGH 0x30
+#define SCSIOP_SEARCH_DATA_EQUAL 0x31
+#define SCSIOP_SEARCH_DATA_LOW 0x32
+#define SCSIOP_SET_LIMITS 0x33
+#define SCSIOP_READ_POSITION 0x34
+#define SCSIOP_SYNCHRONIZE_CACHE 0x35
+#define SCSIOP_COMPARE 0x39
+#define SCSIOP_COPY_COMPARE 0x3A
+#define SCSIOP_WRITE_DATA_BUFF 0x3B
+#define SCSIOP_READ_DATA_BUFF 0x3C
+#define SCSIOP_CHANGE_DEFINITION 0x40
+#define SCSIOP_READ_SUB_CHANNEL 0x42
+#define SCSIOP_READ_TOC 0x43
+#define SCSIOP_READ_HEADER 0x44
+#define SCSIOP_PLAY_AUDIO 0x45
+#define SCSIOP_PLAY_AUDIO_MSF 0x47
+#define SCSIOP_PLAY_TRACK_INDEX 0x48
+#define SCSIOP_PLAY_TRACK_RELATIVE 0x49
+#define SCSIOP_PAUSE_RESUME 0x4B
+#define SCSIOP_LOG_SELECT 0x4C
+#define SCSIOP_LOG_SENSE 0x4D
+#define SCSIOP_MODE_SELECT10 0x55
+#define SCSIOP_MODE_SENSE10 0x5A
+#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6
+#define SCSIOP_MECHANISM_STATUS 0xBD
+#define SCSIOP_READ_CD 0xBE
+
+// IDE command definitions
+#define IDE_COMMAND_ATAPI_RESET 0x08
+#define IDE_COMMAND_READ 0x20
+#define IDE_COMMAND_WRITE 0x30
+#define IDE_COMMAND_RECALIBRATE 0x10
+#define IDE_COMMAND_SEEK 0x70
+#define IDE_COMMAND_SET_PARAMETERS 0x91
+#define IDE_COMMAND_VERIFY 0x40
+#define IDE_COMMAND_ATAPI_PACKET 0xA0
+#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1
+#define IDE_CMD_READ_MULTIPLE 0xC4
+#define IDE_CMD_WRITE_MULTIPLE 0xC5
+#define IDE_CMD_SET_MULTIPLE 0xC6
+#define IDE_COMMAND_IDENTIFY 0xEC
+
+// IDE status definitions
+#define IDE_STATUS_ERROR 0x01
+#define IDE_STATUS_INDEX 0x02
+#define IDE_STATUS_CORRECTED_ERROR 0x04
+#define IDE_STATUS_DRQ 0x08
+#define IDE_STATUS_DSC 0x10
+#define IDE_STATUS_WRITE_FAULT 0x20
+#define IDE_STATUS_DRDY 0x40
+#define IDE_STATUS_BUSY 0x80
+
+typedef struct _ATAPI_STATUS
+ {
+ CHAR check :1;
+ CHAR reserved1 :1;
+ CHAR corr :1;
+ CHAR drq :1;
+ CHAR dsc :1;
+ CHAR reserved2 :1;
+ CHAR drdy :1;
+ CHAR bsy :1;
+ } ATAPI_STATUS;
+
+typedef struct _ATAPI_REASON
+ {
+ CHAR cod :1;
+ CHAR io :1;
+ CHAR reserved1 :6;
+ } ATAPI_REASON;
+
+typedef struct _ATAPI_ERROR
+ {
+ CHAR ili :1;
+ CHAR eom :1;
+ CHAR abort :1;
+ CHAR mcr :1;
+ CHAR senseKey :4;
+ } ATAPI_ERROR;
+
+// IDE error definitions
+#define IDE_ERROR_AMNF 0x01
+#define IDE_ERROR_TKONF 0x02
+#define IDE_ERROR_ABRT 0x04
+#define IDE_ERROR_MCR 0x08
+#define IDE_ERROR_IDFN 0x10
+#define IDE_ERROR_MC 0x20
+#define IDE_ERROR_UNC 0x40
+#define IDE_ERROR_BBK 0x80
+
+// SCSI read capacity structure
+typedef struct _READ_CAPACITY_DATA
+ {
+ ULONG blks; /* total blocks (converted to little endian) */
+ ULONG blksiz; /* size of each (converted to little endian) */
+ } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
+
+// SCSI inquiry data
+typedef struct _INQUIRYDATA
+ {
+ UCHAR DeviceType :5;
+ UCHAR DeviceTypeQualifier :3;
+ UCHAR DeviceTypeModifier :7;
+ UCHAR RemovableMedia :1;
+ UCHAR Versions;
+ UCHAR ResponseDataFormat;
+ UCHAR AdditionalLength;
+ UCHAR Reserved[2];
+ UCHAR SoftReset :1;
+ UCHAR CommandQueue :1;
+ UCHAR Reserved2 :1;
+ UCHAR LinkedCommands :1;
+ UCHAR Synchronous :1;
+ UCHAR Wide16Bit :1;
+ UCHAR Wide32Bit :1;
+ UCHAR RelativeAddressing :1;
+ UCHAR VendorId[8];
+ UCHAR ProductId[16];
+ UCHAR ProductRevisionLevel[4];
+ UCHAR VendorSpecific[20];
+ UCHAR Reserved3[40];
+ } INQUIRYDATA, *PINQUIRYDATA;
+
+// IDE IDENTIFY data
+#pragma pack (1)
+typedef struct _IDENTIFY_DATA
+ {
+ USHORT GeneralConfiguration; // 0
+ USHORT NumberOfCylinders; // 1
+ USHORT Reserved1; // 2
+ USHORT NumberOfHeads; // 3
+ USHORT UnformattedBytesPerTrack; // 4
+ USHORT UnformattedBytesPerSector; // 5
+ USHORT SectorsPerTrack; // 6
+ USHORT NumBytesISG; // 7 Byte Len - inter-sector gap
+ USHORT NumBytesSync; // 8 - sync field
+ USHORT NumWordsVUS; // 9 Len - Vendor Unique Info
+ USHORT SerialNumber[10]; // 10
+ USHORT BufferType; // 20
+ USHORT BufferSectorSize; // 21
+ USHORT NumberOfEccBytes; // 22
+ USHORT FirmwareRevision[4]; // 23
+ USHORT ModelNumber[20]; // 27
+ USHORT NumSectorsPerInt :8; // 47 Multiple Mode - Sec/Blk
+ USHORT Reserved2 :8; // 47
+ USHORT DoubleWordMode; // 48 flag for double word mode capable
+ USHORT VendorUnique1 :8; // 49
+ USHORT SupportDMA :1; // 49 DMA supported
+ USHORT SupportLBA :1; // 49 LBA supported
+ USHORT SupportIORDYDisable :1; // 49 IORDY can be disabled
+ USHORT SupportIORDY :1; // 49 IORDY supported
+ USHORT ReservedPsuedoDMA :1; // 49 reserved for pseudo DMA mode support
+ USHORT Reserved3 :3; // 49
+ USHORT Reserved4; // 50
+ USHORT Reserved5 :8; // 51 Transfer Cycle Timing - PIO
+ USHORT PIOCycleTime :8; // 51 Transfer Cycle Timing - PIO
+ USHORT Reserved6 :8; // 52 - DMA
+ USHORT DMACycleTime :8; // 52 - DMA
+ USHORT Valid_54_58 :1; // 53 words 54 - 58 are vaild
+ USHORT Valid_64_70 :1; // 53 words 64 - 70 are valid
+ USHORT Reserved7 :14; // 53
+ USHORT LogNumCyl; // 54 Current Translation - Num Cyl
+ USHORT LogNumHeads; // 55 Num Heads
+ USHORT LogSectorsPerTrack; // 56 Sec/Trk
+ ULONG LogTotalSectors; // 57 Total Sec
+ USHORT CurrentNumSecPerInt :8; // 59 current setting for number of sectors per interrupt
+ USHORT ValidNumSecPerInt :1; // 59 Current setting is valid for number of sectors per interrupt
+ USHORT Reserved8 :7; // 59
+ ULONG LBATotalSectors; // 60 LBA Mode - Sectors
+ USHORT DMASWordFlags; // 62
+ USHORT DMAMWordFlags; // 63
+ USHORT AdvancedPIOSupport :8; // 64 Flow control PIO transfer modes supported
+ USHORT Reserved9 :8; // 64
+ USHORT MinMultiDMACycle; // 65 minimum multiword DMA transfer cycle time per word
+ USHORT RecomendDMACycle; // 66 Manufacturer's recommende multiword DMA transfer cycle time
+ USHORT MinPIOCycleWithoutFlow; // 67 Minimum PIO transfer cycle time without flow control
+ USHORT MinPIOCylceWithFlow; // 68 Minimum PIO transfer cycle time with IORDY flow control
+ USHORT ReservedSpace[256-69]; // 69
+ } IDENTIFY_DATA, *PIDENTIFY_DATA;
+
+// ATAPI configuration bits
+typedef struct _ATAPI_GENERAL_0
+ {
+ USHORT CmdPacketSize :2; // Command packet size
+ USHORT Reserved1 :3;
+ USHORT CmdDrqType :2;
+ USHORT Removable :1;
+ USHORT DeviceType :5;
+ USHORT Reserved2 :1;
+ USHORT ProtocolType :2;
+ } ATAPI_GENERAL_0;
+
+#pragma pack ()
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 543a98419..e216ef03a 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -182,6 +182,7 @@ END OF TERMS AND CONDITIONS
- Initial Beta Release.
*****************************************************************************/
+
#ifdef MODULE
#include <linux/module.h>
#endif
@@ -2789,7 +2790,7 @@ qla1280_setup_chip(scsi_qla_host_t *ha)
DEBUG(sprintf(debug_buff,"qla1280_setup_chip: loading risc @ =(0x%p),%d,%d(0x%x).\n\r",risc_code_address,cnt,num,risc_address);)
DEBUG(qla1280_print(debug_buff));
- printk("qla1280_setup_chip: loading risc @ =code=(0x%p),cnt=%d,seg=%d,addr=0x%x\n\r",risc_code_address,cnt,num,risc_address);
+ DEBUG(printk("qla1280_setup_chip: loading risc @ =code=(0x%p),cnt=%d,seg=%d,addr=0x%x\n\r",risc_code_address,cnt,num,risc_address));
BCOPY((caddr_t) risc_code_address,(caddr_t) ha->request_ring, (cnt <<1));
mb[0] = MBC_LOAD_RAM;
/* mb[0] = MBC_LOAD_RAM_A64; */
@@ -2799,7 +2800,7 @@ qla1280_setup_chip(scsi_qla_host_t *ha)
mb[2] = (uint16_t) (ha->request_dma >> 16) & 0xffff;
mb[7] = (uint16_t) (MS_64BITS(ha->request_dma) & 0xffff);
mb[6] = (uint16_t) (MS_64BITS(ha->request_dma) >> 16) & 0xffff;
- printk("qla1280_setup_chip: op=%d 0x%lx = 0x%4x,0x%4x,0x%4x,0x%4x\n",mb[0],ha->request_dma,mb[6],mb[7],mb[2],mb[3]);
+ DEBUG(printk("qla1280_setup_chip: op=%d 0x%lx = 0x%4x,0x%4x,0x%4x,0x%4x\n",mb[0],ha->request_dma,mb[6],mb[7],mb[2],mb[3]));
if( (status = qla1280_mailbox_command(ha, BIT_4|BIT_3|BIT_2|BIT_1|BIT_0,
&mb[0])) )
{
diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
index 6196d8eb2..9bc66953d 100644
--- a/drivers/scsi/qlogicfas.c
+++ b/drivers/scsi/qlogicfas.c
@@ -21,7 +21,7 @@
Version 0.46 1/30/97 - kernel 1.2.0+
Functions as standalone, loadable, and PCMCIA driver, the latter from
- Dave Hind's PCMCIA package.
+ Dave Hinds' PCMCIA package.
Redistributable under terms of the GNU Public License
@@ -107,7 +107,6 @@
#ifdef PCMCIA
#undef QL_INT_ACTIVE_HIGH
#define QL_INT_ACTIVE_HIGH 0
-#define MODULE
#endif
#include <linux/module.h>
diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c
index ecdc65cd4..283fe9c3d 100644
--- a/drivers/scsi/qlogicfc.c
+++ b/drivers/scsi/qlogicfc.c
@@ -64,7 +64,7 @@
/* Configuration section **************************************************** */
/* Set the following macro to 1 to reload the ISP2x00's firmware. This is
- version 1.15.37 of the isp2100's firmware and version 2.00.16 of the
+ version 1.17.30 of the isp2100's firmware and version 2.00.40 of the
isp2200's firmware.
*/
@@ -91,7 +91,7 @@
/* #define TRACE_ISP 1 */
-#define DEFAULT_LOOP_COUNT 10000000
+#define DEFAULT_LOOP_COUNT 1000000000
/* End Configuration section ************************************************ */
@@ -632,6 +632,17 @@ struct init_cb {
#define QLOGICFC_MAX_LUN 128
#define QLOGICFC_MAX_LOOP_ID 0x7d
+/* the following connection options only apply to the 2200. i have only
+ * had success with LOOP_ONLY and P2P_ONLY.
+ */
+
+#define LOOP_ONLY 0
+#define P2P_ONLY 1
+#define LOOP_PREFERED 2
+#define P2P_PREFERED 3
+
+#define CONNECTION_PREFERENCE LOOP_ONLY
+
/* adapter_state values */
#define AS_FIRMWARE_DEAD -1
#define AS_LOOP_DOWN 0
@@ -762,7 +773,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt)
hostdata->queued = 0;
/* set up the control block */
hostdata->control_block.version = 0x1;
- hostdata->control_block.firm_opts = 0x000e;
+ hostdata->control_block.firm_opts = 0x800e;
hostdata->control_block.max_frame_len = 2048;
hostdata->control_block.max_iocb = QLOGICFC_REQ_QUEUE_LEN;
hostdata->control_block.exec_throttle = QLOGICFC_CMD_PER_LUN;
@@ -780,6 +791,8 @@ int isp2x00_detect(Scsi_Host_Template * tmpt)
hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(hostdata->req);
hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(hostdata->req);
+
+ hostdata->control_block.add_firm_opts |= CONNECTION_PREFERENCE<<4;
hostdata->adapter_state = AS_LOOP_DOWN;
hostdata->explore_timer.data = 1;
hostdata->host_id = hosts;
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index a7418f18b..d61c832c5 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1036,7 +1036,7 @@ static inline int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd,
int sg_count;
sg = (struct scatterlist *) Cmnd->buffer;
- sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg);
+ sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
ds = cmd->dataseg;
cmd->segment_cnt = sg_count;
@@ -1074,15 +1074,20 @@ static inline int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd,
}
sg_count -= n;
}
- } else {
+ } else if (Cmnd->request_bufflen) {
Cmnd->SCp.ptr = (char *)(unsigned long)
sbus_map_single(qpti->sdev,
Cmnd->request_buffer,
- Cmnd->request_bufflen);
+ Cmnd->request_bufflen,
+ scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr);
cmd->dataseg[0].d_count = Cmnd->request_bufflen;
cmd->segment_cnt = 1;
+ } else {
+ cmd->dataseg[0].d_base = 0;
+ cmd->dataseg[0].d_count = 0;
+ cmd->segment_cnt = 1; /* Shouldn't this be 0? */
}
/* Committed, record Scsi_Cmd so we can find it later. */
@@ -1409,11 +1414,13 @@ static Scsi_Cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
if (Cmnd->use_sg) {
sbus_unmap_sg(qpti->sdev,
(struct scatterlist *)Cmnd->buffer,
- Cmnd->use_sg);
+ Cmnd->use_sg,
+ scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
} else {
sbus_unmap_single(qpti->sdev,
(__u32)((unsigned long)Cmnd->SCp.ptr),
- Cmnd->request_bufflen);
+ Cmnd->request_bufflen,
+ scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
}
qpti->cmd_count[Cmnd->target]--;
sbus_writew(out_ptr, qpti->qregs + MBOX5);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 2d86cbf95..a6e2c14d9 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -224,6 +224,8 @@ void scsi_wait_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
{
DECLARE_MUTEX_LOCKED(sem);
+ if (buffer != NULL && SCpnt->sc_data_direction == SCSI_DATA_NONE)
+ BUG();
SCpnt->request.sem = &sem;
SCpnt->request.rq_status = RQ_SCSI_BUSY;
scsi_do_cmd (SCpnt, (void *) cmnd,
@@ -248,6 +250,73 @@ static spinlock_t device_request_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t scsi_bhqueue_lock = SPIN_LOCK_UNLOCKED;
/*
+ * Function: scsi_allocate_request
+ *
+ * Purpose: Allocate a request descriptor.
+ *
+ * Arguments: device - device for which we want a request
+ *
+ * Lock status: No locks assumed to be held. This function is SMP-safe.
+ *
+ * Returns: Pointer to request block.
+ *
+ * Notes: With the new queueing code, it becomes important
+ * to track the difference between a command and a
+ * request. A request is a pending item in the queue that
+ * has not yet reached the top of the queue.
+ */
+
+Scsi_Request *scsi_allocate_request(Scsi_Device * device)
+{
+ Scsi_Request *SRpnt = NULL;
+
+ if (!device)
+ panic("No device passed to scsi_allocate_request().\n");
+
+ SRpnt = (Scsi_Request *) kmalloc(sizeof(Scsi_Request), GFP_ATOMIC);
+ if( SRpnt == NULL )
+ {
+ return NULL;
+ }
+
+ memset(SRpnt, 0, sizeof(Scsi_Request));
+ SRpnt->sr_device = device;
+ SRpnt->sr_host = device->host;
+ SRpnt->sr_magic = SCSI_REQ_MAGIC;
+ SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN;
+
+ return SRpnt;
+}
+
+/*
+ * Function: scsi_release_request
+ *
+ * Purpose: Release a request descriptor.
+ *
+ * Arguments: device - device for which we want a request
+ *
+ * Lock status: No locks assumed to be held. This function is SMP-safe.
+ *
+ * Returns: Pointer to request block.
+ *
+ * Notes: With the new queueing code, it becomes important
+ * to track the difference between a command and a
+ * request. A request is a pending item in the queue that
+ * has not yet reached the top of the queue. We still need
+ * to free a request when we are done with it, of course.
+ */
+void scsi_release_request(Scsi_Request * req)
+{
+ if( req->sr_command != NULL )
+ {
+ scsi_release_command(req->sr_command);
+ req->sr_command = NULL;
+ }
+
+ kfree(req);
+}
+
+/*
* Function: scsi_allocate_device
*
* Purpose: Allocate a command descriptor.
@@ -269,6 +338,9 @@ static spinlock_t scsi_bhqueue_lock = SPIN_LOCK_UNLOCKED;
* command block, this function will interrupt and return
* NULL in the event that a signal arrives that needs to
* be handled.
+ *
+ * This function is deprecated, and drivers should be
+ * rewritten to use Scsi_Request instead of Scsi_Cmnd.
*/
Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait,
@@ -417,6 +489,10 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait,
SCpnt->transfersize = 0; /* No default transfer size */
SCpnt->cmd_len = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN;
+ SCpnt->sc_request = NULL;
+ SCpnt->sc_magic = SCSI_CMND_MAGIC;
+
SCpnt->result = 0;
SCpnt->underflow = 0; /* Do not flag underflow conditions */
SCpnt->resid = 0;
@@ -451,6 +527,9 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait,
* gets hidden in this function. Upper level drivers don't
* have any chickens to wave in the air to get things to
* work reliably.
+ *
+ * This function is deprecated, and drivers should be
+ * rewritten to use Scsi_Request instead of Scsi_Cmnd.
*/
void scsi_release_command(Scsi_Cmnd * SCpnt)
{
@@ -636,6 +715,8 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
return rtn;
}
+devfs_handle_t scsi_devfs_handle = NULL;
+
/*
* scsi_do_cmd sends all the commands out to the low-level driver. It
* handles the specifics required for each low level driver - ie queued
@@ -643,6 +724,215 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
* drivers go for the same host at the same time.
*/
+void scsi_wait_req (Scsi_Request * SRpnt, const void *cmnd ,
+ void *buffer, unsigned bufflen,
+ int timeout, int retries)
+{
+ DECLARE_MUTEX_LOCKED(sem);
+
+ SRpnt->sr_request.sem = &sem;
+ SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;
+ scsi_do_req (SRpnt, (void *) cmnd,
+ buffer, bufflen, scsi_wait_done, timeout, retries);
+ down (&sem);
+ SRpnt->sr_request.sem = NULL;
+ if( SRpnt->sr_command != NULL )
+ {
+ scsi_release_command(SRpnt->sr_command);
+ SRpnt->sr_command = NULL;
+ }
+
+}
+
+/*
+ * Function: scsi_do_req
+ *
+ * Purpose: Queue a SCSI request
+ *
+ * Arguments: SRpnt - command descriptor.
+ * cmnd - actual SCSI command to be performed.
+ * buffer - data buffer.
+ * bufflen - size of data buffer.
+ * done - completion function to be run.
+ * timeout - how long to let it run before timeout.
+ * retries - number of retries we allow.
+ *
+ * Lock status: With the new queueing code, this is SMP-safe, and no locks
+ * need be held upon entry. The old queueing code the lock was
+ * assumed to be held upon entry.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: Prior to the new queue code, this function was not SMP-safe.
+ * Also, this function is now only used for queueing requests
+ * for things like ioctls and character device requests - this
+ * is because we essentially just inject a request into the
+ * queue for the device. Normal block device handling manipulates
+ * the queue directly.
+ */
+void scsi_do_req(Scsi_Request * SRpnt, const void *cmnd,
+ void *buffer, unsigned bufflen, void (*done) (Scsi_Cmnd *),
+ int timeout, int retries)
+{
+ Scsi_Device * SDpnt = SRpnt->sr_device;
+ struct Scsi_Host *host = SDpnt->host;
+
+ ASSERT_LOCK(&io_request_lock, 0);
+
+ SCSI_LOG_MLQUEUE(4,
+ {
+ int i;
+ int target = SDpnt->id;
+ printk("scsi_do_req (host = %d, channel = %d target = %d, "
+ "buffer =%p, bufflen = %d, done = %p, timeout = %d, "
+ "retries = %d)\n"
+ "command : ", host->host_no, SDpnt->channel, target, buffer,
+ bufflen, done, timeout, retries);
+ for (i = 0; i < 10; ++i)
+ printk("%02x ", ((unsigned char *) cmnd)[i]);
+ printk("\n");
+ });
+
+ if (!host) {
+ panic("Invalid or not present host.\n");
+ }
+
+ /*
+ * If the upper level driver is reusing these things, then
+ * we should release the low-level block now. Another one will
+ * be allocated later when this request is getting queued.
+ */
+ if( SRpnt->sr_command != NULL )
+ {
+ scsi_release_command(SRpnt->sr_command);
+ SRpnt->sr_command = NULL;
+ }
+
+ /*
+ * We must prevent reentrancy to the lowlevel host driver. This prevents
+ * it - we enter a loop until the host we want to talk to is not busy.
+ * Race conditions are prevented, as interrupts are disabled in between the
+ * time we check for the host being not busy, and the time we mark it busy
+ * ourselves.
+ */
+
+
+ /*
+ * Our own function scsi_done (which marks the host as not busy, disables
+ * the timeout counter, etc) will be called by us or by the
+ * scsi_hosts[host].queuecommand() function needs to also call
+ * the completion function for the high level driver.
+ */
+
+ memcpy((void *) SRpnt->sr_cmnd, (const void *) cmnd,
+ sizeof(SRpnt->sr_cmnd));
+ SRpnt->sr_bufflen = bufflen;
+ SRpnt->sr_buffer = buffer;
+ SRpnt->sr_allowed = retries;
+ SRpnt->sr_done = done;
+ SRpnt->sr_timeout_per_command = timeout;
+
+ memcpy((void *) SRpnt->sr_cmnd, (const void *) cmnd,
+ sizeof(SRpnt->sr_cmnd));
+
+ if (SRpnt->sr_cmd_len == 0)
+ SRpnt->sr_cmd_len = COMMAND_SIZE(SRpnt->sr_cmnd[0]);
+
+ /*
+ * At this point, we merely set up the command, stick it in the normal
+ * request queue, and return. Eventually that request will come to the
+ * top of the list, and will be dispatched.
+ */
+ scsi_insert_special_req(SRpnt, 0);
+
+ SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n"));
+}
+
+/*
+ * Function: scsi_init_cmd_from_req
+ *
+ * Purpose: Queue a SCSI command
+ * Purpose: Initialize a Scsi_Cmnd from a Scsi_Request
+ *
+ * Arguments: SCpnt - command descriptor.
+ * SRpnt - Request from the queue.
+ *
+ * Lock status: None needed.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: Mainly transfer data from the request structure to the
+ * command structure. The request structure is allocated
+ * using the normal memory allocator, and requests can pile
+ * up to more or less any depth. The command structure represents
+ * a consumable resource, as these are allocated into a pool
+ * when the SCSI subsystem initializes. The preallocation is
+ * required so that in low-memory situations a disk I/O request
+ * won't cause the memory manager to try and write out a page.
+ * The request structure is generally used by ioctls and character
+ * devices.
+ */
+void scsi_init_cmd_from_req(Scsi_Cmnd * SCpnt, Scsi_Request * SRpnt)
+{
+ struct Scsi_Host *host = SCpnt->host;
+
+ ASSERT_LOCK(&io_request_lock, 0);
+
+ SCpnt->owner = SCSI_OWNER_MIDLEVEL;
+ SRpnt->sr_command = SCpnt;
+
+ if (!host) {
+ panic("Invalid or not present host.\n");
+ }
+
+ SCpnt->cmd_len = SRpnt->sr_cmd_len;
+ SCpnt->use_sg = SRpnt->sr_use_sg;
+
+ memcpy((void *) &SCpnt->request, (const void *) &SRpnt->sr_request,
+ sizeof(SRpnt->sr_request));
+ memcpy((void *) SCpnt->data_cmnd, (const void *) SRpnt->sr_cmnd,
+ sizeof(SCpnt->data_cmnd));
+ SCpnt->reset_chain = NULL;
+ SCpnt->serial_number = 0;
+ SCpnt->serial_number_at_timeout = 0;
+ SCpnt->bufflen = SRpnt->sr_bufflen;
+ SCpnt->buffer = SRpnt->sr_buffer;
+ SCpnt->flags = 0;
+ SCpnt->retries = 0;
+ SCpnt->allowed = SRpnt->sr_allowed;
+ SCpnt->done = SRpnt->sr_done;
+ SCpnt->timeout_per_command = SRpnt->sr_timeout_per_command;
+
+ SCpnt->sc_data_direction = SRpnt->sr_data_direction;
+
+ SCpnt->sglist_len = SRpnt->sr_sglist_len;
+ SCpnt->underflow = SRpnt->sr_underflow;
+
+ SCpnt->sc_request = SRpnt;
+
+ memcpy((void *) SCpnt->cmnd, (const void *) SRpnt->sr_cmnd,
+ sizeof(SCpnt->cmnd));
+ /* Zero the sense buffer. Some host adapters automatically request
+ * sense on error. 0 is not a valid sense code.
+ */
+ memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
+ SCpnt->request_buffer = SRpnt->sr_buffer;
+ SCpnt->request_bufflen = SRpnt->sr_bufflen;
+ SCpnt->old_use_sg = SCpnt->use_sg;
+ if (SCpnt->cmd_len == 0)
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ SCpnt->old_cmd_len = SCpnt->cmd_len;
+ SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
+
+ /* Start the timer ticking. */
+
+ SCpnt->internal_timeout = NORMAL_TIMEOUT;
+ SCpnt->abort_reason = 0;
+ SCpnt->result = 0;
+
+ SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n"));
+}
+
/*
* Function: scsi_do_cmd
*
@@ -737,6 +1027,7 @@ void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd,
if (SCpnt->cmd_len == 0)
SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
SCpnt->old_cmd_len = SCpnt->cmd_len;
+ SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
/* Start the timer ticking. */
@@ -996,6 +1287,7 @@ int scsi_retry_command(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
/*
* Zero the sense information from the last time we tried
@@ -1017,6 +1309,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
{
struct Scsi_Host *host;
Scsi_Device *device;
+ Scsi_Request * SRpnt;
unsigned long flags;
ASSERT_LOCK(&io_request_lock, 0);
@@ -1061,6 +1354,20 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
/* We can get here with use_sg=0, causing a panic in the upper level (DB) */
SCpnt->use_sg = SCpnt->old_use_sg;
+ /*
+ * If there is an associated request structure, copy the data over before we call the
+ * completion function.
+ */
+ SRpnt = SCpnt->sc_request;
+ if( SRpnt != NULL ) {
+ SRpnt->sr_result = SRpnt->sr_command->result;
+ if( SRpnt->sr_result != 0 ) {
+ memcpy(SRpnt->sr_sense_buffer,
+ SRpnt->sr_command->sense_buffer,
+ sizeof(SRpnt->sr_sense_buffer));
+ }
+ }
+
SCpnt->done(SCpnt);
}
@@ -1096,6 +1403,7 @@ void scsi_release_commandblocks(Scsi_Device * SDpnt)
kfree((char *) SCpnt);
}
SDpnt->has_cmdblocks = 0;
+ SDpnt->queue_depth = 0;
spin_unlock_irqrestore(&device_request_lock, flags);
}
@@ -1168,7 +1476,39 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt)
static int proc_scsi_gen_write(struct file * file, const char * buf,
unsigned long length, void *data);
+void __init scsi_host_no_insert(char *str, int n)
+{
+ Scsi_Host_Name *shn, *shn2;
+ int len;
+
+ len = strlen(str);
+ if (len && (shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC))) {
+ if ((shn->name = kmalloc(len+1, GFP_ATOMIC))) {
+ strncpy(shn->name, str, len);
+ shn->name[len] = 0;
+ shn->host_no = n;
+ shn->host_registered = 0;
+ shn->loaded_as_module = 1; /* numbers shouldn't be freed in any case */
+ shn->next = NULL;
+ if (scsi_host_no_list) {
+ for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
+ ;
+ shn2->next = shn;
+ }
+ else
+ scsi_host_no_list = shn;
+ max_scsi_hosts = n+1;
+ }
+ else
+ kfree((char *) shn);
+ }
+}
+
#ifndef MODULE /* { */
+
+char scsi_host_no_table[20][10] __initdata = {};
+int scsi_host_no_set __initdata = 0;
+
/*
* scsi_dev_init() is our initialization routine, which in turn calls host
* initialization, bus scanning, and sd/st initialization routines.
@@ -1184,8 +1524,16 @@ int __init scsi_dev_init(void)
return;
#endif
+ /* Initialize list of host_no if kernel parameter set */
+ if (scsi_host_no_set) {
+ int i;
+ for (i = 0;i < sizeof(scsi_host_no_table)/sizeof(scsi_host_no_table[0]);i++)
+ scsi_host_no_insert(scsi_host_no_table[i], i);
+ }
+
/* Yes we're here... */
+ scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", 4, NULL);
/*
* This makes /proc/scsi and /proc/scsi/scsi visible.
*/
@@ -1535,6 +1883,7 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
* Nobody is using this device any more.
* Free all of the command structures.
*/
+ devfs_unregister (scd->de);
scsi_release_commandblocks(scd);
/* Now we can remove the device structure */
@@ -1834,6 +2183,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
printk("Attached usage count = %d\n", SDpnt->attached);
return;
}
+ devfs_unregister (SDpnt->de);
}
}
@@ -2143,11 +2493,12 @@ static void scsi_dump_status(int level)
printk("Dump of scsi host parameters:\n");
i = 0;
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
- printk(" %d %d %d : %d\n",
+ printk(" %d %d %d : %d %d\n",
shpnt->host_failed,
shpnt->host_busy,
atomic_read(&shpnt->host_active),
- shpnt->host_blocked);
+ shpnt->host_blocked,
+ shpnt->host_self_blocked);
}
@@ -2193,19 +2544,24 @@ static void scsi_dump_status(int level)
/* Now dump the request lists for each block device */
printk("Dump of pending block device requests\n");
for (i = 0; i < MAX_BLKDEV; i++) {
- if (blk_dev[i].request_queue.current_request) {
+ struct list_head * queue_head;
+
+ queue_head = &blk_dev[i].request_queue.queue_head;
+ if (!list_empty(queue_head)) {
struct request *req;
+ struct list_head * entry;
+
printk("%d: ", i);
- req = blk_dev[i].request_queue.current_request;
- while (req) {
+ entry = queue_head->next;
+ do {
+ req = blkdev_entry_to_request(entry);
printk("(%s %d %ld %ld %ld) ",
kdevname(req->rq_dev),
req->cmd,
req->sector,
req->nr_sectors,
req->current_nr_sectors);
- req = req->next;
- }
+ } while ((entry = entry->next) != queue_head);
printk("\n");
}
}
@@ -2216,12 +2572,52 @@ static void scsi_dump_status(int level)
}
#endif /* CONFIG_PROC_FS */
+static int scsi_host_no_init (char *str)
+{
+ static int next_no = 0;
+ char *temp;
+
+#ifndef MODULE
+ int len;
+ scsi_host_no_set = 1;
+ memset(scsi_host_no_table, 0, sizeof(scsi_host_no_table));
+#endif /* MODULE */
+
+ while (str) {
+ temp = str;
+ while (*temp && (*temp != ':') && (*temp != ','))
+ temp++;
+ if (!*temp)
+ temp = NULL;
+ else
+ *temp++ = 0;
+#ifdef MODULE
+ scsi_host_no_insert(str, next_no);
+#else
+ if (next_no < sizeof(scsi_host_no_table)/sizeof(scsi_host_no_table[0])) {
+ if ((len = strlen(str)) >= sizeof(scsi_host_no_table[0]))
+ len = sizeof(scsi_host_no_table[0])-1;
+ strncpy(scsi_host_no_table[next_no], str, len);
+ scsi_host_no_table[next_no][len] = 0;
+ }
+#endif /* MODULE */
+ str = temp;
+ next_no++;
+ }
+ return 1;
+}
+
+#ifndef MODULE
+__setup("scsihosts=", scsi_host_no_init);
+#endif
+
#ifdef MODULE
+static char *scsihosts;
+
+MODULE_PARM(scsihosts, "s");
int init_module(void)
{
- unsigned long size;
- int has_space = 0;
struct proc_dir_entry *generic;
if( scsi_init_minimal_dma_pool() != 0 )
@@ -2249,6 +2645,8 @@ int init_module(void)
scsi_loadable_module_flag = 1;
+ scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", 4, NULL);
+ scsi_host_no_init (scsihosts);
/*
* This is where the processing takes place for most everything
* when commands are completed.
@@ -2260,8 +2658,21 @@ int init_module(void)
void cleanup_module(void)
{
+ Scsi_Host_Name *shn, *shn2 = NULL;
+
remove_bh(SCSI_BH);
+ devfs_unregister (scsi_devfs_handle);
+ for (shn = scsi_host_no_list;shn;shn = shn->next) {
+ if (shn->name)
+ kfree(shn->name);
+ if (shn2)
+ kfree (shn2);
+ shn2 = shn;
+ }
+ if (shn2)
+ kfree (shn2);
+
#ifdef CONFIG_PROC_FS
/* No, we're not here anymore. Don't show the /proc/scsi files. */
remove_proc_entry ("scsi/scsi", 0);
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index df294f2e4..7a073f86e 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -16,6 +16,7 @@
#define _SCSI_H
#include <linux/config.h> /* for CONFIG_SCSI_LOGGING */
+#include <linux/devfs_fs_kernel.h>
#include <linux/proc_fs.h>
/*
@@ -31,6 +32,54 @@
#include <asm/io.h>
/*
+ * These are the values that the SCpnt->sc_data_direction and
+ * SRpnt->sr_data_direction can take. These need to be set
+ * The SCSI_DATA_UNKNOWN value is essentially the default.
+ * In the event that the command creator didn't bother to
+ * set a value, you will see SCSI_DATA_UNKNOWN.
+ */
+#define SCSI_DATA_UNKNOWN 0
+#define SCSI_DATA_WRITE 1
+#define SCSI_DATA_READ 2
+#define SCSI_DATA_NONE 3
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#if ((SCSI_DATA_UNKNOWN == PCI_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == PCI_DMA_TODEVICE) && (SCSI_DATA_READ == PCI_DMA_FROMDEVICE) && (SCSI_DATA_NONE == PCI_DMA_NONE))
+#define scsi_to_pci_dma_dir(scsi_dir) ((int)(scsi_dir))
+#else
+extern __inline__ int scsi_to_pci_dma_dir(unsigned char scsi_dir)
+{
+ if (scsi_dir == SCSI_DATA_UNKNOWN)
+ return PCI_DMA_BIDIRECTIONAL;
+ if (scsi_dir == SCSI_DATA_WRITE)
+ return PCI_DMA_TODEVICE;
+ if (scsi_dir == SCSI_DATA_READ)
+ return PCI_DMA_FROMDEVICE;
+ return PCI_DMA_NONE;
+}
+#endif
+#endif
+
+#ifdef CONFIG_SBUS
+#include <asm/sbus.h>
+#if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE))
+#define scsi_to_sbus_dma_dir(scsi_dir) ((int)(scsi_dir))
+#else
+extern __inline__ int scsi_to_sbus_dma_dir(unsigned char scsi_dir)
+{
+ if (scsi_dir == SCSI_DATA_UNKNOWN)
+ return SBUS_DMA_BIDIRECTIONAL;
+ if (scsi_dir == SCSI_DATA_WRITE)
+ return SBUS_DMA_TODEVICE;
+ if (scsi_dir == SCSI_DATA_READ)
+ return SBUS_DMA_FROMDEVICE;
+ return SBUS_DMA_NONE;
+}
+#endif
+#endif
+
+/*
* Some defs, in case these are not defined elsewhere.
*/
#ifndef TRUE
@@ -303,6 +352,7 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
#define SUGGEST_MASK 0xf0
#define MAX_COMMAND_SIZE 12
+#define SCSI_SENSE_BUFFERSIZE 64
/*
* SCSI command sets
@@ -356,6 +406,10 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
*/
typedef struct scsi_device Scsi_Device;
typedef struct scsi_cmnd Scsi_Cmnd;
+typedef struct scsi_request Scsi_Request;
+
+#define SCSI_CMND_MAGIC 0xE25C23A5
+#define SCSI_REQ_MAGIC 0x75F6D354
/*
* Here is where we prototype most of the mid-layer.
@@ -444,10 +498,25 @@ extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd,
void (*done) (struct scsi_cmnd *),
int timeout, int retries);
extern void scsi_wait_cmd(Scsi_Cmnd *, const void *cmnd,
+ void *buffer, unsigned bufflen,
+ int timeout, int retries);
+extern int scsi_dev_init(void);
+
+/*
+ * Newer request-based interfaces.
+ */
+extern Scsi_Request *scsi_allocate_request(Scsi_Device *);
+extern void scsi_release_request(Scsi_Request *);
+extern void scsi_wait_req(Scsi_Request *, const void *cmnd,
void *buffer, unsigned bufflen,
int timeout, int retries);
-extern int scsi_dev_init(void);
+extern void scsi_do_req(Scsi_Request *, const void *cmnd,
+ void *buffer, unsigned bufflen,
+ void (*done) (struct scsi_cmnd *),
+ int timeout, int retries);
+extern int scsi_insert_special_req(Scsi_Request * SRpnt, int);
+extern void scsi_init_cmd_from_req(Scsi_Cmnd *, Scsi_Request *);
/*
@@ -466,6 +535,7 @@ extern struct proc_dir_entry *proc_scsi;
*/
extern void print_command(unsigned char *);
extern void print_sense(const char *, Scsi_Cmnd *);
+extern void print_req_sense(const char *, Scsi_Request *);
extern void print_driverbyte(int scsiresult);
extern void print_hostbyte(int scsiresult);
extern void print_status (int status);
@@ -512,6 +582,7 @@ struct scsi_device {
int access_count; /* Count of open channels/mounts */
void *hostdata; /* available to low-level driver */
+ devfs_handle_t de; /* directory for the device */
char type;
char scsi_level;
char vendor[8], model[16], rev[4];
@@ -568,6 +639,39 @@ typedef struct scsi_pointer {
volatile int phase;
} Scsi_Pointer;
+/*
+ * This is essentially a slimmed down version of Scsi_Cmnd. The point of
+ * having this is that requests that are injected into the queue as result
+ * of things like ioctls and character devices shouldn't be using a
+ * Scsi_Cmnd until such a time that the command is actually at the head
+ * of the queue and being sent to the driver.
+ */
+struct scsi_request {
+ int sr_magic;
+ int sr_result; /* Status code from lower level driver */
+ unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE
+ * when CHECK CONDITION is
+ * received on original command
+ * (auto-sense) */
+
+ struct Scsi_Host *sr_host;
+ Scsi_Device *sr_device;
+ Scsi_Cmnd *sr_command;
+ struct request sr_request; /* A copy of the command we are
+ working on */
+ unsigned sr_bufflen; /* Size of data buffer */
+ void *sr_buffer; /* Data buffer */
+ int sr_allowed;
+ unsigned char sr_data_direction;
+ unsigned char sr_cmd_len;
+ unsigned char sr_cmnd[MAX_COMMAND_SIZE];
+ void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */
+ int sr_timeout_per_command;
+ unsigned short sr_use_sg; /* Number of pieces of scatter-gather */
+ unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */
+ unsigned sr_underflow; /* Return error if less than
+ this amount is transfered */
+};
/*
* FIXME(eric) - one of the great regrets that I have is that I failed to define
@@ -578,6 +682,7 @@ typedef struct scsi_pointer {
* go back and retrofit at least some of the elements here with with the prefix.
*/
struct scsi_cmnd {
+ int sc_magic;
/* private: */
/*
* This information is private to the scsi mid-layer. Wrapping it in a
@@ -587,6 +692,7 @@ struct scsi_cmnd {
unsigned short state;
unsigned short owner;
Scsi_Device *device;
+ Scsi_Request *sc_request;
struct scsi_cmnd *next;
struct scsi_cmnd *reset_chain;
@@ -630,6 +736,8 @@ struct scsi_cmnd {
unsigned char channel;
unsigned char cmd_len;
unsigned char old_cmd_len;
+ unsigned char sc_data_direction;
+ unsigned char sc_old_data_direction;
/* These elements define the operation we are about to perform */
unsigned char cmnd[MAX_COMMAND_SIZE];
@@ -665,7 +773,7 @@ struct scsi_cmnd {
struct request request; /* A copy of the command we are
working on */
- unsigned char sense_buffer[64]; /* obtained by REQUEST SENSE
+ unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE
* when CHECK CONDITION is
* received on original command
* (auto-sense) */
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 773dc0087..7268bc154 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -408,6 +408,7 @@ STATIC int scsi_eh_retry_command(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command);
@@ -464,6 +465,7 @@ STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = 256;
SCpnt->use_sg = 0;
SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
@@ -486,6 +488,7 @@ STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
/*
* Hey, we are done. Let's look to see what happened.
@@ -531,6 +534,7 @@ STATIC int scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
SCpnt->use_sg = 0;
SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+ SCpnt->sc_data_direction = SCSI_DATA_NONE;
/* Last chance to have valid sense data */
if (!scsi_sense_valid(SCpnt))
@@ -551,6 +555,7 @@ STATIC int scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
/*
* Hey, we are done. Let's look to see what happened.
@@ -730,6 +735,7 @@ STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt)
* things.
*/
SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
*SClist = SCpnt;
}
@@ -1245,6 +1251,7 @@ STATIC void scsi_restart_operations(struct Scsi_Host *host)
request_queue_t *q;
if ((host->can_queue > 0 && (host->host_busy >= host->can_queue))
|| (host->host_blocked)
+ || (host->host_self_blocked)
|| (SDpnt->device_blocked)) {
break;
}
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 56ad67646..abdef85ef 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -105,6 +105,7 @@ static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
return -EINTR;
}
+ SCpnt->sc_data_direction = SCSI_DATA_NONE;
scsi_wait_cmd(SCpnt, cmd, NULL, 0, timeout, retries);
SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SCpnt->result));
@@ -197,6 +198,7 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
int inlen, outlen, cmdlen;
int needed, buf_needed;
int timeout, retries, result;
+ int data_direction;
if (!sic)
return -EINVAL;
@@ -232,8 +234,21 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
if (!buf)
return -ENOMEM;
memset(buf, 0, buf_needed);
- } else
+ if( inlen == 0 ) {
+ data_direction = SCSI_DATA_WRITE;
+ } else if (outlen == 0 ) {
+ data_direction = SCSI_DATA_READ;
+ } else {
+ /*
+ * Can this ever happen?
+ */
+ data_direction = SCSI_DATA_UNKNOWN;
+ }
+
+ } else {
buf = NULL;
+ data_direction = SCSI_DATA_NONE;
+ }
/*
* Obtain the command from the user's address space.
@@ -288,6 +303,7 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
return -EINTR;
}
+ SCpnt->sc_data_direction = data_direction;
scsi_wait_cmd(SCpnt, cmd, buf, needed, timeout, retries);
/*
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 9ec2fe281..2438aecc6 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -86,6 +86,7 @@ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head)
q = &SCpnt->device->request_queue;
SCpnt->request.cmd = SPECIAL;
SCpnt->request.special = (void *) SCpnt;
+ SCpnt->request.q = NULL;
/*
* We have the option of inserting the head or the tail of the queue.
@@ -96,8 +97,7 @@ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head)
spin_lock_irqsave(&io_request_lock, flags);
if (at_head) {
- SCpnt->request.next = q->current_request;
- q->current_request = &SCpnt->request;
+ list_add(&SCpnt->request.queue, &q->queue_head);
} else {
/*
* FIXME(eric) - we always insert at the tail of the
@@ -107,19 +107,75 @@ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head)
* request might not float high enough in the queue
* to be scheduled.
*/
- SCpnt->request.next = NULL;
- if (q->current_request == NULL) {
- q->current_request = &SCpnt->request;
- } else {
- struct request *req;
+ list_add_tail(&SCpnt->request.queue, &q->queue_head);
+ }
- for (req = q->current_request; req; req = req->next) {
- if (req->next == NULL) {
- req->next = &SCpnt->request;
- break;
- }
- }
- }
+ /*
+ * Now hit the requeue function for the queue. If the host is
+ * already busy, so be it - we have nothing special to do. If
+ * the host can queue it, then send it off.
+ */
+ q->request_fn(q);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return 0;
+}
+
+/*
+ * Function: scsi_insert_special_req()
+ *
+ * Purpose: Insert pre-formed request into request queue.
+ *
+ * Arguments: SRpnt - request that is ready to be queued.
+ * at_head - boolean. True if we should insert at head
+ * of queue, false if we should insert at tail.
+ *
+ * Lock status: Assumed that lock is not held upon entry.
+ *
+ * Returns: Nothing
+ *
+ * Notes: This function is called from character device and from
+ * ioctl types of functions where the caller knows exactly
+ * what SCSI command needs to be issued. The idea is that
+ * we merely inject the command into the queue (at the head
+ * for now), and then call the queue request function to actually
+ * process it.
+ */
+int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head)
+{
+ unsigned long flags;
+ request_queue_t *q;
+
+ ASSERT_LOCK(&io_request_lock, 0);
+
+ /*
+ * The SCpnt already contains a request structure - we will doctor the
+ * thing up with the appropriate values and use that in the actual
+ * request queue.
+ */
+ q = &SRpnt->sr_device->request_queue;
+ SRpnt->sr_request.cmd = SPECIAL;
+ SRpnt->sr_request.special = (void *) SRpnt;
+
+ /*
+ * We have the option of inserting the head or the tail of the queue.
+ * Typically we use the tail for new ioctls and so forth. We use the
+ * head of the queue for things like a QUEUE_FULL message from a
+ * device, or a host that is unable to accept a particular command.
+ */
+ spin_lock_irqsave(&io_request_lock, flags);
+
+ if (at_head) {
+ list_add(&SRpnt->sr_request.queue, &q->queue_head);
+ } else {
+ /*
+ * FIXME(eric) - we always insert at the tail of the
+ * list. Otherwise ioctl commands would always take
+ * precedence over normal I/O. An ioctl on a busy
+ * disk might be delayed indefinitely because the
+ * request might not float high enough in the queue
+ * to be scheduled.
+ */
+ list_add_tail(&SRpnt->sr_request.queue, &q->queue_head);
}
/*
@@ -172,6 +228,7 @@ int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt)
*/
SCpnt->old_use_sg = SCpnt->use_sg;
SCpnt->old_cmd_len = SCpnt->cmd_len;
+ SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
memcpy((void *) SCpnt->data_cmnd,
(const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd));
SCpnt->buffer = SCpnt->request_buffer;
@@ -239,9 +296,8 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
* in which case we need to request the blocks that come after
* the bad sector.
*/
- SCpnt->request.next = q->current_request;
- q->current_request = &SCpnt->request;
SCpnt->request.special = (void *) SCpnt;
+ list_add(&SCpnt->request.queue, &q->queue_head);
}
/*
@@ -260,7 +316,7 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
* use function pointers to pick the right one.
*/
if (SDpnt->single_lun
- && q->current_request == NULL
+ && list_empty(&q->queue_head)
&& SDpnt->device_busy == 0) {
request_queue_t *q;
@@ -270,6 +326,7 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
if (((SHpnt->can_queue > 0)
&& (SHpnt->host_busy >= SHpnt->can_queue))
|| (SHpnt->host_blocked)
+ || (SHpnt->host_self_blocked)
|| (SDpnt->device_blocked)) {
break;
}
@@ -291,7 +348,8 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
request_queue_t *q;
if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
- || (SHpnt->host_blocked)) {
+ || (SHpnt->host_blocked)
+ || (SHpnt->host_self_blocked)) {
break;
}
if (SDpnt->device_blocked || !SDpnt->starved) {
@@ -772,6 +830,7 @@ void scsi_request_fn(request_queue_t * q)
{
struct request *req;
Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
Scsi_Device *SDpnt;
struct Scsi_Host *SHpnt;
struct Scsi_Device_Template *STpnt;
@@ -802,13 +861,24 @@ void scsi_request_fn(request_queue_t * q)
*/
while (1 == 1) {
/*
+ * Check this again - each time we loop through we will have
+ * released the lock and grabbed it again, so each time
+ * we need to check to see if the queue is plugged or not.
+ */
+ if (SHpnt->in_recovery
+ || q->plugged) {
+ return;
+ }
+
+ /*
* If the device cannot accept another request, then quit.
*/
if (SDpnt->device_blocked) {
break;
}
if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
- || (SHpnt->host_blocked)) {
+ || (SHpnt->host_blocked)
+ || (SHpnt->host_self_blocked)) {
/*
* If we are unable to process any commands at all for this
* device, then we consider it to be starved. What this means
@@ -850,18 +920,18 @@ void scsi_request_fn(request_queue_t * q)
}
/*
- * Loop through all of the requests in this queue, and find
- * one that is queueable.
- */
- req = q->current_request;
-
- /*
* If we couldn't find a request that could be queued, then we
* can also quit.
*/
- if (!req) {
+ if (list_empty(&q->queue_head))
break;
- }
+
+ /*
+ * Loop through all of the requests in this queue, and find
+ * one that is queueable.
+ */
+ req = blkdev_entry_next_request(&q->queue_head);
+
/*
* Find the actual device driver associated with this command.
* The SPECIAL requests are things like character device or
@@ -875,6 +945,14 @@ void scsi_request_fn(request_queue_t * q)
if (req->cmd == SPECIAL) {
STpnt = NULL;
SCpnt = (Scsi_Cmnd *) req->special;
+ SRpnt = (Scsi_Request *) req->special;
+
+ if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) {
+ SCpnt = scsi_allocate_device(SRpnt->sr_device,
+ FALSE, FALSE);
+ scsi_init_cmd_from_req(SCpnt, SRpnt);
+ }
+
} else {
STpnt = scsi_get_request_dev(req);
if (!STpnt) {
@@ -922,8 +1000,7 @@ void scsi_request_fn(request_queue_t * q)
* reason to search the list, because all of the commands
* in this queue are for the same device.
*/
- q->current_request = req->next;
- SCpnt->request.next = NULL;
+ blkdev_dequeue_request(req);
if (req != &SCpnt->request) {
memcpy(&SCpnt->request, req, sizeof(struct request));
@@ -932,7 +1009,6 @@ void scsi_request_fn(request_queue_t * q)
* We have copied the data out of the request block - it is now in
* a field in SCpnt. Release the request block.
*/
- req->next = NULL;
req->rq_status = RQ_INACTIVE;
wake_up(&wait_for_request);
}
@@ -1005,6 +1081,85 @@ void scsi_request_fn(request_queue_t * q)
}
/*
+ * Function: scsi_block_requests()
+ *
+ * Purpose: Utility function used by low-level drivers to prevent further
+ * commands from being queued to the device.
+ *
+ * Arguments: SHpnt - Host in question
+ *
+ * Returns: Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes: There is no timer nor any other means by which the requests
+ * get unblocked other than the low-level driver calling
+ * scsi_unblock_requests().
+ */
+void scsi_block_requests(struct Scsi_Host * SHpnt)
+{
+ SHpnt->host_self_blocked = TRUE;
+}
+
+/*
+ * Function: scsi_unblock_requests()
+ *
+ * Purpose: Utility function used by low-level drivers to allow further
+ * commands from being queued to the device.
+ *
+ * Arguments: SHpnt - Host in question
+ *
+ * Returns: Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes: There is no timer nor any other means by which the requests
+ * get unblocked other than the low-level driver calling
+ * scsi_unblock_requests().
+ *
+ * This is done as an API function so that changes to the
+ * internals of the scsi mid-layer won't require wholesale
+ * changes to drivers that use this feature.
+ */
+void scsi_unblock_requests(struct Scsi_Host * SHpnt)
+{
+ SHpnt->host_self_blocked = FALSE;
+}
+
+
+/*
+ * Function: scsi_report_bus_reset()
+ *
+ * Purpose: Utility function used by low-level drivers to report that
+ * they have observed a bus reset on the bus being handled.
+ *
+ * Arguments: SHpnt - Host in question
+ * channel - channel on which reset was observed.
+ *
+ * Returns: Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes: This only needs to be called if the reset is one which
+ * originates from an unknown location. Resets originated
+ * by the mid-level itself don't need to call this, but there
+ * should be no harm.
+ *
+ * The main purpose of this is to make sure that a CHECK_CONDITION
+ * is properly treated.
+ */
+void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel)
+{
+ Scsi_Device *SDloop;
+ for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) {
+ if (channel == SDloop->channel) {
+ SDloop->was_reset = 1;
+ SDloop->expecting_cc_ua = 1;
+ }
+ }
+}
+
+/*
* FIXME(eric) - these are empty stubs for the moment. I need to re-implement
* host blocking from scratch. The theory is that hosts that wish to block
* will register/deregister using these functions instead of the old way
diff --git a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c
index c9a1edb60..d917d9306 100644
--- a/drivers/scsi/scsi_merge.c
+++ b/drivers/scsi/scsi_merge.c
@@ -307,6 +307,69 @@ recount_segments(Scsi_Cmnd * SCpnt)
(((((long)(X)->b_data+(X)->b_size)|((long)(Y)->b_data)) & \
(DMA_CHUNK_SIZE - 1)) == 0)
+#ifdef DMA_CHUNK_SIZE
+static inline int scsi_new_mergeable(request_queue_t * q,
+ struct request * req,
+ struct Scsi_Host *SHpnt,
+ int max_segments)
+{
+ /*
+ * pci_map_sg will be able to merge these two
+ * into a single hardware sg entry, check if
+ * we'll have enough memory for the sg list.
+ * scsi.c allocates for this purpose
+ * min(64,sg_tablesize) entries.
+ */
+ if (req->nr_segments >= max_segments &&
+ req->nr_segments >= SHpnt->sg_tablesize)
+ return 0;
+ req->nr_segments++;
+ q->nr_segments++;
+ return 1;
+}
+
+static inline int scsi_new_segment(request_queue_t * q,
+ struct request * req,
+ struct Scsi_Host *SHpnt,
+ int max_segments)
+{
+ /*
+ * pci_map_sg won't be able to map these two
+ * into a single hardware sg entry, so we have to
+ * check if things fit into sg_tablesize.
+ */
+ if (req->nr_hw_segments >= SHpnt->sg_tablesize ||
+ (req->nr_segments >= max_segments &&
+ req->nr_segments >= SHpnt->sg_tablesize))
+ return 0;
+ if (req->nr_segments >= max_segments)
+ return 0;
+ req->nr_hw_segments++;
+ req->nr_segments++;
+ q->nr_segments++;
+ return 1;
+}
+#else
+static inline int scsi_new_segment(request_queue_t * q,
+ struct request * req,
+ struct Scsi_Host *SHpnt,
+ int max_segments)
+{
+ if (req->nr_segments < SHpnt->sg_tablesize &&
+ req->nr_segments < max_segments) {
+ /*
+ * This will form the start of a new segment. Bump the
+ * counter.
+ */
+ req->nr_segments++;
+ q->nr_segments++;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+#endif
+
/*
* Function: __scsi_merge_fn()
*
@@ -340,13 +403,14 @@ recount_segments(Scsi_Cmnd * SCpnt)
* than to have 4 separate functions all doing roughly the
* same thing.
*/
-__inline static int __scsi_merge_fn(request_queue_t * q,
- struct request *req,
- struct buffer_head *bh,
- int use_clustering,
- int dma_host)
+__inline static int __scsi_back_merge_fn(request_queue_t * q,
+ struct request *req,
+ struct buffer_head *bh,
+ int max_segments,
+ int use_clustering,
+ int dma_host)
{
- unsigned int sector, count;
+ unsigned int count;
unsigned int segment_size = 0;
Scsi_Device *SDpnt;
struct Scsi_Host *SHpnt;
@@ -354,130 +418,97 @@ __inline static int __scsi_merge_fn(request_queue_t * q,
SDpnt = (Scsi_Device *) q->queuedata;
SHpnt = SDpnt->host;
- count = bh->b_size >> 9;
- sector = bh->b_rsector;
+ if (max_segments > 64)
+ max_segments = 64;
- /*
- * We come in here in one of two cases. The first is that we
- * are checking to see if we can add the buffer to the end of the
- * request, the other is to see if we should add the request to the
- * start.
- */
- if (req->sector + req->nr_sectors == sector) {
- if (use_clustering) {
- /*
- * See if we can do this without creating another
- * scatter-gather segment. In the event that this is a
- * DMA capable host, make sure that a segment doesn't span
- * the DMA threshold boundary.
- */
- if (dma_host &&
- virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) {
- goto new_end_segment;
- }
- if (CONTIGUOUS_BUFFERS(req->bhtail, bh)) {
+ if (use_clustering) {
+ /*
+ * See if we can do this without creating another
+ * scatter-gather segment. In the event that this is a
+ * DMA capable host, make sure that a segment doesn't span
+ * the DMA threshold boundary.
+ */
+ if (dma_host &&
+ virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) {
+ goto new_end_segment;
+ }
+ if (CONTIGUOUS_BUFFERS(req->bhtail, bh)) {
#ifdef DMA_SEGMENT_SIZE_LIMITED
- if( dma_host
- && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
- segment_size = 0;
- count = __count_segments(req, use_clustering, dma_host, &segment_size);
- if( segment_size + bh->b_size > PAGE_SIZE ) {
- goto new_end_segment;
- }
+ if( dma_host
+ && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
+ segment_size = 0;
+ count = __count_segments(req, use_clustering, dma_host, &segment_size);
+ if( segment_size + bh->b_size > PAGE_SIZE ) {
+ goto new_end_segment;
}
-#endif
- /*
- * This one is OK. Let it go.
- */
- return 1;
}
+#endif
+ /*
+ * This one is OK. Let it go.
+ */
+ return 1;
}
- new_end_segment:
+ }
+ new_end_segment:
#ifdef DMA_CHUNK_SIZE
- if (MERGEABLE_BUFFERS(req->bhtail, bh))
- goto new_mergeable;
+ if (MERGEABLE_BUFFERS(req->bhtail, bh))
+ return scsi_new_mergeable(q, req, SHpnt, max_segments);
#endif
- goto new_segment;
- } else {
- if (req->sector - count != sector) {
- /* Attempt to merge sector that doesn't belong */
- BUG();
+ return scsi_new_segment(q, req, SHpnt, max_segments);
+}
+
+__inline static int __scsi_front_merge_fn(request_queue_t * q,
+ struct request *req,
+ struct buffer_head *bh,
+ int max_segments,
+ int use_clustering,
+ int dma_host)
+{
+ unsigned int count;
+ unsigned int segment_size = 0;
+ Scsi_Device *SDpnt;
+ struct Scsi_Host *SHpnt;
+
+ SDpnt = (Scsi_Device *) q->queuedata;
+ SHpnt = SDpnt->host;
+
+ if (max_segments > 64)
+ max_segments = 64;
+
+ if (use_clustering) {
+ /*
+ * See if we can do this without creating another
+ * scatter-gather segment. In the event that this is a
+ * DMA capable host, make sure that a segment doesn't span
+ * the DMA threshold boundary.
+ */
+ if (dma_host &&
+ virt_to_phys(bh->b_data) - 1 == ISA_DMA_THRESHOLD) {
+ goto new_start_segment;
}
- if (use_clustering) {
- /*
- * See if we can do this without creating another
- * scatter-gather segment. In the event that this is a
- * DMA capable host, make sure that a segment doesn't span
- * the DMA threshold boundary.
- */
- if (dma_host &&
- virt_to_phys(bh->b_data) - 1 == ISA_DMA_THRESHOLD) {
- goto new_start_segment;
- }
- if (CONTIGUOUS_BUFFERS(bh, req->bh)) {
+ if (CONTIGUOUS_BUFFERS(bh, req->bh)) {
#ifdef DMA_SEGMENT_SIZE_LIMITED
- if( dma_host
- && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
- segment_size = bh->b_size;
- count = __count_segments(req, use_clustering, dma_host, &segment_size);
- if( count != req->nr_segments ) {
- goto new_start_segment;
- }
+ if( dma_host
+ && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
+ segment_size = bh->b_size;
+ count = __count_segments(req, use_clustering, dma_host, &segment_size);
+ if( count != req->nr_segments ) {
+ goto new_start_segment;
}
-#endif
- /*
- * This one is OK. Let it go.
- */
- return 1;
}
- }
- new_start_segment:
-#ifdef DMA_CHUNK_SIZE
- if (MERGEABLE_BUFFERS(bh, req->bh))
- goto new_mergeable;
#endif
- goto new_segment;
+ /*
+ * This one is OK. Let it go.
+ */
+ return 1;
+ }
}
+ new_start_segment:
#ifdef DMA_CHUNK_SIZE
- new_mergeable:
- /*
- * pci_map_sg will be able to merge these two
- * into a single hardware sg entry, check if
- * we'll have enough memory for the sg list.
- * scsi.c allocates for this purpose
- * min(64,sg_tablesize) entries.
- */
- if (req->nr_segments >= 64 &&
- req->nr_segments >= SHpnt->sg_tablesize)
- return 0;
- req->nr_segments++;
- return 1;
- new_segment:
- /*
- * pci_map_sg won't be able to map these two
- * into a single hardware sg entry, so we have to
- * check if things fit into sg_tablesize.
- */
- if (req->nr_hw_segments >= SHpnt->sg_tablesize ||
- (req->nr_segments >= 64 &&
- req->nr_segments >= SHpnt->sg_tablesize))
- return 0;
- req->nr_hw_segments++;
- req->nr_segments++;
- return 1;
-#else
- new_segment:
- if (req->nr_segments < SHpnt->sg_tablesize) {
- /*
- * This will form the start of a new segment. Bump the
- * counter.
- */
- req->nr_segments++;
- return 1;
- } else {
- return 0;
- }
+ if (MERGEABLE_BUFFERS(bh, req->bh))
+ return scsi_new_mergeable(q, req, SHpnt, max_segments);
#endif
+ return scsi_new_segment(q, req, SHpnt, max_segments);
}
/*
@@ -497,23 +528,34 @@ __inline static int __scsi_merge_fn(request_queue_t * q,
* Notes: Optimized for different cases depending upon whether
* ISA DMA is in use and whether clustering should be used.
*/
-#define MERGEFCT(_FUNCTION, _CLUSTER, _DMA) \
-static int _FUNCTION(request_queue_t * q, \
- struct request * req, \
- struct buffer_head * bh) \
-{ \
- int ret; \
- SANITY_CHECK(req, _CLUSTER, _DMA); \
- ret = __scsi_merge_fn(q, req, bh, _CLUSTER, _DMA); \
- return ret; \
+#define MERGEFCT(_FUNCTION, _BACK_FRONT, _CLUSTER, _DMA) \
+static int _FUNCTION(request_queue_t * q, \
+ struct request * req, \
+ struct buffer_head * bh, \
+ int max_segments) \
+{ \
+ int ret; \
+ SANITY_CHECK(req, _CLUSTER, _DMA); \
+ ret = __scsi_ ## _BACK_FRONT ## _merge_fn(q, \
+ req, \
+ bh, \
+ max_segments, \
+ _CLUSTER, \
+ _DMA); \
+ return ret; \
}
/* Version with use_clustering 0 and dma_host 1 is not necessary,
* since the only use of dma_host above is protected by use_clustering.
*/
-MERGEFCT(scsi_merge_fn_, 0, 0)
-MERGEFCT(scsi_merge_fn_c, 1, 0)
-MERGEFCT(scsi_merge_fn_dc, 1, 1)
+MERGEFCT(scsi_back_merge_fn_, back, 0, 0)
+MERGEFCT(scsi_back_merge_fn_c, back, 1, 0)
+MERGEFCT(scsi_back_merge_fn_dc, back, 1, 1)
+
+MERGEFCT(scsi_front_merge_fn_, front, 0, 0)
+MERGEFCT(scsi_front_merge_fn_c, front, 1, 0)
+MERGEFCT(scsi_front_merge_fn_dc, front, 1, 1)
+
/*
* Function: __scsi_merge_requests_fn()
*
@@ -550,6 +592,7 @@ MERGEFCT(scsi_merge_fn_dc, 1, 1)
__inline static int __scsi_merge_requests_fn(request_queue_t * q,
struct request *req,
struct request *next,
+ int max_segments,
int use_clustering,
int dma_host)
{
@@ -559,11 +602,14 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
SDpnt = (Scsi_Device *) q->queuedata;
SHpnt = SDpnt->host;
+ if (max_segments > 64)
+ max_segments = 64;
+
#ifdef DMA_CHUNK_SIZE
/* If it would not fit into prepared memory space for sg chain,
* then don't allow the merge.
*/
- if (req->nr_segments + next->nr_segments - 1 > 64 &&
+ if (req->nr_segments + next->nr_segments - 1 > max_segments &&
req->nr_segments + next->nr_segments - 1 > SHpnt->sg_tablesize) {
return 0;
}
@@ -619,6 +665,7 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
* This one is OK. Let it go.
*/
req->nr_segments += next->nr_segments - 1;
+ q->nr_segments--;
#ifdef DMA_CHUNK_SIZE
req->nr_hw_segments += next->nr_hw_segments - 1;
#endif
@@ -627,7 +674,7 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
}
dont_combine:
#ifdef DMA_CHUNK_SIZE
- if (req->nr_segments + next->nr_segments > 64 &&
+ if (req->nr_segments + next->nr_segments > max_segments &&
req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) {
return 0;
}
@@ -650,7 +697,8 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
* Make sure we can fix something that is the sum of the two.
* A slightly stricter test than we had above.
*/
- if (req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) {
+ if (req->nr_segments + next->nr_segments > max_segments &&
+ req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) {
return 0;
} else {
/*
@@ -683,11 +731,12 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
#define MERGEREQFCT(_FUNCTION, _CLUSTER, _DMA) \
static int _FUNCTION(request_queue_t * q, \
struct request * req, \
- struct request * next) \
+ struct request * next, \
+ int max_segments) \
{ \
int ret; \
SANITY_CHECK(req, _CLUSTER, _DMA); \
- ret = __scsi_merge_requests_fn(q, req, next, _CLUSTER, _DMA); \
+ ret = __scsi_merge_requests_fn(q, req, next, max_segments, _CLUSTER, _DMA); \
return ret; \
}
@@ -1068,7 +1117,7 @@ void initialize_merge_fn(Scsi_Device * SDpnt)
* pick a new one.
*/
#if 0
- if (q->merge_fn != NULL)
+ if (q->back_merge_fn && q->front_merge_fn)
return;
#endif
/*
@@ -1083,19 +1132,23 @@ void initialize_merge_fn(Scsi_Device * SDpnt)
* rather than rely upon the default behavior of ll_rw_blk.
*/
if (!CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma == 0) {
- q->merge_fn = scsi_merge_fn_;
+ q->back_merge_fn = scsi_back_merge_fn_;
+ q->front_merge_fn = scsi_front_merge_fn_;
q->merge_requests_fn = scsi_merge_requests_fn_;
SDpnt->scsi_init_io_fn = scsi_init_io_v;
} else if (!CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma != 0) {
- q->merge_fn = scsi_merge_fn_;
+ q->back_merge_fn = scsi_back_merge_fn_;
+ q->front_merge_fn = scsi_front_merge_fn_;
q->merge_requests_fn = scsi_merge_requests_fn_;
SDpnt->scsi_init_io_fn = scsi_init_io_vd;
} else if (CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma == 0) {
- q->merge_fn = scsi_merge_fn_c;
+ q->back_merge_fn = scsi_back_merge_fn_c;
+ q->front_merge_fn = scsi_front_merge_fn_c;
q->merge_requests_fn = scsi_merge_requests_fn_c;
SDpnt->scsi_init_io_fn = scsi_init_io_vc;
} else if (CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma != 0) {
- q->merge_fn = scsi_merge_fn_dc;
+ q->back_merge_fn = scsi_back_merge_fn_dc;
+ q->front_merge_fn = scsi_front_merge_fn_dc;
q->merge_requests_fn = scsi_merge_requests_fn_dc;
SDpnt->scsi_init_io_fn = scsi_init_io_vdc;
}
diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c
index ee1041d88..a957a4c01 100644
--- a/drivers/scsi/scsi_obsolete.c
+++ b/drivers/scsi/scsi_obsolete.c
@@ -231,6 +231,8 @@ static void scsi_request_sense(Scsi_Cmnd * SCpnt)
SCpnt->use_sg = 0;
SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
SCpnt->result = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
+
/*
* Ugly, ugly. The newer interfaces all assume that the lock
* isn't held. Mustn't disappoint, or we deadlock the system.
@@ -374,6 +376,7 @@ void scsi_old_done(Scsi_Cmnd * SCpnt)
if (SCpnt->flags & WAS_SENSE) {
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
}
switch (host_byte(result)) {
case DID_OK:
@@ -633,6 +636,7 @@ void scsi_old_done(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
SCpnt->result = 0;
/*
* Ugly, ugly. The newer interfaces all
@@ -649,6 +653,7 @@ void scsi_old_done(Scsi_Cmnd * SCpnt)
}
if (status == CMD_FINISHED) {
+ Scsi_Request *SRpnt;
#ifdef DEBUG
printk("Calling done function - at address %p\n", SCpnt->done);
#endif
@@ -658,6 +663,7 @@ void scsi_old_done(Scsi_Cmnd * SCpnt)
SCpnt->result = result | ((exit & 0xff) << 24);
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
/*
* The upper layers assume the lock isn't held. We mustn't
* disappoint them. When the new error handling code is in
@@ -665,6 +671,16 @@ void scsi_old_done(Scsi_Cmnd * SCpnt)
* it isn't an issue.
*/
spin_unlock_irq(&io_request_lock);
+ SRpnt = SCpnt->sc_request;
+ if( SRpnt != NULL ) {
+ SRpnt->sr_result = SRpnt->sr_command->result;
+ if( SRpnt->sr_result != 0 ) {
+ memcpy(SRpnt->sr_sense_buffer,
+ SRpnt->sr_command->sense_buffer,
+ sizeof(SRpnt->sr_sense_buffer));
+ }
+ }
+
SCpnt->done(SCpnt);
spin_lock_irq(&io_request_lock);
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 645edb67c..40a7cb124 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -455,6 +455,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
int *sparse_lun, Scsi_Device ** SDpnt2,
struct Scsi_Host *shpnt, char *scsi_result)
{
+ char devname[64];
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
struct Scsi_Device_Template *sdtpnt;
Scsi_Device *SDtail, *SDpnt = *SDpnt2;
@@ -462,6 +463,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
int bflags, type = -1;
static int ghost_channel=-1, ghost_dev=-1;
int org_lun = lun;
+ extern devfs_handle_t scsi_devfs_handle;
SDpnt->host = shpnt;
SDpnt->id = dev;
@@ -500,6 +502,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
SCpnt->target = SDpnt->id;
SCpnt->lun = SDpnt->lun;
SCpnt->channel = SDpnt->channel;
+ SCpnt->sc_data_direction = SCSI_DATA_NONE;
scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
(void *) NULL,
@@ -537,6 +540,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
scsi_cmd[4] = 255;
scsi_cmd[5] = 0;
SCpnt->cmd_len = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
(void *) scsi_result,
@@ -637,6 +641,11 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
print_inquiry(scsi_result);
+ sprintf (devname, "host%d/bus%d/target%d/lun%d",
+ SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
+ if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname);
+ else SDpnt->de = devfs_mk_dir (scsi_devfs_handle, devname, 0, NULL);
+
for (sdtpnt = scsi_devicelist; sdtpnt;
sdtpnt = sdtpnt->next)
if (sdtpnt->detect)
@@ -696,6 +705,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
scsi_cmd[4] = 0x2a;
scsi_cmd[5] = 0;
SCpnt->cmd_len = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
(void *) scsi_result, 0x2a,
SCSI_TIMEOUT, 3);
diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
index 3379299d8..f6e8939a6 100644
--- a/drivers/scsi/scsi_syms.c
+++ b/drivers/scsi/scsi_syms.c
@@ -28,16 +28,11 @@
#include "sd.h"
#include <scsi/scsicam.h>
+
/*
* This source file contains the symbol table used by scsi loadable
* modules.
*/
-
-extern void print_command(unsigned char *command);
-extern void print_sense(const char *devclass, Scsi_Cmnd * SCpnt);
-
-extern const char *const scsi_device_types[];
-
EXPORT_SYMBOL(scsi_register_module);
EXPORT_SYMBOL(scsi_unregister_module);
EXPORT_SYMBOL(scsi_free);
@@ -53,6 +48,7 @@ EXPORT_SYMBOL(scsi_command_size);
EXPORT_SYMBOL(scsi_ioctl);
EXPORT_SYMBOL(print_command);
EXPORT_SYMBOL(print_sense);
+EXPORT_SYMBOL(print_req_sense);
EXPORT_SYMBOL(print_msg);
EXPORT_SYMBOL(print_status);
EXPORT_SYMBOL(scsi_dma_free_sectors);
@@ -67,6 +63,15 @@ EXPORT_SYMBOL(scsi_ioctl_send_command);
EXPORT_SYMBOL(scsi_logging_level);
#endif
+EXPORT_SYMBOL(scsi_allocate_request);
+EXPORT_SYMBOL(scsi_release_request);
+EXPORT_SYMBOL(scsi_wait_req);
+EXPORT_SYMBOL(scsi_do_req);
+
+EXPORT_SYMBOL(scsi_report_bus_reset);
+EXPORT_SYMBOL(scsi_block_requests);
+EXPORT_SYMBOL(scsi_unblock_requests);
+
EXPORT_SYMBOL(scsi_get_host_dev);
EXPORT_SYMBOL(scsi_free_host_dev);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index a897c9597..43187600b 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -17,6 +17,8 @@
*
* Modified by Jirka Hanika geo@ff.cuni.cz to support more
* scsi disks using eight major numbers.
+ *
+ * Modified by Richard Gooch rgooch@atnf.csiro.au to support devfs.
*/
#include <linux/config.h>
@@ -307,9 +309,11 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
return 0;
}
SCpnt->cmnd[0] = WRITE_6;
+ SCpnt->sc_data_direction = SCSI_DATA_WRITE;
break;
case READ:
SCpnt->cmnd[0] = READ_6;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
break;
default:
panic("Unknown sd command %d\n", SCpnt->request.cmd);
@@ -489,7 +493,8 @@ static struct gendisk sd_gendisk =
NULL, /* block sizes */
0, /* number */
NULL, /* internal */
- NULL /* next */
+ NULL, /* next */
+ &sd_fops, /* file operations */
};
static struct gendisk *sd_gendisks = &sd_gendisk;
@@ -692,6 +697,7 @@ static int sd_init_onedisk(int i)
SCpnt->cmd_len = 0;
SCpnt->sense_buffer[0] = 0;
SCpnt->sense_buffer[2] = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd (SCpnt, (void *) cmd, (void *) buffer,
0/*512*/, SD_TIMEOUT, MAX_RETRIES);
@@ -703,6 +709,22 @@ static int sd_init_onedisk(int i)
break;
}
+ /*
+ * If the drive has indicated to us that it doesn't have
+ * any media in it, don't bother with any of the rest of
+ * this crap.
+ */
+ if( the_result != 0
+ && ((driver_byte(the_result) & DRIVER_SENSE) != 0)
+ && SCpnt->sense_buffer[2] == UNIT_ATTENTION
+ && SCpnt->sense_buffer[12] == 0x3A ) {
+ rscsi_disks[i].capacity = 0x1fffff;
+ sector_size = 512;
+ rscsi_disks[i].device->changed = 1;
+ rscsi_disks[i].ready = 0;
+ break;
+ }
+
/* Look for non-removable devices that return NOT_READY.
* Issue command to spin up drive for these cases. */
if (the_result && !rscsi_disks[i].device->removable &&
@@ -719,8 +741,9 @@ static int sd_init_onedisk(int i)
SCpnt->sense_buffer[0] = 0;
SCpnt->sense_buffer[2] = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
- 512, SD_TIMEOUT, MAX_RETRIES);
+ 0/*512*/, SD_TIMEOUT, MAX_RETRIES);
}
spintime = 1;
spintime_value = jiffies;
@@ -749,6 +772,7 @@ static int sd_init_onedisk(int i)
SCpnt->sense_buffer[0] = 0;
SCpnt->sense_buffer[2] = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
8, SD_TIMEOUT, MAX_RETRIES);
@@ -900,6 +924,7 @@ static int sd_init_onedisk(int i)
SCpnt->sense_buffer[2] = 0;
/* same code as READCAPA !! */
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
512, SD_TIMEOUT, MAX_RETRIES);
@@ -948,7 +973,7 @@ static int sd_init()
if (!sd_registered) {
for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) {
- if (register_blkdev(SD_MAJOR(i), "sd", &sd_fops)) {
+ if (devfs_register_blkdev(SD_MAJOR(i), "sd", &sd_fops)) {
printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i));
return 1;
}
@@ -988,6 +1013,15 @@ static int sd_init()
sd_gendisks = (struct gendisk *)
kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC);
for (i = 0; i < N_USED_SD_MAJORS; i++) {
+ sd_gendisks[i] = sd_gendisk;
+ sd_gendisks[i].de_arr = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr,
+ GFP_ATOMIC);
+ memset (sd_gendisks[i].de_arr, 0,
+ SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr);
+ sd_gendisks[i].flags = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].flags,
+ GFP_ATOMIC);
+ memset (sd_gendisks[i].flags, 0,
+ SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].flags);
sd_gendisks[i].major = SD_MAJOR(i);
sd_gendisks[i].major_name = "sd";
sd_gendisks[i].minor_shift = 4;
@@ -1061,8 +1095,10 @@ static int sd_detect(Scsi_Device * SDp)
return 1;
}
+
static int sd_attach(Scsi_Device * SDp)
{
+ unsigned int devnum;
Scsi_Disk *dpnt;
int i;
@@ -1084,6 +1120,10 @@ static int sd_attach(Scsi_Device * SDp)
rscsi_disks[i].has_part_table = 0;
sd_template.nr_dev++;
SD_GENDISK(i).nr_real++;
+ devnum = i % SCSI_DISKS_PER_MAJOR;
+ SD_GENDISK(i).de_arr[devnum] = SDp->de;
+ if (SDp->removable)
+ SD_GENDISK(i).flags[devnum] |= GENHD_FL_REMOVABLE;
return 0;
}
@@ -1182,6 +1222,8 @@ static void sd_detach(Scsi_Device * SDp)
sd_gendisks->part[index].nr_sects = 0;
sd_sizes[index] = 0;
}
+ devfs_register_partitions (&SD_GENDISK (i),
+ SD_MINOR_NUMBER (start), 1);
/* unregister_disk() */
dpnt->has_part_table = 0;
dpnt->device = NULL;
@@ -1212,7 +1254,7 @@ void cleanup_module(void)
scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++)
- unregister_blkdev(SD_MAJOR(i), "sd");
+ devfs_unregister_blkdev(SD_MAJOR(i), "sd");
sd_registered--;
if (rscsi_disks != NULL) {
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index e092f40a1..2ccf9ac09 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -9,6 +9,8 @@
* Version 2 and 3 extensions to driver:
* Copyright (C) 1998, 1999 Douglas Gilbert
*
+ * Modified 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -50,6 +52,7 @@
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/poll.h>
+
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -179,6 +182,7 @@ typedef struct sg_device /* holds the state of each scsi generic device */
wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
int sg_tablesize; /* adapter's max scatter-gather table size */
Sg_fd * headfp; /* first open fd belonging to this device */
+ devfs_handle_t de;
kdev_t i_rdev; /* holds device major+minor number */
char exclude; /* opened for exclusive access */
char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
@@ -1075,7 +1079,7 @@ static int sg_init()
if (sg_template.dev_noticed == 0) return 0;
if(!sg_registered) {
- if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
+ if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
{
printk("Unable to get major %d for generic SCSI device\n",
SCSI_GENERIC_MAJOR);
@@ -1150,6 +1154,10 @@ static int sg_attach(Scsi_Device * scsidp)
sdp->sgdebug = 0;
sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k);
+ sdp->de = devfs_register (scsidp->de, "generic", 7, DEVFS_FL_NONE,
+ SCSI_GENERIC_MAJOR, k,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+ &sg_fops, NULL);
sg_template.nr_dev++;
return 0;
}
@@ -1194,6 +1202,8 @@ static void sg_detach(Scsi_Device * scsidp)
SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
sdp->device = NULL;
}
+ devfs_unregister (sdp->de);
+ sdp->de = NULL;
scsidp->attached--;
sg_template.nr_dev--;
/* avoid associated device /dev/sg? being incremented
@@ -1219,7 +1229,7 @@ int init_module(void) {
void cleanup_module( void)
{
scsi_unregister_module(MODULE_SCSI_DEV, &sg_template);
- unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
+ devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
#ifdef CONFIG_PROC_FS
sg_proc_cleanup();
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 365c90660..35f18a53c 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -23,6 +23,8 @@
* Modified by Jens Axboe <axboe@image.dk> - Uniform sr_packet()
* interface, capabilities probe additions, ioctl cleanups, etc.
*
+ * Modified by Richard Gooch <rgooch@atnf.csiro.au> to support devfs
+ *
*/
#include <linux/module.h>
@@ -87,7 +89,6 @@ static int sr_open(struct cdrom_device_info *, int);
void get_sectorsize(int);
void get_capabilities(int);
-void requeue_sr_request(Scsi_Cmnd * SCpnt);
static int sr_media_change(struct cdrom_device_info *, int);
static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *);
@@ -325,9 +326,11 @@ static int sr_init_command(Scsi_Cmnd * SCpnt)
return 0;
}
SCpnt->cmnd[0] = WRITE_10;
+ SCpnt->sc_data_direction = SCSI_DATA_WRITE;
break;
case READ:
SCpnt->cmnd[0] = READ_10;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
break;
default:
panic("Unknown sr command %d\n", SCpnt->request.cmd);
@@ -462,36 +465,37 @@ void get_sectorsize(int i)
unsigned char *buffer;
int the_result, retries;
int sector_size;
- Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
buffer = (unsigned char *) scsi_malloc(512);
- SCpnt = scsi_allocate_device(scsi_CDs[i].device, 1, FALSE);
+ SRpnt = scsi_allocate_request(scsi_CDs[i].device);
retries = 3;
do {
cmd[0] = READ_CAPACITY;
cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
memset((void *) &cmd[2], 0, 8);
- SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */
- SCpnt->cmd_len = 0;
+ SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */
+ SRpnt->sr_cmd_len = 0;
memset(buffer, 0, 8);
/* Do the command and wait.. */
- scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
+ SRpnt->sr_data_direction = SCSI_DATA_READ;
+ scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
512, SR_TIMEOUT, MAX_RETRIES);
- the_result = SCpnt->result;
+ the_result = SRpnt->sr_result;
retries--;
} while (the_result && retries);
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
if (the_result) {
scsi_CDs[i].capacity = 0x1fffff;
@@ -568,7 +572,7 @@ void get_capabilities(int i)
cmd[2] = 0x2a;
cmd[4] = 128;
cmd[3] = cmd[5] = 0;
- rc = sr_do_ioctl(i, cmd, buffer, 128, 1);
+ rc = sr_do_ioctl(i, cmd, buffer, 128, 1, SCSI_DATA_READ);
if (-EINVAL == rc) {
/* failed, drive has'nt this mode page */
@@ -633,19 +637,19 @@ void get_capabilities(int i)
*/
static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc)
{
- Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device;
unsigned char *buffer = cgc->buffer;
int buflen;
/* get the device */
- SCpnt = scsi_allocate_device(device, 1, FALSE);
- if (SCpnt == NULL)
+ SRpnt = scsi_allocate_request(device);
+ if (SRpnt == NULL)
return -ENODEV; /* this just doesn't seem right /axboe */
/* use buffer for ISA DMA */
buflen = (cgc->buflen + 511) & ~511;
- if (cgc->buffer && SCpnt->host->unchecked_isa_dma &&
+ if (cgc->buffer && SRpnt->sr_host->unchecked_isa_dma &&
(virt_to_phys(cgc->buffer) + cgc->buflen - 1 > ISA_DMA_THRESHOLD)) {
buffer = scsi_malloc(buflen);
if (buffer == NULL) {
@@ -658,20 +662,25 @@ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command
cgc->cmd[1] |= device->lun << 5;
/* do the locking and issue the command */
- SCpnt->request.rq_dev = cdi->dev;
+ SRpnt->sr_request.rq_dev = cdi->dev;
/* scsi_wait_cmd sets the command length */
- SCpnt->cmd_len = 0;
+ SRpnt->sr_cmd_len = 0;
+
+ /*
+ * FIXME(eric) - need to set the data direction here.
+ */
+ SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN;
- scsi_wait_cmd(SCpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
+ scsi_wait_req(SRpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
SR_TIMEOUT, MAX_RETRIES);
- if ((cgc->stat = SCpnt->result))
- cgc->sense = (struct request_sense *) SCpnt->sense_buffer;
+ if ((cgc->stat = SRpnt->sr_result))
+ cgc->sense = (struct request_sense *) SRpnt->sr_sense_buffer;
/* release */
- SCpnt->request.rq_dev = MKDEV(0, 0);
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ SRpnt->sr_request.rq_dev = MKDEV(0, 0);
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
/* write DMA buffer back if used */
if (buffer && (buffer != cgc->buffer)) {
@@ -693,7 +702,7 @@ static int sr_init()
return 0;
if (!sr_registered) {
- if (register_blkdev(MAJOR_NR, "sr", &cdrom_fops)) {
+ if (devfs_register_blkdev(MAJOR_NR, "sr", &cdrom_fops)) {
printk("Unable to get major %d for SCSI-CD\n", MAJOR_NR);
return 1;
}
@@ -767,6 +776,11 @@ void sr_finish()
sprintf(name, "sr%d", i);
strcpy(scsi_CDs[i].cdi.name, name);
+ scsi_CDs[i].cdi.de =
+ devfs_register (scsi_CDs[i].device->de, "cd", 2,
+ DEVFS_FL_DEFAULT, MAJOR_NR, i,
+ S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
+ &cdrom_fops, NULL);
register_cdrom(&scsi_CDs[i].cdi);
}
@@ -828,7 +842,7 @@ int init_module(void)
void cleanup_module(void)
{
scsi_unregister_module(MODULE_SCSI_DEV, &sr_template);
- unregister_blkdev(MAJOR_NR, "sr");
+ devfs_unregister_blkdev(MAJOR_NR, "sr");
sr_registered--;
if (scsi_CDs != NULL) {
kfree((char *) scsi_CDs);
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
index e4aad11ab..d3239e647 100644
--- a/drivers/scsi/sr.h
+++ b/drivers/scsi/sr.h
@@ -36,7 +36,7 @@ typedef struct {
extern Scsi_CD *scsi_CDs;
-int sr_do_ioctl(int, unsigned char *, void *, unsigned, int);
+int sr_do_ioctl(int, unsigned char *, void *, unsigned, int, int);
int sr_lock_door(struct cdrom_device_info *, int);
int sr_tray_move(struct cdrom_device_info *, int);
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 9d08b209b..32e71e06f 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -34,20 +34,21 @@ extern void get_sectorsize(int);
error code is. Normally the UNIT_ATTENTION code will automatically
clear after one error */
-int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet)
+int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet, int readwrite)
{
- Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
Scsi_Device *SDev;
struct request *req;
int result, err = 0, retries = 0;
char *bounce_buffer;
SDev = scsi_CDs[target].device;
- SCpnt = scsi_allocate_device(scsi_CDs[target].device, 1, FALSE);
+ SRpnt = scsi_allocate_request(scsi_CDs[target].device);
+ SRpnt->sr_data_direction = readwrite;
/* use ISA DMA buffer if necessary */
- SCpnt->request.buffer = buffer;
- if (buffer && SCpnt->host->unchecked_isa_dma &&
+ SRpnt->sr_request.buffer = buffer;
+ if (buffer && SRpnt->sr_host->unchecked_isa_dma &&
(virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) {
bounce_buffer = (char *) scsi_malloc((buflength + 511) & ~511);
if (bounce_buffer == NULL) {
@@ -62,21 +63,21 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
return -ENODEV;
- scsi_wait_cmd(SCpnt, (void *) sr_cmd, (void *) buffer, buflength,
+ scsi_wait_req(SRpnt, (void *) sr_cmd, (void *) buffer, buflength,
IOCTL_TIMEOUT, IOCTL_RETRIES);
- req = &SCpnt->request;
- if (SCpnt->buffer && req->buffer && SCpnt->buffer != req->buffer) {
- memcpy(req->buffer, SCpnt->buffer, SCpnt->bufflen);
- scsi_free(SCpnt->buffer, (SCpnt->bufflen + 511) & ~511);
- SCpnt->buffer = req->buffer;
+ req = &SRpnt->sr_request;
+ if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) {
+ memcpy(req->buffer, SRpnt->sr_buffer, SRpnt->sr_bufflen);
+ scsi_free(SRpnt->sr_buffer, (SRpnt->sr_bufflen + 511) & ~511);
+ SRpnt->sr_buffer = req->buffer;
}
- result = SCpnt->result;
+ result = SRpnt->sr_result;
/* Minimal error checking. Ignore cases we know about, and report the rest. */
if (driver_byte(result) != 0) {
- switch (SCpnt->sense_buffer[2] & 0xf) {
+ switch (SRpnt->sr_sense_buffer[2] & 0xf) {
case UNIT_ATTENTION:
scsi_CDs[target].device->changed = 1;
if (!quiet)
@@ -86,8 +87,8 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
err = -ENOMEDIUM;
break;
case NOT_READY: /* This happens if there is no disc in drive */
- if (SCpnt->sense_buffer[12] == 0x04 &&
- SCpnt->sense_buffer[13] == 0x01) {
+ if (SRpnt->sr_sense_buffer[12] == 0x04 &&
+ SRpnt->sr_sense_buffer[13] == 0x01) {
/* sense: Logical unit is in process of becoming ready */
if (!quiet)
printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
@@ -104,7 +105,7 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
if (!quiet)
printk(KERN_INFO "sr%d: CDROM not ready. Make sure there is a disc in the drive.\n", target);
#ifdef DEBUG
- print_sense("sr", SCpnt);
+ print_req_sense("sr", SRpnt);
#endif
err = -ENOMEDIUM;
break;
@@ -112,8 +113,8 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
if (!quiet)
printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
"REQUEST.\n", target);
- if (SCpnt->sense_buffer[12] == 0x20 &&
- SCpnt->sense_buffer[13] == 0x00) {
+ if (SRpnt->sr_sense_buffer[12] == 0x20 &&
+ SRpnt->sr_sense_buffer[13] == 0x00) {
/* sense: Invalid command operation code */
err = -EDRIVE_CANT_DO_THIS;
} else {
@@ -121,20 +122,20 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
}
#ifdef DEBUG
print_command(sr_cmd);
- print_sense("sr", SCpnt);
+ print_req_sense("sr", SRpnt);
#endif
break;
default:
printk(KERN_ERR "sr%d: CDROM (ioctl) error, command: ", target);
print_command(sr_cmd);
- print_sense("sr", SCpnt);
+ print_req_sense("sr", SRpnt);
err = -EIO;
}
}
- result = SCpnt->result;
+ result = SRpnt->sr_result;
/* Wake up a process waiting for device */
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return err;
}
@@ -148,7 +149,7 @@ static int test_unit_ready(int minor)
sr_cmd[0] = GPCMD_TEST_UNIT_READY;
sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5);
sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
- return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1);
+ return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1, SCSI_DATA_NONE);
}
int sr_tray_move(struct cdrom_device_info *cdi, int pos)
@@ -160,7 +161,7 @@ int sr_tray_move(struct cdrom_device_info *cdi, int pos)
sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
- return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0);
+ return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0, SCSI_DATA_NONE);
}
int sr_lock_door(struct cdrom_device_info *cdi, int lock)
@@ -237,7 +238,7 @@ int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
sr_cmd[8] = 24;
sr_cmd[9] = 0;
- result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0);
+ result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ);
memcpy(mcn->medium_catalog_number, buffer + 9, 13);
mcn->medium_catalog_number[13] = 0;
@@ -266,7 +267,7 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed)
sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */
sr_cmd[3] = speed & 0xff; /* LSB */
- if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0))
+ if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE))
return -EIO;
return 0;
}
@@ -296,7 +297,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
sr_cmd[8] = 12; /* LSB of length */
sr_cmd[9] = 0;
- result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1);
+ result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1, SCSI_DATA_READ);
tochdr->cdth_trk0 = buffer[2];
tochdr->cdth_trk1 = buffer[3];
@@ -317,7 +318,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
sr_cmd[8] = 12; /* LSB of length */
sr_cmd[9] = 0;
- result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0);
+ result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0, SCSI_DATA_READ);
tocentry->cdte_ctrl = buffer[5] & 0xf;
tocentry->cdte_adr = buffer[5] >> 4;
@@ -390,7 +391,7 @@ int sr_read_cd(int minor, unsigned char *dest, int lba, int format, int blksize)
cmd[9] = 0x10;
break;
}
- return sr_do_ioctl(minor, cmd, dest, blksize, 0);
+ return sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ);
}
/*
@@ -428,7 +429,7 @@ int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
cmd[4] = (unsigned char) (lba >> 8) & 0xff;
cmd[5] = (unsigned char) lba & 0xff;
cmd[8] = 1;
- rc = sr_do_ioctl(minor, cmd, dest, blksize, 0);
+ rc = sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ);
return rc;
}
diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c
index 77be00ea3..a57c25c39 100644
--- a/drivers/scsi/sr_vendor.c
+++ b/drivers/scsi/sr_vendor.c
@@ -132,7 +132,7 @@ int sr_set_blocklength(int minor, int blocklength)
modesel->density = density;
modesel->block_length_med = (blocklength >> 8) & 0xff;
modesel->block_length_lo = blocklength & 0xff;
- if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0))) {
+ if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE))) {
scsi_CDs[minor].device->sector_size = blocklength;
}
#ifdef DEBUG
@@ -176,7 +176,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
cmd[1] = (scsi_CDs[minor].device->lun << 5);
cmd[8] = 12;
cmd[9] = 0x40;
- rc = sr_do_ioctl(minor, cmd, buffer, 12, 1);
+ rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ);
if (rc != 0)
break;
if ((buffer[0] << 8) + buffer[1] < 0x0a) {
@@ -200,7 +200,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
cmd[0] = 0xde;
cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
cmd[2] = 0xb0;
- rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1);
+ rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ);
if (rc != 0)
break;
if (buffer[14] != 0 && buffer[14] != 0xb0) {
@@ -224,7 +224,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = 0xc7;
cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
- rc = sr_do_ioctl(minor, cmd, buffer, 4, 1);
+ rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ);
if (rc == -EINVAL) {
printk(KERN_INFO "sr%d: Hmm, seems the drive "
"doesn't support multisession CD's\n", minor);
@@ -249,7 +249,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
cmd[1] = (scsi_CDs[minor].device->lun << 5);
cmd[8] = 0x04;
cmd[9] = 0x40;
- rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1);
+ rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ);
if (rc != 0) {
break;
}
@@ -263,7 +263,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
cmd[6] = rc & 0x7f; /* number of last session */
cmd[8] = 0x0c;
cmd[9] = 0x40;
- rc = sr_do_ioctl(minor, cmd, buffer, 12, 1);
+ rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ);
if (rc != 0) {
break;
}
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 5817b1424..f897cba9a 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -11,8 +11,10 @@
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Tue Jan 4 21:43:17 2000 by makisara@kai.makisara.local
+ Last modified: Sat Feb 19 17:22:34 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
+
+ Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
#include <linux/module.h>
@@ -66,15 +68,15 @@ static int buffer_kbs = 0;
static int write_threshold_kbs = 0;
static int max_buffers = (-1);
static int max_sg_segs = 0;
-#ifdef MODULE
+
MODULE_AUTHOR("Kai Makisara");
MODULE_DESCRIPTION("SCSI Tape Driver");
MODULE_PARM(buffer_kbs, "i");
MODULE_PARM(write_threshold_kbs, "i");
MODULE_PARM(max_buffers, "i");
MODULE_PARM(max_sg_segs, "i");
-#else
+#ifndef MODULE
static struct st_dev_parm {
char *name;
int *val;
@@ -92,7 +94,6 @@ static struct st_dev_parm {
"max_sg_segs", &max_sg_segs
}
};
-
#endif
@@ -168,16 +169,15 @@ static int st_int_ioctl(struct inode *inode, unsigned int cmd_in,
-
/* Convert the result to success code */
-static int st_chk_result(Scsi_Cmnd * SCpnt)
+static int st_chk_result(Scsi_Request * SRpnt)
{
- int dev = TAPE_NR(SCpnt->request.rq_dev);
- int result = SCpnt->result;
- unsigned char *sense = SCpnt->sense_buffer, scode;
+ int dev = TAPE_NR(SRpnt->sr_request.rq_dev);
+ int result = SRpnt->sr_result;
+ unsigned char *sense = SRpnt->sr_sense_buffer, scode;
DEB(const char *stp;)
- if (!result /* && SCpnt->sense_buffer[0] == 0 */ )
+ if (!result)
return 0;
if (driver_byte(result) & DRIVER_SENSE)
@@ -191,11 +191,11 @@ static int st_chk_result(Scsi_Cmnd * SCpnt)
if (debugging) {
printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
dev, result,
- SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2],
- SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5],
- SCpnt->request_bufflen);
+ SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
+ SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
+ SRpnt->sr_bufflen);
if (driver_byte(result) & DRIVER_SENSE)
- print_sense("st", SCpnt);
+ print_req_sense("st", SRpnt);
} else ) /* end DEB */
if (!(driver_byte(result) & DRIVER_SENSE) ||
((sense[0] & 0x70) == 0x70 &&
@@ -204,11 +204,11 @@ static int st_chk_result(Scsi_Cmnd * SCpnt)
/* scode != UNIT_ATTENTION && */
scode != BLANK_CHECK &&
scode != VOLUME_OVERFLOW &&
- SCpnt->data_cmnd[0] != MODE_SENSE &&
- SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
+ SRpnt->sr_cmnd[0] != MODE_SENSE &&
+ SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
if (driver_byte(result) & DRIVER_SENSE) {
printk(KERN_WARNING "st%d: Error with sense data: ", dev);
- print_sense("st", SCpnt);
+ print_req_sense("st", SRpnt);
} else
printk(KERN_WARNING
"st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
@@ -219,8 +219,8 @@ static int st_chk_result(Scsi_Cmnd * SCpnt)
if ((sense[0] & 0x70) == 0x70 &&
scode == RECOVERED_ERROR
#if ST_RECOVERED_WRITE_FATAL
- && SCpnt->data_cmnd[0] != WRITE_6
- && SCpnt->data_cmnd[0] != WRITE_FILEMARKS
+ && SRpnt->sr_cmnd[0] != WRITE_6
+ && SRpnt->sr_cmnd[0] != WRITE_FILEMARKS
#endif
) {
scsi_tapes[dev].recover_count++;
@@ -228,9 +228,9 @@ static int st_chk_result(Scsi_Cmnd * SCpnt)
DEB(
if (debugging) {
- if (SCpnt->data_cmnd[0] == READ_6)
+ if (SRpnt->sr_cmnd[0] == READ_6)
stp = "read";
- else if (SCpnt->data_cmnd[0] == WRITE_6)
+ else if (SRpnt->sr_cmnd[0] == WRITE_6)
stp = "write";
else
stp = "ioctl";
@@ -267,13 +267,13 @@ static void st_sleep_done(Scsi_Cmnd * SCpnt)
remainder = 0;
if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
remainder > 0)
- (STp->buffer)->last_result = SCpnt->result; /* Error */
+ (STp->buffer)->midlevel_result = SCpnt->result; /* Error */
else
- (STp->buffer)->last_result = INT_MAX; /* OK */
+ (STp->buffer)->midlevel_result = INT_MAX; /* OK */
} else
- (STp->buffer)->last_result = SCpnt->result;
+ (STp->buffer)->midlevel_result = SCpnt->result;
SCpnt->request.rq_status = RQ_SCSI_DONE;
- (STp->buffer)->last_SCpnt = SCpnt;
+ (STp->buffer)->last_SRpnt = SCpnt->sc_request;
DEB( STp->write_pending = 0; )
up(SCpnt->request.sem);
@@ -288,47 +288,49 @@ static void st_sleep_done(Scsi_Cmnd * SCpnt)
/* Do the scsi command. Waits until command performed if do_wait is true.
Otherwise write_behind_check() is used to check that the command
has finished. */
-static Scsi_Cmnd *
- st_do_scsi(Scsi_Cmnd * SCpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes,
- int timeout, int retries, int do_wait)
+static Scsi_Request *
+ st_do_scsi(Scsi_Request * SRpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes,
+ int direction, int timeout, int retries, int do_wait)
{
unsigned char *bp;
- if (SCpnt == NULL)
- SCpnt = scsi_allocate_device(STp->device, 1, TRUE);
- if (SCpnt == NULL) {
+ if (SRpnt == NULL)
+ SRpnt = scsi_allocate_request(STp->device);
+ if (SRpnt == NULL) {
DEBC( printk(KERN_ERR "st%d: Can't get SCSI request.\n",
TAPE_NR(STp->devt)); );
if (signal_pending(current))
- (STp->buffer)->last_result_fatal = (-EINTR);
+ (STp->buffer)->syscall_result = (-EINTR);
else
- (STp->buffer)->last_result_fatal = (-EBUSY);
+ (STp->buffer)->syscall_result = (-EBUSY);
return NULL;
}
- cmd[1] |= (SCpnt->lun << 5) & 0xe0;
+ cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
init_MUTEX_LOCKED(&STp->sem);
- SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ?
+ SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
(STp->buffer)->use_sg : 0;
- if (SCpnt->use_sg) {
+ if (SRpnt->sr_use_sg) {
bp = (char *) &((STp->buffer)->sg[0]);
- if ((STp->buffer)->sg_segs < SCpnt->use_sg)
- SCpnt->use_sg = (STp->buffer)->sg_segs;
+ if ((STp->buffer)->sg_segs < SRpnt->sr_use_sg)
+ SRpnt->sr_use_sg = (STp->buffer)->sg_segs;
} else
bp = (STp->buffer)->b_data;
- SCpnt->cmd_len = 0;
- SCpnt->request.sem = &(STp->sem);
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- SCpnt->request.rq_dev = STp->devt;
+ SRpnt->sr_data_direction = direction;
+ SRpnt->sr_cmd_len = 0;
+ SRpnt->sr_request.sem = &(STp->sem);
+ SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;
+ SRpnt->sr_request.rq_dev = STp->devt;
- scsi_do_cmd(SCpnt, (void *) cmd, bp, bytes,
+ scsi_do_req(SRpnt, (void *) cmd, bp, bytes,
st_sleep_done, timeout, retries);
if (do_wait) {
- down(SCpnt->request.sem);
- (STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
+ down(SRpnt->sr_request.sem);
+ SRpnt->sr_request.sem = NULL;
+ (STp->buffer)->syscall_result = st_chk_result(SRpnt);
}
- return SCpnt;
+ return SRpnt;
}
@@ -348,9 +350,10 @@ static void write_behind_check(Scsi_Tape * STp)
) /* end DEB */
down(&(STp->sem));
+ (STp->buffer)->last_SRpnt->sr_request.sem = NULL;
- (STp->buffer)->last_result_fatal = st_chk_result((STp->buffer)->last_SCpnt);
- scsi_release_command((STp->buffer)->last_SCpnt);
+ (STp->buffer)->syscall_result = st_chk_result((STp->buffer)->last_SRpnt);
+ scsi_release_request((STp->buffer)->last_SRpnt);
if (STbuffer->writing < STbuffer->buffer_bytes)
#if 0
@@ -379,8 +382,8 @@ static void write_behind_check(Scsi_Tape * STp)
it messes up the block number). */
static int cross_eof(Scsi_Tape * STp, int forward)
{
- Scsi_Cmnd *SCpnt;
- unsigned char cmd[10];
+ Scsi_Request *SRpnt;
+ unsigned char cmd[MAX_COMMAND_SIZE];
cmd[0] = SPACE;
cmd[1] = 0x01; /* Space FileMarks */
@@ -394,18 +397,19 @@ static int cross_eof(Scsi_Tape * STp, int forward)
DEBC(printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n",
TAPE_NR(STp->devt), forward ? "forward" : "backward"));
- SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
+ STp->timeout, MAX_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
- if ((STp->buffer)->last_result != 0)
+ if ((STp->buffer)->midlevel_result != 0)
printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n",
TAPE_NR(STp->devt), forward ? "forward" : "backward");
- return (STp->buffer)->last_result_fatal;
+ return (STp->buffer)->syscall_result;
}
@@ -414,17 +418,17 @@ static int flush_write_buffer(Scsi_Tape * STp)
{
int offset, transfer, blks;
int result;
- unsigned char cmd[10];
- Scsi_Cmnd *SCpnt;
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
ST_partstat *STps;
if ((STp->buffer)->writing) {
write_behind_check(STp);
- if ((STp->buffer)->last_result_fatal) {
+ if ((STp->buffer)->syscall_result) {
DEBC(printk(ST_DEB_MSG
"st%d: Async write error (flush) %x.\n",
- TAPE_NR(STp->devt), (STp->buffer)->last_result))
- if ((STp->buffer)->last_result == INT_MAX)
+ TAPE_NR(STp->devt), (STp->buffer)->midlevel_result))
+ if ((STp->buffer)->midlevel_result == INT_MAX)
return (-ENOSPC);
return (-EIO);
}
@@ -443,7 +447,7 @@ static int flush_write_buffer(Scsi_Tape * STp)
memset((STp->buffer)->b_data + offset, 0, transfer - offset);
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = WRITE_6;
cmd[1] = 1;
blks = transfer / STp->block_size;
@@ -451,16 +455,16 @@ static int flush_write_buffer(Scsi_Tape * STp)
cmd[3] = blks >> 8;
cmd[4] = blks;
- SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout,
- MAX_WRITE_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, cmd, transfer, SCSI_DATA_WRITE,
+ STp->timeout, MAX_WRITE_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
STps = &(STp->ps[STp->partition]);
- if ((STp->buffer)->last_result_fatal != 0) {
- if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
- (SCpnt->sense_buffer[2] & 0x40) &&
- (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) {
+ if ((STp->buffer)->syscall_result != 0) {
+ if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+ (SRpnt->sr_sense_buffer[2] & 0x40) &&
+ (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
STp->dirty = 0;
(STp->buffer)->buffer_bytes = 0;
result = (-ENOSPC);
@@ -476,8 +480,8 @@ static int flush_write_buffer(Scsi_Tape * STp)
STp->dirty = 0;
(STp->buffer)->buffer_bytes = 0;
}
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
return result;
}
@@ -582,8 +586,9 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
{
unsigned short flags;
int i, need_dma_buffer, new_session = FALSE;
- unsigned char cmd[10];
- Scsi_Cmnd *SCpnt;
+ int retval;
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
@@ -601,8 +606,14 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); )
return (-EBUSY);
}
+ STp->in_use = 1;
STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
+ if (scsi_tapes[dev].device->host->hostt->module)
+ __MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+ if (st_template.module)
+ __MOD_INC_USE_COUNT(st_template.module);
+
if (mode != STp->current_mode) {
DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n",
dev, STp->current_mode, mode));
@@ -621,13 +632,14 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
if (STp->buffer == NULL) {
printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev);
- return (-EBUSY);
+ retval = (-EBUSY);
+ goto err_out;
}
} else
STp->buffer = st_buffers[i];
(STp->buffer)->in_use = 1;
(STp->buffer)->writing = 0;
- (STp->buffer)->last_result_fatal = 0;
+ (STp->buffer)->syscall_result = 0;
(STp->buffer)->use_sg = STp->device->host->sg_tablesize;
/* Compute the usable buffer size for this SCSI adapter */
@@ -651,35 +663,27 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
STp->recover_count = 0;
DEB( STp->nbr_waits = STp->nbr_finished = 0; )
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_INC_USE_COUNT(st_template.module);
-
- memset((void *) &cmd[0], 0, 10);
+ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = TEST_UNIT_READY;
- SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
- TRUE);
- if (!SCpnt) {
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_DEC_USE_COUNT(st_template.module);
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout,
+ MAX_READY_RETRIES, TRUE);
+ if (!SRpnt) {
+ retval = (STp->buffer)->syscall_result;
+ goto err_out;
}
- if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
- (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
+ if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+ (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
/* Flush the queued UNIT ATTENTION sense data */
for (i=0; i < 10; i++) {
- memset((void *) &cmd[0], 0, 10);
+ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = TEST_UNIT_READY;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout,
- MAX_READY_RETRIES, TRUE);
- if ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
- (SCpnt->sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
+ STp->long_timeout, MAX_READY_RETRIES, TRUE);
+ if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
+ (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
break;
}
@@ -700,36 +704,35 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
new_session = TRUE;
}
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
if ((STp->device)->scsi_level >= SCSI_2 &&
- (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
- (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY &&
- SCpnt->sense_buffer[12] == 0x3a) { /* Check ASC */
+ (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+ (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
+ SRpnt->sr_sense_buffer[12] == 0x3a) { /* Check ASC */
STp->ready = ST_NO_TAPE;
} else
STp->ready = ST_NOT_READY;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
STp->density = 0; /* Clear the erroneous "residue" */
STp->write_prot = 0;
STp->block_size = 0;
STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
STp->partition = STp->new_partition = 0;
STp->door_locked = ST_UNLOCKED;
- STp->in_use = 1;
return 0;
}
if (STp->omit_blklims)
STp->min_block = STp->max_block = (-1);
else {
- memset((void *) &cmd[0], 0, 10);
+ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = READ_BLOCK_LIMITS;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES,
- TRUE);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->timeout,
+ MAX_READY_RETRIES, TRUE);
- if (!SCpnt->result && !SCpnt->sense_buffer[0]) {
+ if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) {
STp->max_block = ((STp->buffer)->b_data[1] << 16) |
((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
STp->min_block = ((STp->buffer)->b_data[4] << 8) |
@@ -745,16 +748,17 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
}
}
- memset((void *) &cmd[0], 0, 10);
+ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SENSE;
cmd[4] = 12;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES, TRUE);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->timeout,
+ MAX_READY_RETRIES, TRUE);
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev));
STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */
- (STp->buffer)->last_result_fatal = 0; /* Prevent error propagation */
+ (STp->buffer)->syscall_result = 0; /* Prevent error propagation */
STp->drv_write_prot = 0;
} else {
DEBC(printk(ST_DEB_MSG
@@ -779,19 +783,14 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
!enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n",
dev, STp->block_size);
- scsi_release_command(SCpnt);
- (STp->buffer)->in_use = 0;
- STp->buffer = NULL;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_DEC_USE_COUNT(st_template.module);
- return (-EIO);
+ scsi_release_request(SRpnt);
+ retval = (-EIO);
+ goto err_out;
}
STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
}
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
STp->inited = TRUE;
if (STp->block_size > 0)
@@ -812,13 +811,8 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
DEBC(printk(ST_DEB_MSG "st%d: Write protected\n", dev));
if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
- (STp->buffer)->in_use = 0;
- STp->buffer = NULL;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_DEC_USE_COUNT(st_template.module);
- return (-EROFS);
+ retval = (-EROFS);
+ goto err_out;
}
}
@@ -829,13 +823,8 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
DEBC(printk(ST_DEB_MSG
"st%d: Updating partition number in status.\n", dev));
if ((STp->partition = find_partition(inode)) < 0) {
- (STp->buffer)->in_use = 0;
- STp->buffer = NULL;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_DEC_USE_COUNT(st_template.module);
- return STp->partition;
+ retval = STp->partition;
+ goto err_out;
}
STp->new_partition = STp->partition;
STp->nbr_partitions = 1; /* This guess will be updated when necessary */
@@ -845,15 +834,8 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
STp->density_changed = STp->blksize_changed = FALSE;
STp->compression_changed = FALSE;
if (!(STm->defaults_for_writes) &&
- (i = set_mode_densblk(inode, STp, STm)) < 0) {
- (STp->buffer)->in_use = 0;
- STp->buffer = NULL;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_DEC_USE_COUNT(st_template.module);
- return i;
- }
+ (retval = set_mode_densblk(inode, STp, STm)) < 0)
+ goto err_out;
if (STp->default_drvbuffer != 0xff) {
if (st_int_ioctl(inode, MTSETDRVBUFFER, STp->default_drvbuffer))
@@ -862,9 +844,21 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
dev, STp->default_drvbuffer);
}
}
- STp->in_use = 1;
return 0;
+
+ err_out:
+ if (STp->buffer != NULL) {
+ (STp->buffer)->in_use = 0;
+ STp->buffer = NULL;
+ }
+ STp->in_use = 0;
+ if (scsi_tapes[dev].device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+ if (st_template.module)
+ __MOD_DEC_USE_COUNT(st_template.module);
+ return retval;
+
}
@@ -872,8 +866,8 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
static int scsi_tape_flush(struct file *filp)
{
int result = 0, result2;
- static unsigned char cmd[10];
- Scsi_Cmnd *SCpnt;
+ static unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
@@ -890,59 +884,62 @@ static int scsi_tape_flush(struct file *filp)
STm = &(STp->modes[STp->current_mode]);
STps = &(STp->ps[STp->partition]);
+ if (STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+ result = flush_write_buffer(STp);
+ if (result != 0 && result != (-ENOSPC))
+ goto out;
+ }
+
if (STp->can_partitions &&
- (result = update_partition(inode)) < 0) {
+ (result2 = update_partition(inode)) < 0) {
DEBC(printk(ST_DEB_MSG
"st%d: update_partition at close failed.\n", dev));
+ if (result == 0)
+ result = result2;
goto out;
}
if (STps->rw == ST_WRITING && !(STp->device)->was_reset) {
- result = flush_write_buffer(STp);
-
DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
dev, (long) (filp->f_pos));
printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n",
dev, STp->nbr_waits, STp->nbr_finished);
)
- if (result == 0 || result == (-ENOSPC)) {
-
- memset(cmd, 0, 10);
- cmd[0] = WRITE_FILEMARKS;
- cmd[4] = 1 + STp->two_fm;
+ memset(cmd, 0, MAX_COMMAND_SIZE);
+ cmd[0] = WRITE_FILEMARKS;
+ cmd[4] = 1 + STp->two_fm;
- SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout,
- MAX_WRITE_RETRIES, TRUE);
- if (!SCpnt) {
- result = (STp->buffer)->last_result_fatal;
- goto out;
- }
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
+ STp->timeout, MAX_WRITE_RETRIES, TRUE);
+ if (!SRpnt) {
+ result = (STp->buffer)->syscall_result;
+ goto out;
+ }
- if ((STp->buffer)->last_result_fatal != 0 &&
- ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
- (SCpnt->sense_buffer[2] & 0x4f) != 0x40 ||
- ((SCpnt->sense_buffer[0] & 0x80) != 0 &&
- (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] |
- SCpnt->sense_buffer[5] |
- SCpnt->sense_buffer[6]) == 0))) {
- /* Filter out successful write at EOM */
- scsi_release_command(SCpnt);
- SCpnt = NULL;
- printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
- if (result == 0)
- result = (-EIO);
- } else {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- if (STp->two_fm)
- cross_eof(STp, FALSE);
- STps->eof = ST_FM;
- }
+ if ((STp->buffer)->syscall_result != 0 &&
+ ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
+ (SRpnt->sr_sense_buffer[2] & 0x4f) != 0x40 ||
+ ((SRpnt->sr_sense_buffer[0] & 0x80) != 0 &&
+ (SRpnt->sr_sense_buffer[3] | SRpnt->sr_sense_buffer[4] |
+ SRpnt->sr_sense_buffer[5] |
+ SRpnt->sr_sense_buffer[6]) == 0))) {
+ /* Filter out successful write at EOM */
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
+ printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
+ if (result == 0)
+ result = (-EIO);
+ } else {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
+ if (STps->drv_file >= 0)
+ STps->drv_file++;
+ STps->drv_block = 0;
+ if (STp->two_fm)
+ cross_eof(STp, FALSE);
+ STps->eof = ST_FM;
}
DEBC(printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n",
@@ -1021,9 +1018,9 @@ static ssize_t
ssize_t i, do_count, blks, retval, transfer;
int write_threshold;
int doing_write = 0;
- static unsigned char cmd[10];
+ static unsigned char cmd[MAX_COMMAND_SIZE];
const char *b_point;
- Scsi_Cmnd *SCpnt = NULL;
+ Scsi_Request *SRpnt = NULL;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
@@ -1118,10 +1115,10 @@ static ssize_t
if ((STp->buffer)->writing) {
write_behind_check(STp);
- if ((STp->buffer)->last_result_fatal) {
+ if ((STp->buffer)->syscall_result) {
DEBC(printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n",
- dev, (STp->buffer)->last_result));
- if ((STp->buffer)->last_result == INT_MAX)
+ dev, (STp->buffer)->midlevel_result));
+ if ((STp->buffer)->midlevel_result == INT_MAX)
STps->eof = ST_EOM_OK;
else
STps->eof = ST_EOM_ERROR;
@@ -1153,7 +1150,7 @@ static ssize_t
total = count;
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = WRITE_6;
cmd[1] = (STp->block_size != 0);
@@ -1175,9 +1172,9 @@ static ssize_t
i = append_to_buffer(b_point, STp->buffer, do_count);
if (i) {
- if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
return i;
}
@@ -1193,23 +1190,23 @@ static ssize_t
cmd[3] = blks >> 8;
cmd[4] = blks;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout,
- MAX_WRITE_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
+ STp->timeout, MAX_WRITE_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev));
- if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
- (SCpnt->sense_buffer[2] & 0x40)) {
+ if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+ (SRpnt->sr_sense_buffer[2] & 0x40)) {
if (STp->block_size != 0 &&
- (SCpnt->sense_buffer[0] & 0x80) != 0)
- transfer = (SCpnt->sense_buffer[3] << 24) |
- (SCpnt->sense_buffer[4] << 16) |
- (SCpnt->sense_buffer[5] << 8) |
- SCpnt->sense_buffer[6];
+ (SRpnt->sr_sense_buffer[0] & 0x80) != 0)
+ transfer = (SRpnt->sr_sense_buffer[3] << 24) |
+ (SRpnt->sr_sense_buffer[4] << 16) |
+ (SRpnt->sr_sense_buffer[5] << 8) |
+ SRpnt->sr_sense_buffer[6];
else if (STp->block_size == 0 &&
- (SCpnt->sense_buffer[2] & 0x0f) ==
+ (SRpnt->sr_sense_buffer[2] & 0x0f) ==
VOLUME_OVERFLOW)
transfer = do_count;
else
@@ -1246,8 +1243,8 @@ static ssize_t
retval = (-EIO);
}
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
(STp->buffer)->buffer_bytes = 0;
STp->dirty = 0;
if (count < total)
@@ -1271,9 +1268,9 @@ static ssize_t
STp->dirty = 1;
i = append_to_buffer(b_point, STp->buffer, count);
if (i) {
- if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
return i;
}
@@ -1281,10 +1278,10 @@ static ssize_t
count = 0;
}
- if (doing_write && (STp->buffer)->last_result_fatal != 0) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
- return (STp->buffer)->last_result_fatal;
+ if (doing_write && (STp->buffer)->syscall_result != 0) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
+ return (STp->buffer)->syscall_result;
}
if (STm->do_async_writes &&
@@ -1309,14 +1306,15 @@ static ssize_t
cmd[4] = blks;
DEB( STp->write_pending = 1; )
- SCpnt = st_do_scsi(SCpnt, STp, cmd, (STp->buffer)->writing, STp->timeout,
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, (STp->buffer)->writing,
+ SCSI_DATA_WRITE, STp->timeout,
MAX_WRITE_RETRIES, FALSE);
- if (SCpnt == NULL)
- return (STp->buffer)->last_result_fatal;
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
- } else if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ } else if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
STps->at_sm &= (total == 0);
if (total > 0)
@@ -1328,11 +1326,11 @@ static ssize_t
/* Read data from the tape. Returns zero in the normal case, one if the
eof status has changed, and the negative error code in case of a
fatal error. Otherwise updates the buffer and the eof state. */
-static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
+static long read_tape(struct inode *inode, long count, Scsi_Request ** aSRpnt)
{
int transfer, blks, bytes;
- static unsigned char cmd[10];
- Scsi_Cmnd *SCpnt;
+ static unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
@@ -1348,7 +1346,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
if (STps->eof == ST_FM_HIT)
return 1;
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = READ_6;
cmd[1] = (STp->block_size != 0);
if (STp->block_size == 0)
@@ -1369,49 +1367,51 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
cmd[3] = blks >> 8;
cmd[4] = blks;
- SCpnt = *aSCpnt;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, STp->timeout, MAX_RETRIES, TRUE);
- *aSCpnt = SCpnt;
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = *aSRpnt;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, SCSI_DATA_READ,
+ STp->timeout, MAX_RETRIES, TRUE);
+ *aSRpnt = SRpnt;
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
(STp->buffer)->read_pointer = 0;
STps->at_sm = 0;
/* Something to check */
- if ((STp->buffer)->last_result_fatal) {
+ if ((STp->buffer)->syscall_result) {
retval = 1;
DEBC(printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
dev,
- SCpnt->sense_buffer[0], SCpnt->sense_buffer[1],
- SCpnt->sense_buffer[2], SCpnt->sense_buffer[3],
- SCpnt->sense_buffer[4], SCpnt->sense_buffer[5],
- SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]));
- if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */
+ SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1],
+ SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
+ SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5],
+ SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7]));
+ if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) { /* extended sense */
- if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
- SCpnt->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */
+ if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
+ SRpnt->sr_sense_buffer[2] &= 0xcf; /* No need for EOM in this case */
- if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
+ if ((SRpnt->sr_sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
/* Compute the residual count */
- if ((SCpnt->sense_buffer[0] & 0x80) != 0)
- transfer = (SCpnt->sense_buffer[3] << 24) |
- (SCpnt->sense_buffer[4] << 16) |
- (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
+ if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0)
+ transfer = (SRpnt->sr_sense_buffer[3] << 24) |
+ (SRpnt->sr_sense_buffer[4] << 16) |
+ (SRpnt->sr_sense_buffer[5] << 8) |
+ SRpnt->sr_sense_buffer[6];
else
transfer = 0;
if (STp->block_size == 0 &&
- (SCpnt->sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
+ (SRpnt->sr_sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
transfer = bytes;
- if (SCpnt->sense_buffer[2] & 0x20) { /* ILI */
+ if (SRpnt->sr_sense_buffer[2] & 0x20) { /* ILI */
if (STp->block_size == 0) {
if (transfer <= 0)
transfer = 0;
(STp->buffer)->buffer_bytes = bytes - transfer;
} else {
- scsi_release_command(SCpnt);
- SCpnt = *aSCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = *aSRpnt = NULL;
if (transfer == blks) { /* We did not get anything, error */
printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
if (STps->drv_block >= 0)
@@ -1430,7 +1430,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
if (st_int_ioctl(inode, MTBSR, 1))
return (-EIO);
}
- } else if (SCpnt->sense_buffer[2] & 0x80) { /* FM overrides EOM */
+ } else if (SRpnt->sr_sense_buffer[2] & 0x80) { /* FM overrides EOM */
if (STps->eof != ST_FM_HIT)
STps->eof = ST_FM_HIT;
else
@@ -1443,7 +1443,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
DEBC(printk(ST_DEB_MSG
"st%d: EOF detected (%d bytes read).\n",
dev, (STp->buffer)->buffer_bytes));
- } else if (SCpnt->sense_buffer[2] & 0x40) {
+ } else if (SRpnt->sr_sense_buffer[2] & 0x40) {
if (STps->eof == ST_FM)
STps->eof = ST_EOD_1;
else
@@ -1464,7 +1464,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
"st%d: Tape error while reading.\n", dev));
STps->drv_block = (-1);
if (STps->eof == ST_FM &&
- (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) {
+ (SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) {
DEBC(printk(ST_DEB_MSG
"st%d: Zero returned for first BLANK CHECK after EOF.\n",
dev));
@@ -1475,7 +1475,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
}
/* End of extended sense test */
else { /* Non-extended sense */
- retval = (STp->buffer)->last_result_fatal;
+ retval = (STp->buffer)->syscall_result;
}
}
@@ -1501,7 +1501,7 @@ static ssize_t
ssize_t total;
ssize_t i, transfer;
int special;
- Scsi_Cmnd *SCpnt = NULL;
+ Scsi_Request *SRpnt = NULL;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
@@ -1594,10 +1594,10 @@ static ssize_t
/* Get new data if the buffer is empty */
if ((STp->buffer)->buffer_bytes == 0) {
- special = read_tape(inode, count - total, &SCpnt);
+ special = read_tape(inode, count - total, &SRpnt);
if (special < 0) { /* No need to continue read */
- if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
+ if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
}
return special;
}
@@ -1616,9 +1616,9 @@ static ssize_t
(STp->buffer)->buffer_bytes : count - total;
i = from_buffer(STp->buffer, buf, transfer);
if (i) {
- if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
return i;
}
@@ -1633,9 +1633,9 @@ static ssize_t
} /* for (total = 0, special = 0;
total < count && !special; ) */
- if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
/* Change the eof state if no data from tape or buffer */
@@ -1836,30 +1836,31 @@ static int st_set_options(struct inode *inode, long options)
static int st_compression(Scsi_Tape * STp, int state)
{
int dev;
- unsigned char cmd[10];
- Scsi_Cmnd *SCpnt = NULL;
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt = NULL;
if (STp->ready != ST_READY)
return (-EIO);
/* Read the current page contents */
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SENSE;
cmd[1] = 8;
cmd[2] = COMPRESSION_PAGE;
cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
- if (SCpnt == NULL)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ,
+ STp->timeout, 0, TRUE);
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
- dev = TAPE_NR(SCpnt->request.rq_dev);
+ dev = TAPE_NR(SRpnt->sr_request.rq_dev);
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n",
dev));
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return (-EIO);
}
DEBC(printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev,
@@ -1868,8 +1869,8 @@ static int st_compression(Scsi_Tape * STp, int state)
/* Check if compression can be changed */
if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) {
DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev));
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return (-EIO);
}
@@ -1879,7 +1880,7 @@ static int st_compression(Scsi_Tape * STp, int state)
else
(STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] &= ~DCE_MASK;
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SELECT;
cmd[1] = 0x10;
cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
@@ -1887,19 +1888,20 @@ static int st_compression(Scsi_Tape * STp, int state)
(STp->buffer)->b_data[0] = 0; /* Reserved data length */
(STp->buffer)->b_data[1] = 0; /* Reserved media type byte */
(STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
+ STp->timeout, 0, TRUE);
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev));
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return (-EIO);
}
DEBC(printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n",
dev, state));
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
STp->compression_changed = TRUE;
return 0;
}
@@ -1913,11 +1915,12 @@ static int st_int_ioctl(struct inode *inode,
long ltmp;
int i, ioctl_result;
int chg_eof = TRUE;
- unsigned char cmd[10];
- Scsi_Cmnd *SCpnt;
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
Scsi_Tape *STp;
ST_partstat *STps;
- int fileno, blkno, at_sm, undone, datalen;
+ int fileno, blkno, at_sm, undone;
+ int datalen = 0, direction = SCSI_DATA_NONE;
int dev = TAPE_NR(inode->i_rdev);
STp = &(scsi_tapes[dev]);
@@ -1933,8 +1936,7 @@ static int st_int_ioctl(struct inode *inode,
blkno = STps->drv_block;
at_sm = STps->at_sm;
- memset(cmd, 0, 10);
- datalen = 0;
+ memset(cmd, 0, MAX_COMMAND_SIZE);
switch (cmd_in) {
case MTFSFM:
chg_eof = FALSE; /* Changed from the FSF after this */
@@ -2176,6 +2178,7 @@ static int st_int_ioctl(struct inode *inode,
}
cmd[0] = MODE_SELECT;
cmd[4] = datalen = 12;
+ direction = SCSI_DATA_WRITE;
memset((STp->buffer)->b_data, 0, 12);
if (cmd_in == MTSETDRVBUFFER)
@@ -2222,15 +2225,16 @@ static int st_int_ioctl(struct inode *inode,
return (-ENOSYS);
}
- SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction,
+ timeout, MAX_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
- ioctl_result = (STp->buffer)->last_result_fatal;
+ ioctl_result = (STp->buffer)->syscall_result;
if (!ioctl_result) { /* SCSI command successful */
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
STps->drv_block = blkno;
STps->drv_file = fileno;
STps->at_sm = at_sm;
@@ -2279,7 +2283,7 @@ static int st_int_ioctl(struct inode *inode,
} else { /* SCSI command was not completely successful. Don't return
from this block without releasing the SCSI command block! */
- if (SCpnt->sense_buffer[2] & 0x40) {
+ if (SRpnt->sr_sense_buffer[2] & 0x40) {
if (cmd_in != MTBSF && cmd_in != MTBSFM &&
cmd_in != MTBSR && cmd_in != MTBSS)
STps->eof = ST_EOM_OK;
@@ -2287,14 +2291,14 @@ static int st_int_ioctl(struct inode *inode,
}
undone = (
- (SCpnt->sense_buffer[3] << 24) +
- (SCpnt->sense_buffer[4] << 16) +
- (SCpnt->sense_buffer[5] << 8) +
- SCpnt->sense_buffer[6]);
+ (SRpnt->sr_sense_buffer[3] << 24) +
+ (SRpnt->sr_sense_buffer[4] << 16) +
+ (SRpnt->sr_sense_buffer[5] << 8) +
+ SRpnt->sr_sense_buffer[6]);
if (cmd_in == MTWEOF &&
- (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
- (SCpnt->sense_buffer[2] & 0x4f) == 0x40 &&
- ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) {
+ (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+ (SRpnt->sr_sense_buffer[2] & 0x4f) == 0x40 &&
+ ((SRpnt->sr_sense_buffer[0] & 0x80) == 0 || undone == 0)) {
ioctl_result = 0; /* EOF written succesfully at EOM */
if (fileno >= 0)
fileno++;
@@ -2315,7 +2319,7 @@ static int st_int_ioctl(struct inode *inode,
STps->drv_block = 0;
STps->eof = ST_NOEOF;
} else if (cmd_in == MTFSR) {
- if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */
+ if (SRpnt->sr_sense_buffer[2] & 0x80) { /* Hit filemark */
if (STps->drv_file >= 0)
STps->drv_file++;
STps->drv_block = 0;
@@ -2328,7 +2332,7 @@ static int st_int_ioctl(struct inode *inode,
STps->eof = ST_NOEOF;
}
} else if (cmd_in == MTBSR) {
- if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */
+ if (SRpnt->sr_sense_buffer[2] & 0x80) { /* Hit filemark */
STps->drv_file--;
STps->drv_block = (-1);
} else {
@@ -2345,14 +2349,14 @@ static int st_int_ioctl(struct inode *inode,
} else if (chg_eof)
STps->eof = ST_NOEOF;
- if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
+ if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
STps->eof = ST_EOD;
if (cmd_in == MTLOCK)
STp->door_locked = ST_LOCK_FAILS;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
return ioctl_result;
@@ -2368,14 +2372,14 @@ static int get_location(struct inode *inode, unsigned int *block, int *partition
Scsi_Tape *STp;
int dev = TAPE_NR(inode->i_rdev);
int result;
- unsigned char scmd[10];
- Scsi_Cmnd *SCpnt;
+ unsigned char scmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
- memset(scmd, 0, 10);
+ memset(scmd, 0, MAX_COMMAND_SIZE);
if ((STp->device)->scsi_level < SCSI_2) {
scmd[0] = QFA_REQUEST_BLOCK;
scmd[4] = 3;
@@ -2384,11 +2388,12 @@ static int get_location(struct inode *inode, unsigned int *block, int *partition
if (!logical && !STp->scsi2_logical)
scmd[1] = 1;
}
- SCpnt = st_do_scsi(NULL, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, scmd, 20, SCSI_DATA_READ, STp->timeout,
+ MAX_READY_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
- if ((STp->buffer)->last_result_fatal != 0 ||
+ if ((STp->buffer)->syscall_result != 0 ||
(STp->device->scsi_level >= SCSI_2 &&
((STp->buffer)->b_data[0] & 4) != 0)) {
*block = *partition = 0;
@@ -2414,8 +2419,8 @@ static int get_location(struct inode *inode, unsigned int *block, int *partition
DEBC(printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev,
*block, *partition));
}
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return result;
}
@@ -2432,8 +2437,8 @@ static int set_location(struct inode *inode, unsigned int block, int partition,
int result, p;
unsigned int blk;
int timeout;
- unsigned char scmd[10];
- Scsi_Cmnd *SCpnt;
+ unsigned char scmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
@@ -2462,7 +2467,7 @@ static int set_location(struct inode *inode, unsigned int block, int partition,
}
}
- memset(scmd, 0, 10);
+ memset(scmd, 0, MAX_COMMAND_SIZE);
if ((STp->device)->scsi_level < SCSI_2) {
scmd[0] = QFA_SEEK_BLOCK;
scmd[2] = (block >> 16);
@@ -2490,13 +2495,14 @@ static int set_location(struct inode *inode, unsigned int block, int partition,
timeout = STp->timeout;
#endif
- SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, scmd, 0, SCSI_DATA_NONE,
+ timeout, MAX_READY_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
STps->drv_block = STps->drv_file = (-1);
STps->eof = ST_NOEOF;
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
result = (-EIO);
if (STp->can_partitions &&
(STp->device)->scsi_level >= SCSI_2 &&
@@ -2518,8 +2524,8 @@ static int set_location(struct inode *inode, unsigned int block, int partition,
result = 0;
}
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return result;
}
@@ -2568,27 +2574,28 @@ static int nbr_partitions(struct inode *inode)
{
int dev = TAPE_NR(inode->i_rdev), result;
Scsi_Tape *STp;
- Scsi_Cmnd *SCpnt = NULL;
- unsigned char cmd[10];
+ Scsi_Request *SRpnt = NULL;
+ unsigned char cmd[MAX_COMMAND_SIZE];
STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
- memset((void *) &cmd[0], 0, 10);
+ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SENSE;
cmd[1] = 8; /* Page format */
cmd[2] = PART_PAGE;
cmd[4] = 200;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES, TRUE);
- if (SCpnt == NULL)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 200, SCSI_DATA_READ, STp->timeout,
+ MAX_READY_RETRIES, TRUE);
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n",
dev));
result = (-EIO);
@@ -2608,8 +2615,8 @@ static int partition_tape(struct inode *inode, int size)
int dev = TAPE_NR(inode->i_rdev), result;
int length;
Scsi_Tape *STp;
- Scsi_Cmnd *SCpnt = NULL;
- unsigned char cmd[10], *bp;
+ Scsi_Request *SRpnt = NULL;
+ unsigned char cmd[MAX_COMMAND_SIZE], *bp;
if ((result = nbr_partitions(inode)) < 0)
return result;
@@ -2640,20 +2647,20 @@ static int partition_tape(struct inode *inode, int size)
bp[MODE_HEADER_LENGTH] &= 0x3f;
bp[MODE_HEADER_LENGTH + 1] = length - 2;
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SELECT;
cmd[1] = 0x10;
cmd[4] = length + MODE_HEADER_LENGTH;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout,
- MAX_READY_RETRIES, TRUE);
- if (SCpnt == NULL)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
+ STp->long_timeout, MAX_READY_RETRIES, TRUE);
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
result = (-EIO);
} else
@@ -3230,7 +3237,7 @@ static int st_attach(Scsi_Device * SDp)
Scsi_Tape *tpnt;
ST_mode *STm;
ST_partstat *STps;
- int i;
+ int i, mode;
if (SDp->type != TYPE_TAPE)
return 1;
@@ -3247,6 +3254,26 @@ static int st_attach(Scsi_Device * SDp)
if (i >= st_template.dev_max)
panic("scsi_devices corrupt (st)");
+ for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+ char name[8];
+ static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
+
+ /* Rewind entry */
+ sprintf (name, "mt%s", formats[mode]);
+ tpnt->de_r[mode] =
+ devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
+ MAJOR_NR, i + (mode << 5),
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ 0, 0, &st_fops, NULL);
+ /* No-rewind entry */
+ sprintf (name, "mt%sn", formats[mode]);
+ tpnt->de_n[mode] =
+ devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
+ MAJOR_NR, i + (mode << 5) + 128,
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ 0, 0, &st_fops, NULL);
+ }
+ devfs_register_tape (tpnt->de_r[0]);
scsi_tapes[i].device = SDp;
if (SDp->scsi_level <= 2)
scsi_tapes[i].mt_status->mt_type = MT_ISSCSI1;
@@ -3336,7 +3363,7 @@ static int st_init()
st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
if (!st_registered) {
- if (register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
+ if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
MAJOR_NR);
return 1;
@@ -3355,7 +3382,7 @@ static int st_init()
GFP_ATOMIC);
if (scsi_tapes == NULL) {
printk(KERN_ERR "Unable to allocate descriptors for SCSI tapes.\n");
- unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+ devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
return 1;
}
@@ -3372,7 +3399,7 @@ static int st_init()
for (j=0; j < i; j++)
kfree(scsi_tapes[j].mt_status);
kfree(scsi_tapes);
- unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+ devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
return 1;
}
/* Initialize status */
@@ -3385,7 +3412,7 @@ static int st_init()
GFP_ATOMIC);
if (st_buffers == NULL) {
printk(KERN_ERR "Unable to allocate tape buffer pointers.\n");
- unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+ devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
for (i=0; i < st_template.dev_max; i++)
kfree(scsi_tapes[i].mt_status);
kfree(scsi_tapes);
@@ -3416,11 +3443,17 @@ static int st_init()
static void st_detach(Scsi_Device * SDp)
{
Scsi_Tape *tpnt;
- int i;
+ int i, mode;
for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++)
if (tpnt->device == SDp) {
tpnt->device = NULL;
+ for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+ devfs_unregister (tpnt->de_r[mode]);
+ tpnt->de_r[mode] = NULL;
+ devfs_unregister (tpnt->de_n[mode]);
+ tpnt->de_n[mode] = NULL;
+ }
SDp->attached--;
st_template.nr_dev--;
st_template.dev_noticed--;
@@ -3445,7 +3478,7 @@ void cleanup_module(void)
int i;
scsi_unregister_module(MODULE_SCSI_DEV, &st_template);
- unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+ devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
st_registered--;
if (scsi_tapes != NULL) {
for (i=0; i < st_template.dev_max; ++i)
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 479dca079..e751efc28 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -8,6 +8,7 @@
#ifndef _SCSI_H
#include "scsi.h"
#endif
+#include <linux/devfs_fs_kernel.h>
/* The tape buffer descriptor. */
typedef struct {
@@ -18,9 +19,9 @@ typedef struct {
int buffer_bytes;
int read_pointer;
int writing;
- int last_result;
- int last_result_fatal;
- Scsi_Cmnd *last_SCpnt;
+ int midlevel_result;
+ int syscall_result;
+ Scsi_Request *last_SRpnt;
unsigned char *b_data;
unsigned short use_sg; /* zero or number of segments for this adapter */
unsigned short sg_segs; /* total number of allocated segments */
@@ -85,6 +86,8 @@ typedef struct {
/* Mode characteristics */
ST_mode modes[ST_NBR_MODES];
int current_mode;
+ devfs_handle_t de_r[ST_NBR_MODES]; /* Rewind entries */
+ devfs_handle_t de_n[ST_NBR_MODES]; /* No-rewind entries */
/* Status variables */
int partition;
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
new file mode 100644
index 000000000..510386823
--- /dev/null
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -0,0 +1,3012 @@
+/* sun3_NCR5380.c -- adapted from atari_NCR5380.c for the sun3 by
+ Sam Creasey. */
+/*
+ * NCR 5380 generic driver routines. These should make it *trivial*
+ * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * architecture.
+ *
+ * Note that these routines also work with NR53c400 family chips.
+ *
+ * Copyright 1993, Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 666-5836
+ *
+ * DISTRIBUTION RELEASE 6.
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * ++roman: To port the 5380 driver to the Atari, I had to do some changes in
+ * this file, too:
+ *
+ * - Some of the debug statements were incorrect (undefined variables and the
+ * like). I fixed that.
+ *
+ * - In information_transfer(), I think a #ifdef was wrong. Looking at the
+ * possible DMA transfer size should also happen for REAL_DMA. I added this
+ * in the #if statement.
+ *
+ * - When using real DMA, information_transfer() should return in a DATAOUT
+ * phase after starting the DMA. It has nothing more to do.
+ *
+ * - The interrupt service routine should run main after end of DMA, too (not
+ * only after RESELECTION interrupts). Additionally, it should _not_ test
+ * for more interrupts after running main, since a DMA process may have
+ * been started and interrupts are turned on now. The new int could happen
+ * inside the execution of NCR5380_intr(), leading to recursive
+ * calls.
+ *
+ * - I've added a function merge_contiguous_buffers() that tries to
+ * merge scatter-gather buffers that are located at contiguous
+ * physical addresses and can be processed with the same DMA setup.
+ * Since most scatter-gather operations work on a page (4K) of
+ * 4 buffers (1K), in more than 90% of all cases three interrupts and
+ * DMA setup actions are saved.
+ *
+ * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
+ * and USLEEP, because these were messing up readability and will never be
+ * needed for Atari SCSI.
+ *
+ * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
+ * stuff), and 'main' is executed in a bottom half if awoken by an
+ * interrupt.
+ *
+ * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
+ * constructs. In my eyes, this made the source rather unreadable, so I
+ * finally replaced that by the *_PRINTK() macros.
+ *
+ */
+
+/*
+ * Further development / testing that should be done :
+ * 1. Test linked command handling code after Eric is ready with
+ * the high level code.
+ */
+
+#if (NDEBUG & NDEBUG_LISTS)
+#define LIST(x,y) \
+ { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
+ if ((x)==(y)) udelay(5); }
+#define REMOVE(w,x,y,z) \
+ { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \
+ (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
+ if ((x)==(y)) udelay(5); }
+#else
+#define LIST(x,y)
+#define REMOVE(w,x,y,z)
+#endif
+
+#ifndef notyet
+#undef LINKED
+#endif
+
+/*
+ * Design
+ * Issues :
+ *
+ * The other Linux SCSI drivers were written when Linux was Intel PC-only,
+ * and specifically for each board rather than each chip. This makes their
+ * adaptation to platforms like the Mac (Some of which use NCR5380's)
+ * more difficult than it has to be.
+ *
+ * Also, many of the SCSI drivers were written before the command queuing
+ * routines were implemented, meaning their implementations of queued
+ * commands were hacked on rather than designed in from the start.
+ *
+ * When I designed the Linux SCSI drivers I figured that
+ * while having two different SCSI boards in a system might be useful
+ * for debugging things, two of the same type wouldn't be used.
+ * Well, I was wrong and a number of users have mailed me about running
+ * multiple high-performance SCSI boards in a server.
+ *
+ * Finally, when I get questions from users, I have no idea what
+ * revision of my driver they are running.
+ *
+ * This driver attempts to address these problems :
+ * This is a generic 5380 driver. To use it on a different platform,
+ * one simply writes appropriate system specific macros (ie, data
+ * transfer - some PC's will use the I/O bus, 68K's must use
+ * memory mapped) and drops this file in their 'C' wrapper.
+ *
+ * As far as command queueing, two queues are maintained for
+ * each 5380 in the system - commands that haven't been issued yet,
+ * and commands that are currently executing. This means that an
+ * unlimited number of commands may be queued, letting
+ * more commands propagate from the higher driver levels giving higher
+ * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
+ * allowing multiple commands to propagate all the way to a SCSI-II device
+ * while a command is already executing.
+ *
+ * To solve the multiple-boards-in-the-same-system problem,
+ * there is a separate instance structure for each instance
+ * of a 5380 in the system. So, multiple NCR5380 drivers will
+ * be able to coexist with appropriate changes to the high level
+ * SCSI code.
+ *
+ * A NCR5380_PUBLIC_REVISION macro is provided, with the release
+ * number (updated for each public release) printed by the
+ * NCR5380_print_options command, which should be called from the
+ * wrapper detect function, so that I know what release of the driver
+ * users are using.
+ *
+ * Issues specific to the NCR5380 :
+ *
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
+ * piece of hardware that requires you to sit in a loop polling for
+ * the REQ signal as long as you are connected. Some devices are
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
+ * while doing long seek operations.
+ *
+ * The workaround for this is to keep track of devices that have
+ * disconnected. If the device hasn't disconnected, for commands that
+ * should disconnect, we do something like
+ *
+ * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
+ *
+ * Some tweaking of N and M needs to be done. An algorithm based
+ * on "time to data" would give the best results as long as short time
+ * to datas (ie, on the same track) were considered, however these
+ * broken devices are the exception rather than the rule and I'd rather
+ * spend my time optimizing for the normal case.
+ *
+ * Architecture :
+ *
+ * At the heart of the design is a coroutine, NCR5380_main,
+ * which is started when not running by the interrupt handler,
+ * timer, and queue command function. It attempts to establish
+ * I_T_L or I_T_L_Q nexuses by removing the commands from the
+ * issue queue and calling NCR5380_select() if a nexus
+ * is not established.
+ *
+ * Once a nexus is established, the NCR5380_information_transfer()
+ * phase goes through the various phases as instructed by the target.
+ * if the target goes into MSG IN and sends a DISCONNECT message,
+ * the command structure is placed into the per instance disconnected
+ * queue, and NCR5380_main tries to find more work. If USLEEP
+ * was defined, and the target is idle for too long, the system
+ * will try to sleep.
+ *
+ * If a command has disconnected, eventually an interrupt will trigger,
+ * calling NCR5380_intr() which will in turn call NCR5380_reselect
+ * to reestablish a nexus. This will run main if necessary.
+ *
+ * On command termination, the done function will be called as
+ * appropriate.
+ *
+ * SCSI pointers are maintained in the SCp field of SCSI command
+ * structures, being initialized after the command is connected
+ * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
+ * Note that in violation of the standard, an implicit SAVE POINTERS operation
+ * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
+ */
+
+/*
+ * Using this file :
+ * This file a skeleton Linux SCSI driver for the NCR 5380 series
+ * of chips. To use it, you write an architecture specific functions
+ * and macros and include this file in your driver.
+ *
+ * These macros control options :
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ * for commands that return with a CHECK CONDITION status.
+ *
+ * LINKED - if defined, linked commands are supported.
+ *
+ * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
+ *
+ * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
+ *
+ * These macros MUST be defined :
+ *
+ * NCR5380_read(register) - read from the specified register
+ *
+ * NCR5380_write(register, value) - write to the specific register
+ *
+ * Either real DMA *or* pseudo DMA may be implemented
+ * REAL functions :
+ * NCR5380_REAL_DMA should be defined if real DMA is to be used.
+ * Note that the DMA setup functions should return the number of bytes
+ * that they were able to program the controller for.
+ *
+ * Also note that generic i386/PC versions of these macros are
+ * available as NCR5380_i386_dma_write_setup,
+ * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ *
+ * NCR5380_dma_write_setup(instance, src, count) - initialize
+ * NCR5380_dma_read_setup(instance, dst, count) - initialize
+ * NCR5380_dma_residual(instance); - residual count
+ *
+ * PSEUDO functions :
+ * NCR5380_pwrite(instance, src, count)
+ * NCR5380_pread(instance, dst, count);
+ *
+ * If nothing specific to this implementation needs doing (ie, with external
+ * hardware), you must also define
+ *
+ * NCR5380_queue_command
+ * NCR5380_reset
+ * NCR5380_abort
+ * NCR5380_proc_info
+ *
+ * to be the global entry points into the specific driver, ie
+ * #define NCR5380_queue_command t128_queue_command.
+ *
+ * If this is not done, the routines will be defined as static functions
+ * with the NCR5380* names and the user must provide a globally
+ * accessible wrapper function.
+ *
+ * The generic driver is initialized by calling NCR5380_init(instance),
+ * after setting the appropriate host specific fields and ID. If the
+ * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
+ * possible) function may be used. Before the specific driver initialization
+ * code finishes, NCR5380_print_options should be called.
+ */
+
+static struct Scsi_Host *first_instance = NULL;
+static Scsi_Host_Template *the_template = NULL;
+
+/* Macros ease life... :-) */
+#define SETUP_HOSTDATA(in) \
+ struct NCR5380_hostdata *hostdata = \
+ (struct NCR5380_hostdata *)(in)->hostdata
+#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
+
+#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble))
+#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble))
+
+#define HOSTNO instance->host_no
+#define H_NO(cmd) (cmd)->host->host_no
+
+#ifdef SUPPORT_TAGS
+
+/*
+ * Functions for handling tagged queuing
+ * =====================================
+ *
+ * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes:
+ *
+ * Using consecutive numbers for the tags is no good idea in my eyes. There
+ * could be wrong re-usings if the counter (8 bit!) wraps and some early
+ * command has been preempted for a long time. My solution: a bitfield for
+ * remembering used tags.
+ *
+ * There's also the problem that each target has a certain queue size, but we
+ * cannot know it in advance :-( We just see a QUEUE_FULL status being
+ * returned. So, in this case, the driver internal queue size assumption is
+ * reduced to the number of active tags if QUEUE_FULL is returned by the
+ * target. The command is returned to the mid-level, but with status changed
+ * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
+ * correctly.
+ *
+ * We're also not allowed running tagged commands as long as an untagged
+ * command is active. And REQUEST SENSE commands after a contingent allegiance
+ * condition _must_ be untagged. To keep track whether an untagged command has
+ * been issued, the host->busy array is still employed, as it is without
+ * support for tagged queuing.
+ *
+ * One could suspect that there are possible race conditions between
+ * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the
+ * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(),
+ * which already guaranteed to be running at most once. It is also the only
+ * place where tags/LUNs are allocated. So no other allocation can slip
+ * between that pair, there could only happen a reselection, which can free a
+ * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes
+ * important: the tag bit must be cleared before 'nr_allocated' is decreased.
+ */
+
+/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */
+#undef TAG_NONE
+#define TAG_NONE 0xff
+
+/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */
+#if (MAX_TAGS % 32) != 0
+#error "MAX_TAGS must be a multiple of 32!"
+#endif
+
+typedef struct {
+ char allocated[MAX_TAGS/8];
+ int nr_allocated;
+ int queue_size;
+} TAG_ALLOC;
+
+static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+
+
+static void __init init_tags( void )
+{
+ int target, lun;
+ TAG_ALLOC *ta;
+
+ if (!setup_use_tagged_queuing)
+ return;
+
+ for( target = 0; target < 8; ++target ) {
+ for( lun = 0; lun < 8; ++lun ) {
+ ta = &TagAlloc[target][lun];
+ memset( &ta->allocated, 0, MAX_TAGS/8 );
+ ta->nr_allocated = 0;
+ /* At the beginning, assume the maximum queue size we could
+ * support (MAX_TAGS). This value will be decreased if the target
+ * returns QUEUE_FULL status.
+ */
+ ta->queue_size = MAX_TAGS;
+ }
+ }
+}
+
+
+/* Check if we can issue a command to this LUN: First see if the LUN is marked
+ * busy by an untagged command. If the command should use tagged queuing, also
+ * check that there is a free tag and the target's queue won't overflow. This
+ * function should be called with interrupts disabled to avoid race
+ * conditions.
+ */
+
+static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+ SETUP_HOSTDATA(cmd->host);
+
+ if (hostdata->busy[cmd->target] & (1 << cmd->lun))
+ return( 1 );
+ if (!should_be_tagged ||
+ !setup_use_tagged_queuing || !cmd->device->tagged_supported)
+ return( 0 );
+ if (TagAlloc[cmd->target][cmd->lun].nr_allocated >=
+ TagAlloc[cmd->target][cmd->lun].queue_size ) {
+ TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
+ H_NO(cmd), cmd->target, cmd->lun );
+ return( 1 );
+ }
+ return( 0 );
+}
+
+
+/* Allocate a tag for a command (there are no checks anymore, check_lun_busy()
+ * must be called before!), or reserve the LUN in 'busy' if the command is
+ * untagged.
+ */
+
+static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+ SETUP_HOSTDATA(cmd->host);
+
+ /* If we or the target don't support tagged queuing, allocate the LUN for
+ * an untagged command.
+ */
+ if (!should_be_tagged ||
+ !setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+ cmd->tag = TAG_NONE;
+ hostdata->busy[cmd->target] |= (1 << cmd->lun);
+ TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
+ "command\n", H_NO(cmd), cmd->target, cmd->lun );
+ }
+ else {
+ TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+
+ cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );
+ set_bit( cmd->tag, &ta->allocated );
+ ta->nr_allocated++;
+ TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
+ "(now %d tags in use)\n",
+ H_NO(cmd), cmd->tag, cmd->target, cmd->lun,
+ ta->nr_allocated );
+ }
+}
+
+
+/* Mark the tag of command 'cmd' as free, or in case of an untagged command,
+ * unlock the LUN.
+ */
+
+static void cmd_free_tag( Scsi_Cmnd *cmd )
+{
+ SETUP_HOSTDATA(cmd->host);
+
+ if (cmd->tag == TAG_NONE) {
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
+ H_NO(cmd), cmd->target, cmd->lun );
+ }
+ else if (cmd->tag >= MAX_TAGS) {
+ printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
+ H_NO(cmd), cmd->tag );
+ }
+ else {
+ TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+ clear_bit( cmd->tag, &ta->allocated );
+ ta->nr_allocated--;
+ TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
+ H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
+ }
+}
+
+
+static void free_all_tags( void )
+{
+ int target, lun;
+ TAG_ALLOC *ta;
+
+ if (!setup_use_tagged_queuing)
+ return;
+
+ for( target = 0; target < 8; ++target ) {
+ for( lun = 0; lun < 8; ++lun ) {
+ ta = &TagAlloc[target][lun];
+ memset( &ta->allocated, 0, MAX_TAGS/8 );
+ ta->nr_allocated = 0;
+ }
+ }
+}
+
+#endif /* SUPPORT_TAGS */
+
+
+/*
+ * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+ *
+ * Purpose: Try to merge several scatter-gather requests into one DMA
+ * transfer. This is possible if the scatter buffers lie on
+ * physical contiguous addresses.
+ *
+ * Parameters: Scsi_Cmnd *cmd
+ * The command to work on. The first scatter buffer's data are
+ * assumed to be already transfered into ptr/this_residual.
+ */
+
+static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+{
+ unsigned long endaddr;
+#if (NDEBUG & NDEBUG_MERGING)
+ unsigned long oldlen = cmd->SCp.this_residual;
+ int cnt = 1;
+#endif
+
+ for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
+ cmd->SCp.buffers_residual &&
+ virt_to_phys(cmd->SCp.buffer[1].address) == endaddr; ) {
+
+ MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
+ cmd->SCp.buffer[1].address, endaddr);
+#if (NDEBUG & NDEBUG_MERGING)
+ ++cnt;
+#endif
+ ++cmd->SCp.buffer;
+ --cmd->SCp.buffers_residual;
+ cmd->SCp.this_residual += cmd->SCp.buffer->length;
+ endaddr += cmd->SCp.buffer->length;
+ }
+#if (NDEBUG & NDEBUG_MERGING)
+ if (oldlen != cmd->SCp.this_residual)
+ MER_PRINTK("merged %d buffers from %p, new length %08x\n",
+ cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
+#endif
+}
+
+/*
+ * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+ *
+ * Purpose : initialize the saved data pointers for cmd to point to the
+ * start of the buffer.
+ *
+ * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ */
+
+static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
+{
+ /*
+ * Initialize the Scsi Pointer field so that all of the commands in the
+ * various queues are valid.
+ */
+
+ if (cmd->use_sg) {
+ cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffers_residual = cmd->use_sg - 1;
+ cmd->SCp.ptr = (char *) cmd->SCp.buffer->address;
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ /* ++roman: Try to merge some scatter-buffers if they are at
+ * contiguous physical addresses.
+ */
+ merge_contiguous_buffers( cmd );
+ } else {
+ cmd->SCp.buffer = NULL;
+ cmd->SCp.buffers_residual = 0;
+ cmd->SCp.ptr = (char *) cmd->request_buffer;
+ cmd->SCp.this_residual = cmd->request_bufflen;
+ }
+
+}
+
+#include <linux/config.h>
+#include <linux/delay.h>
+
+#if 1
+static struct {
+ unsigned char mask;
+ const char * name;}
+signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
+ { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
+ { SR_SEL, "SEL" }, {0, NULL}},
+basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
+icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+ {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
+ {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
+ {0, NULL}},
+mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
+ {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
+ "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+ {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+ {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
+ {0, NULL}};
+
+/*
+ * Function : void NCR5380_print(struct Scsi_Host *instance)
+ *
+ * Purpose : print the SCSI bus signals for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print(struct Scsi_Host *instance) {
+ unsigned char status, data, basr, mr, icr, i;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+ status = NCR5380_read(STATUS_REG);
+ mr = NCR5380_read(MODE_REG);
+ icr = NCR5380_read(INITIATOR_COMMAND_REG);
+ basr = NCR5380_read(BUS_AND_STATUS_REG);
+ restore_flags(flags);
+ printk("STATUS_REG: %02x ", status);
+ for (i = 0; signals[i].mask ; ++i)
+ if (status & signals[i].mask)
+ printk(",%s", signals[i].name);
+ printk("\nBASR: %02x ", basr);
+ for (i = 0; basrs[i].mask ; ++i)
+ if (basr & basrs[i].mask)
+ printk(",%s", basrs[i].name);
+ printk("\nICR: %02x ", icr);
+ for (i = 0; icrs[i].mask; ++i)
+ if (icr & icrs[i].mask)
+ printk(",%s", icrs[i].name);
+ printk("\nMODE: %02x ", mr);
+ for (i = 0; mrs[i].mask; ++i)
+ if (mr & mrs[i].mask)
+ printk(",%s", mrs[i].name);
+ printk("\n");
+}
+
+static struct {
+ unsigned char value;
+ const char *name;
+} phases[] = {
+ {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+ {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+ {PHASE_UNKNOWN, "UNKNOWN"}};
+
+/*
+ * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
+ *
+ * Purpose : print the current SCSI phase for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print_phase(struct Scsi_Host *instance)
+{
+ unsigned char status;
+ int i;
+
+ status = NCR5380_read(STATUS_REG);
+ if (!(status & SR_REQ))
+ printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+ else {
+ for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
+ (phases[i].value != (status & PHASE_MASK)); ++i);
+ printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+ }
+}
+
+#else /* !NDEBUG */
+
+/* dummies... */
+__inline__ void NCR5380_print(struct Scsi_Host *instance) { };
+__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
+
+#endif
+
+/*
+ * ++roman: New scheme of calling NCR5380_main()
+ *
+ * If we're not in an interrupt, we can call our main directly, it cannot be
+ * already running. Else, we queue it on a task queue, if not 'main_running'
+ * tells us that a lower level is already executing it. This way,
+ * 'main_running' needs not be protected in a special way.
+ *
+ * queue_main() is a utility function for putting our main onto the task
+ * queue, if main_running is false. It should be called only from a
+ * interrupt or bottom half.
+ */
+
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+
+static volatile int main_running = 0;
+static struct tq_struct NCR5380_tqueue = {
+ NULL, /* next */
+ 0, /* sync */
+ (void (*)(void*))NCR5380_main, /* routine, must have (void *) arg... */
+ NULL /* data */
+};
+
+static __inline__ void queue_main(void)
+{
+ if (!main_running) {
+ /* If in interrupt and NCR5380_main() not already running,
+ queue it on the 'immediate' task queue, to be processed
+ immediately after the current interrupt processing has
+ finished. */
+ queue_task(&NCR5380_tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ /* else: nothing to do: the running NCR5380_main() will pick up
+ any newly queued command. */
+}
+
+
+static inline void NCR5380_all_init (void)
+{
+ static int done = 0;
+ if (!done) {
+ INI_PRINTK("scsi : NCR5380_all_init()\n");
+ done = 1;
+ }
+}
+
+
+/*
+ * Function : void NCR58380_print_options (struct Scsi_Host *instance)
+ *
+ * Purpose : called by probe code indicating the NCR5380 driver
+ * options that were selected.
+ *
+ * Inputs : instance, pointer to this instance. Unused.
+ */
+
+static void __init NCR5380_print_options (struct Scsi_Host *instance)
+{
+ printk(" generic options"
+#ifdef AUTOSENSE
+ " AUTOSENSE"
+#endif
+#ifdef REAL_DMA
+ " REAL DMA"
+#endif
+#ifdef PARITY
+ " PARITY"
+#endif
+#ifdef SUPPORT_TAGS
+ " SCSI-2 TAGGED QUEUING"
+#endif
+ );
+ printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+}
+
+/*
+ * Function : void NCR5380_print_status (struct Scsi_Host *instance)
+ *
+ * Purpose : print commands in the various queues, called from
+ * NCR5380_abort and NCR5380_debug to aid debugging.
+ *
+ * Inputs : instance, pointer to this instance.
+ */
+
+static void NCR5380_print_status (struct Scsi_Host *instance)
+{
+ char *pr_bfr;
+ char *start;
+ int len;
+
+ NCR_PRINT(NDEBUG_ANY);
+ NCR_PRINT_PHASE(NDEBUG_ANY);
+
+ pr_bfr = (char *) __get_free_page(GFP_ATOMIC);
+ if (!pr_bfr) {
+ printk("NCR5380_print_status: no memory for print buffer\n");
+ return;
+ }
+ len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
+ pr_bfr[len] = 0;
+ printk("\n%s\n", pr_bfr);
+ free_page((unsigned long) pr_bfr);
+}
+
+
+/******************************************/
+/*
+ * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
+ *
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written
+*/
+
+#undef SPRINTF
+#define SPRINTF(fmt,args...) \
+ do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
+ pos += sprintf(pos, fmt , ## args); } while(0)
+static
+char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
+
+#ifndef NCR5380_proc_info
+static
+#endif
+int NCR5380_proc_info (char *buffer, char **start, off_t offset,
+ int length, int hostno, int inout)
+{
+ char *pos = buffer;
+ struct Scsi_Host *instance;
+ struct NCR5380_hostdata *hostdata;
+ Scsi_Cmnd *ptr;
+ unsigned long flags;
+ off_t begin = 0;
+#define check_offset() \
+ do { \
+ if (pos - buffer < offset - begin) { \
+ begin += pos - buffer; \
+ pos = buffer; \
+ } \
+ } while (0)
+
+ for (instance = first_instance; instance && HOSTNO != hostno;
+ instance = instance->next)
+ ;
+ if (!instance)
+ return(-ESRCH);
+ hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+ if (inout) { /* Has data been written to the file ? */
+ return(-ENOSYS); /* Currently this is a no-op */
+ }
+ SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+ check_offset();
+ save_flags(flags);
+ cli();
+ SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
+ check_offset();
+ if (!hostdata->connected)
+ SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+ else
+ pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
+ pos, buffer, length);
+ SPRINTF("scsi%d: issue_queue\n", HOSTNO);
+ check_offset();
+ for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
+ pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+ check_offset();
+ }
+
+ SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
+ check_offset();
+ for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+ ptr = NEXT(ptr)) {
+ pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+ check_offset();
+ }
+
+ restore_flags(flags);
+ *start = buffer + (offset - begin);
+ if (pos - buffer < offset - begin)
+ return 0;
+ else if (pos - buffer - (offset - begin) < length)
+ return pos - buffer - (offset - begin);
+ return length;
+}
+
+static char *
+lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+{
+ int i, s;
+ unsigned char *command;
+ SPRINTF("scsi%d: destination target %d, lun %d\n",
+ H_NO(cmd), cmd->target, cmd->lun);
+ SPRINTF(" command = ");
+ command = cmd->cmnd;
+ SPRINTF("%2d (0x%02x)", command[0], command[0]);
+ for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+ SPRINTF(" %02x", command[i]);
+ SPRINTF("\n");
+ return pos;
+}
+
+
+/*
+ * Function : void NCR5380_init (struct Scsi_Host *instance)
+ *
+ * Purpose : initializes *instance and corresponding 5380 chip.
+ *
+ * Inputs : instance - instantiation of the 5380 driver.
+ *
+ * Notes : I assume that the host, hostno, and id bits have been
+ * set correctly. I don't care about the irq and other fields.
+ *
+ */
+
+static void __init NCR5380_init (struct Scsi_Host *instance, int flags)
+{
+ int i;
+ SETUP_HOSTDATA(instance);
+
+ NCR5380_all_init();
+
+ hostdata->aborted = 0;
+ hostdata->id_mask = 1 << instance->this_id;
+ hostdata->id_higher_mask = 0;
+ for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+ if (i > hostdata->id_mask)
+ hostdata->id_higher_mask |= i;
+ for (i = 0; i < 8; ++i)
+ hostdata->busy[i] = 0;
+#ifdef SUPPORT_TAGS
+ init_tags();
+#endif
+#if defined (REAL_DMA)
+ hostdata->dma_len = 0;
+#endif
+ hostdata->targets_present = 0;
+ hostdata->connected = NULL;
+ hostdata->issue_queue = NULL;
+ hostdata->disconnected_queue = NULL;
+ hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+
+ if (!the_template) {
+ the_template = instance->hostt;
+ first_instance = instance;
+ }
+
+
+#ifndef AUTOSENSE
+ if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
+ printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
+ " without AUTOSENSE option, contingent allegiance conditions may\n"
+ " be incorrectly cleared.\n", HOSTNO);
+#endif /* def AUTOSENSE */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+}
+
+/*
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
+ * void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ * a pointer to the command descriptor.
+ *
+ * Returns : 0
+ *
+ * Side effects :
+ * cmd is added to the per instance issue_queue, with minor
+ * twiddling done to the host specific fields of cmd. If the
+ * main coroutine is not running, it is restarted.
+ *
+ */
+
+/* Only make static if a wrapper function is used */
+#ifndef NCR5380_queue_command
+static
+#endif
+int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+ SETUP_HOSTDATA(cmd->host);
+ Scsi_Cmnd *tmp;
+ unsigned long flags;
+ extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
+
+#if (NDEBUG & NDEBUG_NO_WRITE)
+ switch (cmd->cmnd[0]) {
+ case WRITE_6:
+ case WRITE_10:
+ printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+ H_NO(cmd));
+ cmd->result = (DID_ERROR << 16);
+ done(cmd);
+ return 0;
+ }
+#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
+
+
+#ifdef NCR5380_STATS
+# if 0
+ if (!hostdata->connected && !hostdata->issue_queue &&
+ !hostdata->disconnected_queue) {
+ hostdata->timebase = jiffies;
+ }
+# endif
+# ifdef NCR5380_STAT_LIMIT
+ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+ switch (cmd->cmnd[0])
+ {
+ case WRITE:
+ case WRITE_6:
+ case WRITE_10:
+ hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_write[cmd->target] += cmd->request_bufflen;
+ hostdata->pendingw++;
+ break;
+ case READ:
+ case READ_6:
+ case READ_10:
+ hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_read[cmd->target] += cmd->request_bufflen;
+ hostdata->pendingr++;
+ break;
+ }
+#endif
+
+ /*
+ * We use the host_scribble field as a pointer to the next command
+ * in a queue
+ */
+
+ NEXT(cmd) = NULL;
+ cmd->scsi_done = done;
+
+ cmd->result = 0;
+
+
+ /*
+ * Insert the cmd into the issue queue. Note that REQUEST SENSE
+ * commands are added to the head of the queue since any command will
+ * clear the contingent allegiance condition that exists and the
+ * sense data is only guaranteed to be valid while the condition exists.
+ */
+
+ save_flags(flags);
+ cli();
+ /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
+ * Otherwise a running NCR5380_main may steal the lock.
+ * Lock before actually inserting due to fairness reasons explained in
+ * atari_scsi.c. If we insert first, then it's impossible for this driver
+ * to release the lock.
+ * Stop timer for this command while waiting for the lock, or timeouts
+ * may happen (and they really do), and it's no good if the command doesn't
+ * appear in any of the queues.
+ * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+ * because also a timer int can trigger an abort or reset, which would
+ * alter queues and touch the lock.
+ */
+ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+ LIST(cmd, hostdata->issue_queue);
+ NEXT(cmd) = hostdata->issue_queue;
+ hostdata->issue_queue = cmd;
+ } else {
+ for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+ NEXT(tmp); tmp = NEXT(tmp))
+ ;
+ LIST(cmd, tmp);
+ NEXT(tmp) = cmd;
+ }
+
+ restore_flags(flags);
+
+ QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
+ (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+ /* If queue_command() is called from an interrupt (real one or bottom
+ * half), we let queue_main() do the job of taking care about main. If it
+ * is already running, this is a no-op, else main will be queued.
+ *
+ * If we're not in an interrupt, we can call NCR5380_main()
+ * unconditionally, because it cannot be already running.
+ */
+ if (in_interrupt() || ((flags >> 8) & 7) >= 6)
+ queue_main();
+ else
+ NCR5380_main();
+ return 0;
+}
+
+/*
+ * Function : NCR5380_main (void)
+ *
+ * Purpose : NCR5380_main is a coroutine that runs as long as more work can
+ * be done on the NCR5380 host adapters in a system. Both
+ * NCR5380_queue_command() and NCR5380_intr() will try to start it
+ * in case it is not running.
+ *
+ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
+ * reenable them. This prevents reentrancy and kernel stack overflow.
+ */
+
+static void NCR5380_main (void)
+{
+ Scsi_Cmnd *tmp, *prev;
+ struct Scsi_Host *instance = first_instance;
+ struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+ int done;
+ unsigned long flags;
+
+ /*
+ * We run (with interrupts disabled) until we're sure that none of
+ * the host adapters have anything that can be done, at which point
+ * we set main_running to 0 and exit.
+ *
+ * Interrupts are enabled before doing various other internal
+ * instructions, after we've decided that we need to run through
+ * the loop again.
+ *
+ * this should prevent any race conditions.
+ *
+ * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+ * because also a timer int can trigger an abort or reset, which can
+ * alter queues and touch the Falcon lock.
+ */
+
+ /* Tell int handlers main() is now already executing. Note that
+ no races are possible here. If an int comes in before
+ 'main_running' is set here, and queues/executes main via the
+ task queue, it doesn't do any harm, just this instance of main
+ won't find any work left to do. */
+ if (main_running)
+ return;
+ main_running = 1;
+
+ save_flags(flags);
+ do {
+ cli(); /* Freeze request queues */
+ done = 1;
+
+ if (!hostdata->connected) {
+ MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO );
+ /*
+ * Search through the issue_queue for a command destined
+ * for a target that's not busy.
+ */
+#if (NDEBUG & NDEBUG_LISTS)
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+ tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+ ;
+ if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
+#endif
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+ prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
+
+#if (NDEBUG & NDEBUG_LISTS)
+ if (prev != tmp)
+ printk("MAIN tmp=%p target=%d busy=%d lun=%d\n",
+ tmp, tmp->target, hostdata->busy[tmp->target],
+ tmp->lun);
+#endif
+ /* When we find one, remove it from the issue queue. */
+ /* ++guenther: possible race with Falcon locking */
+ if (
+#ifdef SUPPORT_TAGS
+ !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
+#else
+ !(hostdata->busy[tmp->target] & (1 << tmp->lun))
+#endif
+ ) {
+ cli(); /* ++guenther: just to be sure, this must be atomic */
+ if (prev) {
+ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+ NEXT(prev) = NEXT(tmp);
+ } else {
+ REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+ hostdata->issue_queue = NEXT(tmp);
+ }
+ NEXT(tmp) = NULL;
+
+ /* reenable interrupts after finding one */
+ restore_flags(flags);
+
+ /*
+ * Attempt to establish an I_T_L nexus here.
+ * On success, instance->hostdata->connected is set.
+ * On failure, we must add the command back to the
+ * issue queue so we can keep trying.
+ */
+ MAIN_PRINTK("scsi%d: main(): command for target %d "
+ "lun %d removed from issue_queue\n",
+ HOSTNO, tmp->target, tmp->lun);
+ /*
+ * REQUEST SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent allegiance condition exists for the
+ * entire unit.
+ */
+ /* ++roman: ...and the standard also requires that
+ * REQUEST SENSE command are untagged.
+ */
+
+#ifdef SUPPORT_TAGS
+ cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
+#endif
+ if (!NCR5380_select(instance, tmp,
+ (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
+ TAG_NEXT)) {
+ break;
+ } else {
+ cli();
+ LIST(tmp, hostdata->issue_queue);
+ NEXT(tmp) = hostdata->issue_queue;
+ hostdata->issue_queue = tmp;
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( tmp );
+#endif
+ restore_flags(flags);
+ MAIN_PRINTK("scsi%d: main(): select() failed, "
+ "returned to issue_queue\n", HOSTNO);
+ if (hostdata->connected)
+ break;
+ }
+ } /* if target/lun/target queue is not busy */
+ } /* for issue_queue */
+ } /* if (!hostdata->connected) */
+ if (hostdata->connected
+#ifdef REAL_DMA
+ && !hostdata->dma_len
+#endif
+ ) {
+ restore_flags(flags);
+ MAIN_PRINTK("scsi%d: main: performing information transfer\n",
+ HOSTNO);
+ NCR5380_information_transfer(instance);
+ MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
+ done = 0;
+ }
+ } while (!done);
+
+ /* Better allow ints _after_ 'main_running' has been cleared, else
+ an interrupt could believe we'll pick up the work it left for
+ us, but we won't see it anymore here... */
+ main_running = 0;
+ restore_flags(flags);
+}
+
+
+#ifdef REAL_DMA
+/*
+ * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
+ *
+ * Purpose : Called by interrupt handler when DMA finishes or a phase
+ * mismatch occurs (which would finish the DMA transfer).
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+static void NCR5380_dma_complete( struct Scsi_Host *instance )
+{
+ SETUP_HOSTDATA(instance);
+ int transfered;
+ unsigned char **data;
+ volatile int *count;
+
+ if (!hostdata->connected) {
+ printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
+ "no connected cmd\n", HOSTNO);
+ return;
+ }
+
+ DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+ HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+ NCR5380_read(STATUS_REG));
+
+ if((sun3scsi_dma_finish())) {
+ printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO);
+ printk("please e-mail sammy@oh.verio.com with a description of how this\n");
+ printk("error was produced.\n");
+ machine_halt();
+ }
+
+ /* make sure we're not stuck in a data phase */
+ if((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH |
+ BASR_ACK)) ==
+ (BASR_PHASE_MATCH | BASR_ACK)) {
+ printk("scsi%d: BASR %02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG));
+ printk("scsi%d: bus stuck in data phase -- probably a
+ single byte overrun!\n", HOSTNO);
+ printk("not prepared for this error!\n");
+ printk("please e-mail sammy@oh.verio.com with a description of how this\n");
+ printk("error was produced.\n");
+ machine_halt();
+ }
+
+
+
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+ hostdata->dma_len = 0;
+
+ data = (unsigned char **) &(hostdata->connected->SCp.ptr);
+ count = &(hostdata->connected->SCp.this_residual);
+ *data += transfered;
+ *count -= transfered;
+
+}
+#endif /* REAL_DMA */
+
+
+/*
+ * Function : void NCR5380_intr (int irq)
+ *
+ * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ * from the disconnected queue, and restarting NCR5380_main()
+ * as required.
+ *
+ * Inputs : int irq, irq that caused this interrupt.
+ *
+ */
+
+static void NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct Scsi_Host *instance = first_instance;
+ int done = 1;
+ unsigned char basr;
+
+ INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
+
+ /* Look for pending interrupts */
+ basr = NCR5380_read(BUS_AND_STATUS_REG);
+ INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
+ /* dispatch to appropriate routine if found and done=0 */
+ if (basr & BASR_IRQ) {
+ NCR_PRINT(NDEBUG_INTR);
+ if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+ done = 0;
+ ENABLE_IRQ();
+ INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
+ NCR5380_reselect(instance);
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ else if (basr & BASR_PARITY_ERROR) {
+ INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+ INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ else {
+ /*
+ * The rest of the interrupt conditions can occur only during a
+ * DMA transfer
+ */
+
+#if defined(REAL_DMA)
+ /*
+ * We should only get PHASE MISMATCH and EOP interrupts if we have
+ * DMA enabled, so do a sanity check based on the current setting
+ * of the MODE register.
+ */
+
+ if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
+ ((basr & BASR_END_DMA_TRANSFER) ||
+ !(basr & BASR_PHASE_MATCH))) {
+
+ INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+ NCR5380_dma_complete( instance );
+ done = 0;
+ ENABLE_IRQ();
+ } else
+#endif /* REAL_DMA */
+ {
+/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
+ if (basr & BASR_PHASE_MATCH)
+ printk(KERN_NOTICE "scsi%d: unknown interrupt, "
+ "BASR 0x%x, MR 0x%x, SR 0x%x\n",
+ HOSTNO, basr, NCR5380_read(MODE_REG),
+ NCR5380_read(STATUS_REG));
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ } /* if !(SELECTION || PARITY) */
+ } /* BASR & IRQ */
+ else {
+
+ printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
+ "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
+ NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+
+ if (!done) {
+ INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
+ /* Put a call to NCR5380_main() on the queue... */
+ queue_main();
+ }
+}
+
+#ifdef NCR5380_STATS
+static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+{
+# ifdef NCR5380_STAT_LIMIT
+ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+ switch (cmd->cmnd[0])
+ {
+ case WRITE:
+ case WRITE_6:
+ case WRITE_10:
+ hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/
+ hostdata->pendingw--;
+ break;
+ case READ:
+ case READ_6:
+ case READ_10:
+ hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/
+ hostdata->pendingr--;
+ break;
+ }
+}
+#endif
+
+/*
+ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
+ * int tag);
+ *
+ * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
+ * including ARBITRATION, SELECTION, and initial message out for
+ * IDENTIFY and queue messages.
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this
+ * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
+ * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
+ * the command that is presently connected.
+ *
+ * Returns : -1 if selection could not execute for some reason,
+ * 0 if selection succeeded or failed because the target
+ * did not respond.
+ *
+ * Side effects :
+ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * with registers as they should have been on entry - ie
+ * SELECT_ENABLE will be set appropriately, the NCR5380
+ * will cease to drive any SCSI bus signals.
+ *
+ * If successful : I_T_L or I_T_L_Q nexus will be established,
+ * instance->connected will be set to cmd.
+ * SELECT interrupt will be disabled.
+ *
+ * If failed (no target) : cmd->scsi_done() will be called, and the
+ * cmd->result host byte set to DID_BAD_TARGET.
+ */
+
+static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+{
+ SETUP_HOSTDATA(instance);
+ unsigned char tmp[3], phase;
+ unsigned char *data;
+ int len;
+ unsigned long timeout;
+ unsigned long flags;
+
+ hostdata->restart_select = 0;
+ NCR_PRINT(NDEBUG_ARBITRATION);
+ ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+ instance->this_id);
+
+ /*
+ * Set the phase bits to 0, otherwise the NCR5380 won't drive the
+ * data bus during SELECTION.
+ */
+
+ save_flags(flags);
+ cli();
+ if (hostdata->connected) {
+ restore_flags(flags);
+ return -1;
+ }
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+
+ /*
+ * Start arbitration.
+ */
+
+ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+ NCR5380_write(MODE_REG, MR_ARBITRATE);
+
+ restore_flags(flags);
+
+ /* Wait for arbitration logic to complete */
+#if NCR_TIMEOUT
+ {
+ unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+ && time_before(jiffies, timeout) && !hostdata->connected)
+ ;
+ if (time_after_eq(jiffies, timeout))
+ {
+ printk("scsi : arbitration timeout at %d\n", __LINE__);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
+ }
+#else /* NCR_TIMEOUT */
+ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+ && !hostdata->connected);
+#endif
+
+ ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
+
+ if (hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ return -1;
+ }
+ /*
+ * The arbitration delay is 2.2us, but this is a minimum and there is
+ * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+ * the integral nature of udelay().
+ *
+ */
+
+ udelay(3);
+
+ /* Check for lost arbitration */
+ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
+ HOSTNO);
+ return -1;
+ }
+
+ /* after/during arbitration, BSY should be asserted.
+ IBM DPES-31080 Version S31Q works now */
+ /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
+ ICR_ASSERT_BSY ) ;
+
+ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
+ HOSTNO);
+ return -1;
+ }
+
+ /*
+ * Again, bus clear + bus settle time is 1.2us, however, this is
+ * a minimum so we'll udelay ceil(1.2)
+ */
+
+#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+ /* ++roman: But some targets (see above :-) seem to need a bit more... */
+ udelay(15);
+#else
+ udelay(2);
+#endif
+
+ if (hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
+ }
+
+ ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+
+ /*
+ * Now that we have won arbitration, start Selection process, asserting
+ * the host and target ID's on the SCSI bus.
+ */
+
+ NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));
+
+ /*
+ * Raise ATN while SEL is true before BSY goes false from arbitration,
+ * since this is the only way to guarantee that we'll get a MESSAGE OUT
+ * phase immediately after selection.
+ */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+ NCR5380_write(MODE_REG, MR_BASE);
+
+ /*
+ * Reselect interrupts must be turned off prior to the dropping of BSY,
+ * otherwise we will trigger an interrupt.
+ */
+
+ if (hostdata->connected) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
+ }
+
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+
+ /*
+ * The initiator shall then wait at least two deskew delays and release
+ * the BSY signal.
+ */
+ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
+
+ /* Reset BSY */
+ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
+ ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+ /*
+ * Something weird happens when we cease to drive BSY - looks
+ * like the board/chip is letting us do another read before the
+ * appropriate propagation delay has expired, and we're confusing
+ * a BSY signal from ourselves as the target's response to SELECTION.
+ *
+ * A small delay (the 'C++' frontend breaks the pipeline with an
+ * unnecessary jump, making it work on my 386-33/Trantor T128, the
+ * tighter 'C' code breaks and requires this) solves the problem -
+ * the 1 us delay is arbitrary, and only used because this delay will
+ * be the same on other platforms and since it works here, it should
+ * work there.
+ *
+ * wingel suggests that this could be due to failing to wait
+ * one deskew delay.
+ */
+
+ udelay(1);
+
+ SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target);
+
+ /*
+ * The SCSI specification calls for a 250 ms timeout for the actual
+ * selection.
+ */
+
+ timeout = jiffies + 25;
+
+ /*
+ * XXX very interesting - we're seeing a bounce where the BSY we
+ * asserted is being reflected / still asserted (propagation delay?)
+ * and it's detecting as true. Sigh.
+ */
+
+#if 0
+ /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
+ * IO while SEL is true. But again, there are some disks out the in the
+ * world that do that nevertheless. (Somebody claimed that this announces
+ * reselection capability of the target.) So we better skip that test and
+ * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
+ */
+
+ while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
+ (SR_BSY | SR_IO)));
+
+ if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==
+ (SR_SEL | SR_IO)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_reselect(instance);
+ printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
+ HOSTNO);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
+#else
+ while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
+#endif
+
+ /*
+ * No less than two deskew delays after the initiator detects the
+ * BSY signal is true, it shall release the SEL signal and may
+ * change the DATA BUS. -wingel
+ */
+
+ udelay(1);
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+ if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ if (hostdata->targets_present & (1 << cmd->target)) {
+ printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
+ if (hostdata->restart_select)
+ printk(KERN_NOTICE "\trestart select\n");
+ NCR_PRINT(NDEBUG_ANY);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
+ cmd->result = DID_BAD_TARGET << 16;
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( cmd );
+#endif
+ cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return 0;
+ }
+
+ hostdata->targets_present |= (1 << cmd->target);
+
+ /*
+ * Since we followed the SCSI spec, and raised ATN while SEL
+ * was true but before BSY was false during selection, the information
+ * transfer phase should be a MESSAGE OUT phase so that we can send the
+ * IDENTIFY message.
+ *
+ * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+ * message (2 bytes) with a tag ID that we increment with every command
+ * until it wraps back to 0.
+ *
+ * XXX - it turns out that there are some broken SCSI-II devices,
+ * which claim to support tagged queuing but fail when more than
+ * some number of commands are issued at once.
+ */
+
+ /* Wait for start of REQ/ACK handshake */
+ while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+ SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+ HOSTNO, cmd->target);
+ tmp[0] = IDENTIFY(1, cmd->lun);
+
+#ifdef SUPPORT_TAGS
+ if (cmd->tag != TAG_NONE) {
+ tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
+ tmp[2] = cmd->tag;
+ len = 3;
+ } else
+ len = 1;
+#else
+ len = 1;
+ cmd->tag=0;
+#endif /* SUPPORT_TAGS */
+
+ /* Send message(s) */
+ data = tmp;
+ phase = PHASE_MSGOUT;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
+ /* XXX need to handle errors here */
+ hostdata->connected = cmd;
+#ifndef SUPPORT_TAGS
+ hostdata->busy[cmd->target] |= (1 << cmd->lun);
+#endif
+
+ initialize_SCp(cmd);
+
+
+ return 0;
+}
+
+/*
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using polled I/O
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
+ *
+ * Returns : -1 when different phase is entered without transferring
+ * maximum number of bytes, 0 if all bytes are transfered or exit
+ * is in same phase.
+ *
+ * Also, *phase, *count, *data are modified in place.
+ *
+ * XXX Note : handling for bus free may be useful.
+ */
+
+/*
+ * Note : this code is not as quick as it could be, however it
+ * IS 100% reliable, and for the actual data transfer where speed
+ * counts, we will always do a pseudo DMA or DMA transfer.
+ */
+
+static int NCR5380_transfer_pio( struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
+{
+ register unsigned char p = *phase, tmp;
+ register int c = *count;
+ register unsigned char *d = *data;
+
+ /*
+ * The NCR5380 chip will only drive the SCSI bus when the
+ * phase specified in the appropriate bits of the TARGET COMMAND
+ * REGISTER match the STATUS REGISTER
+ */
+
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+ do {
+ /*
+ * Wait for assertion of REQ, after which the phase bits will be
+ * valid
+ */
+ while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+
+ HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
+
+ /* Check for phase mismatch */
+ if ((tmp & PHASE_MASK) != p) {
+ PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
+ NCR_PRINT_PHASE(NDEBUG_PIO);
+ break;
+ }
+
+ /* Do actual transfer from SCSI bus to / from memory */
+ if (!(p & SR_IO))
+ NCR5380_write(OUTPUT_DATA_REG, *d);
+ else
+ *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+
+ ++d;
+
+ /*
+ * The SCSI standard suggests that in MSGOUT phase, the initiator
+ * should drop ATN on the last byte of the message phase
+ * after REQ has been asserted for the handshake but before
+ * the initiator raises ACK.
+ */
+
+ if (!(p & SR_IO)) {
+ if (!((p & SR_MSG) && c > 1)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA);
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+ } else {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ }
+ } else {
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+ }
+
+ while (NCR5380_read(STATUS_REG) & SR_REQ);
+
+ HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+
+/*
+ * We have several special cases to consider during REQ/ACK handshaking :
+ * 1. We were in MSGOUT phase, and we are on the last byte of the
+ * message. ATN must be dropped as ACK is dropped.
+ *
+ * 2. We are in a MSGIN phase, and we are on the last byte of the
+ * message. We must exit with ACK asserted, so that the calling
+ * code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3. ACK and ATN are clear and the target may proceed as normal.
+ */
+ if (!(p == PHASE_MSGIN && c == 1)) {
+ if (p == PHASE_MSGOUT && c > 1)
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ else
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ }
+ } while (--c);
+
+ PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
+
+ *count = c;
+ *data = d;
+ tmp = NCR5380_read(STATUS_REG);
+ /* The phase read from the bus is valid if either REQ is (already)
+ * asserted or if ACK hasn't been released yet. The latter is the case if
+ * we're in MSGIN and all wanted bytes have been received. */
+ if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+ *phase = tmp & PHASE_MASK;
+ else
+ *phase = PHASE_UNKNOWN;
+
+ if (!c || (*phase == p))
+ return 0;
+ else
+ return -1;
+}
+
+/*
+ * Function : do_abort (Scsi_Host *host)
+ *
+ * Purpose : abort the currently established nexus. Should only be
+ * called from a routine which can drop into a
+ *
+ * Returns : 0 on success, -1 on failure.
+ */
+
+static int do_abort (struct Scsi_Host *host)
+{
+ unsigned char tmp, *msgptr, phase;
+ int len;
+
+ /* Request message out phase */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+ /*
+ * Wait for the target to indicate a valid phase by asserting
+ * REQ. Once this happens, we'll have either a MSGOUT phase
+ * and can immediately send the ABORT message, or we'll have some
+ * other phase and will have to source/sink data.
+ *
+ * We really don't care what value was on the bus or what value
+ * the target sees, so we just handshake.
+ */
+
+ while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
+
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+ if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+ ICR_ASSERT_ACK);
+ while (NCR5380_read(STATUS_REG) & SR_REQ);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ }
+
+ tmp = ABORT;
+ msgptr = &tmp;
+ len = 1;
+ phase = PHASE_MSGOUT;
+ NCR5380_transfer_pio (host, &phase, &len, &msgptr);
+
+ /*
+ * If we got here, and the command completed successfully,
+ * we're about to go into bus free state.
+ */
+
+ return len ? -1 : 0;
+}
+
+#if defined(REAL_DMA)
+/*
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using either real
+ * or pseudo DMA.
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
+ *
+ * Returns : -1 when different phase is entered without transferring
+ * maximum number of bytes, 0 if all bytes or transfered or exit
+ * is in same phase.
+ *
+ * Also, *phase, *count, *data are modified in place.
+ *
+ */
+
+
+static int NCR5380_transfer_dma( struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
+{
+ SETUP_HOSTDATA(instance);
+ register int c = *count;
+ register unsigned char p = *phase;
+ unsigned long flags;
+
+ /* sanity check */
+ if(!sun3_dma_setup_done) {
+ printk("scsi%d: transfer_dma without setup!\n", HOSTNO);
+ machine_halt();
+ }
+
+ hostdata->dma_len = c;
+
+ DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+ HOSTNO, (p & SR_IO) ? "reading" : "writing",
+ c, (p & SR_IO) ? "to" : "from", d);
+
+ /* netbsd turns off ints here, why not be safe and do it too */
+ save_flags(flags);
+ cli();
+
+ /* send start chain */
+ sun3_udc_write(UDC_CHN_START, UDC_CSR);
+
+ if (p & SR_IO) {
+ NCR5380_write(TARGET_COMMAND_REG, 1);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ NCR5380_write(INITIATOR_COMMAND_REG, 0);
+ NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
+ NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+ } else {
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA);
+ NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
+ NCR5380_write(START_DMA_SEND_REG, 0);
+ }
+
+ restore_flags(flags);
+
+ sun3_dma_active = 1;
+ return 0;
+}
+#endif /* defined(REAL_DMA) */
+
+/*
+ * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
+ *
+ * Purpose : run through the various SCSI phases and do as the target
+ * directs us to. Operates on the currently connected command,
+ * instance->connected.
+ *
+ * Inputs : instance, instance for which we are doing commands
+ *
+ * Side effects : SCSI things happen, the disconnected queue will be
+ * modified if a command disconnects, *instance->connected will
+ * change.
+ *
+ * XXX Note : we need to watch for bus free or a reset condition here
+ * to recover from an unexpected bus free condition.
+ */
+
+static void NCR5380_information_transfer (struct Scsi_Host *instance)
+{
+ SETUP_HOSTDATA(instance);
+ unsigned long flags;
+ unsigned char msgout = NOP;
+ int sink = 0;
+ int len;
+#if defined(REAL_DMA)
+ int transfersize;
+#endif
+ unsigned char *data;
+ unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
+ Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+
+ while (1) {
+ tmp = NCR5380_read(STATUS_REG);
+ /* We only have a valid SCSI phase when REQ is asserted */
+ if (tmp & SR_REQ) {
+ phase = (tmp & PHASE_MASK);
+ if (phase != old_phase) {
+ old_phase = phase;
+ NCR_PRINT_PHASE(NDEBUG_INFORMATION);
+ }
+
+ if(phase == PHASE_CMDOUT) {
+ void *d;
+ unsigned long count;
+
+ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+ count = cmd->SCp.buffer->length;
+ d = cmd->SCp.buffer->address;
+ } else {
+ count = cmd->SCp.this_residual;
+ d = cmd->SCp.ptr;
+ }
+#ifdef REAL_DMA
+ /* this command setup for dma yet? */
+ if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
+ != cmd))
+ {
+ sun3scsi_dma_setup(d, count,
+ cmd->request.cmd);
+ sun3_dma_setup_done = cmd;
+ }
+#endif
+ }
+
+
+ if (sink && (phase != PHASE_MSGOUT)) {
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+ ICR_ASSERT_ACK);
+ while (NCR5380_read(STATUS_REG) & SR_REQ);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ sink = 0;
+ continue;
+ }
+
+ switch (phase) {
+ case PHASE_DATAOUT:
+#if (NDEBUG & NDEBUG_NO_DATAOUT)
+ printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
+ "aborted\n", HOSTNO);
+ sink = 1;
+ do_abort(instance);
+ cmd->result = DID_ERROR << 16;
+ cmd->done(cmd);
+ return;
+#endif
+ case PHASE_DATAIN:
+ /*
+ * If there is no room left in the current buffer in the
+ * scatter-gather list, move onto the next one.
+ */
+ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+ ++cmd->SCp.buffer;
+ --cmd->SCp.buffers_residual;
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ cmd->SCp.ptr = cmd->SCp.buffer->address;
+
+ /* ++roman: Try to merge some scatter-buffers if
+ * they are at contiguous physical addresses.
+ */
+// merge_contiguous_buffers( cmd );
+ INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
+ HOSTNO, cmd->SCp.this_residual,
+ cmd->SCp.buffers_residual);
+ }
+
+ /*
+ * The preferred transfer method is going to be
+ * PSEUDO-DMA for systems that are strictly PIO,
+ * since we can let the hardware do the handshaking.
+ *
+ * For this to work, we need to know the transfersize
+ * ahead of time, since the pseudo-DMA code will sit
+ * in an unconditional loop.
+ */
+
+/* ++roman: I suggest, this should be
+ * #if def(REAL_DMA)
+ * instead of leaving REAL_DMA out.
+ */
+
+#if defined(REAL_DMA)
+// if (!cmd->device->borken &&
+ if((transfersize =
+ NCR5380_dma_xfer_len(instance,cmd,phase)) > SUN3_DMA_MINSIZE) {
+ len = transfersize;
+ cmd->SCp.phase = phase;
+
+ if (NCR5380_transfer_dma(instance, &phase,
+ &len, (unsigned char **) &cmd->SCp.ptr)) {
+ /*
+ * If the watchdog timer fires, all future
+ * accesses to this device will use the
+ * polled-IO. */
+ printk(KERN_NOTICE "scsi%d: switching target %d "
+ "lun %d to slow handshake\n", HOSTNO,
+ cmd->target, cmd->lun);
+ cmd->device->borken = 1;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ sink = 1;
+ do_abort(instance);
+ cmd->result = DID_ERROR << 16;
+ cmd->done(cmd);
+ /* XXX - need to source or sink data here, as appropriate */
+ } else {
+#ifdef REAL_DMA
+ /* ++roman: When using real DMA,
+ * information_transfer() should return after
+ * starting DMA since it has nothing more to
+ * do.
+ */
+ return;
+#else
+ cmd->SCp.this_residual -= transfersize - len;
+#endif
+ }
+ } else
+#endif /* defined(REAL_DMA) */
+ NCR5380_transfer_pio(instance, &phase,
+ (int *) &cmd->SCp.this_residual, (unsigned char **)
+ &cmd->SCp.ptr);
+#ifdef REAL_DMA
+ /* if we had intended to dma that command clear it */
+ if(sun3_dma_setup_done == cmd)
+ sun3_dma_setup_done = NULL;
+#endif
+
+ break;
+ case PHASE_MSGIN:
+ len = 1;
+ data = &tmp;
+ NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ cmd->SCp.Message = tmp;
+
+ switch (tmp) {
+ /*
+ * Linking lets us reduce the time required to get the
+ * next command out to the device, hopefully this will
+ * mean we don't waste another revolution due to the delays
+ * required by ARBITRATION and another SELECTION.
+ *
+ * In the current implementation proposal, low level drivers
+ * merely have to start the next command, pointed to by
+ * next_link, done() is called as with unlinked commands.
+ */
+#ifdef LINKED
+ case LINKED_CMD_COMPLETE:
+ case LINKED_FLG_CMD_COMPLETE:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ LNK_PRINTK("scsi%d: target %d lun %d linked command "
+ "complete.\n", HOSTNO, cmd->target, cmd->lun);
+
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /*
+ * Sanity check : A linked command should only terminate
+ * with one of these messages if there are more linked
+ * commands available.
+ */
+
+ if (!cmd->next_link) {
+ printk(KERN_NOTICE "scsi%d: target %d lun %d "
+ "linked command complete, no next_link\n",
+ HOSTNO, cmd->target, cmd->lun);
+ sink = 1;
+ do_abort (instance);
+ return;
+ }
+
+ initialize_SCp(cmd->next_link);
+ /* The next command is still part of this process; copy it
+ * and don't free it! */
+ cmd->next_link->tag = cmd->tag;
+ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+ LNK_PRINTK("scsi%d: target %d lun %d linked request "
+ "done, calling scsi_done().\n",
+ HOSTNO, cmd->target, cmd->lun);
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
+ cmd->scsi_done(cmd);
+ cmd = hostdata->connected;
+ break;
+#endif /* def LINKED */
+ case ABORT:
+ case COMMAND_COMPLETE:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ hostdata->connected = NULL;
+ QU_PRINTK("scsi%d: command for target %d, lun %d "
+ "completed\n", HOSTNO, cmd->target, cmd->lun);
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( cmd );
+ if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
+ /* Turn a QUEUE FULL status into BUSY, I think the
+ * mid level cannot handle QUEUE FULL :-( (The
+ * command is retried after BUSY). Also update our
+ * queue size to the number of currently issued
+ * commands now.
+ */
+ /* ++Andreas: the mid level code knows about
+ QUEUE_FULL now. */
+ TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+ TAG_PRINTK("scsi%d: target %d lun %d returned "
+ "QUEUE_FULL after %d commands\n",
+ HOSTNO, cmd->target, cmd->lun,
+ ta->nr_allocated);
+ if (ta->queue_size > ta->nr_allocated)
+ ta->nr_allocated = ta->queue_size;
+ }
+#else
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
+ /*
+ * I'm not sure what the correct thing to do here is :
+ *
+ * If the command that just executed is NOT a request
+ * sense, the obvious thing to do is to set the result
+ * code to the values of the stored parameters.
+ *
+ * If it was a REQUEST SENSE command, we need some way to
+ * differentiate between the failure code of the original
+ * and the failure code of the REQUEST sense - the obvious
+ * case is success, where we fall through and leave the
+ * result code unchanged.
+ *
+ * The non-obvious place is where the REQUEST SENSE failed
+ */
+
+ if (cmd->cmnd[0] != REQUEST_SENSE)
+ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+ else if (status_byte(cmd->SCp.Status) != GOOD)
+ cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+
+#ifdef AUTOSENSE
+ if ((cmd->cmnd[0] != REQUEST_SENSE) &&
+ (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+ ASEN_PRINTK("scsi%d: performing request sense\n",
+ HOSTNO);
+ cmd->cmnd[0] = REQUEST_SENSE;
+ cmd->cmnd[1] &= 0xe0;
+ cmd->cmnd[2] = 0;
+ cmd->cmnd[3] = 0;
+ cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+ cmd->cmnd[5] = 0;
+ cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+ cmd->use_sg = 0;
+ /* this is initialized from initialize_SCp
+ cmd->SCp.buffer = NULL;
+ cmd->SCp.buffers_residual = 0;
+ */
+ cmd->request_buffer = (char *) cmd->sense_buffer;
+ cmd->request_bufflen = sizeof(cmd->sense_buffer);
+
+ save_flags(flags);
+ cli();
+ LIST(cmd,hostdata->issue_queue);
+ NEXT(cmd) = hostdata->issue_queue;
+ hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+ restore_flags(flags);
+ QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+ "issue queue\n", H_NO(cmd));
+ } else
+#endif /* def AUTOSENSE */
+ {
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
+ cmd->scsi_done(cmd);
+ }
+
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
+ * arbitration can resume.
+ */
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+ barrier();
+
+ return;
+ case MESSAGE_REJECT:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ switch (hostdata->last_message) {
+ case HEAD_OF_QUEUE_TAG:
+ case ORDERED_QUEUE_TAG:
+ case SIMPLE_QUEUE_TAG:
+ /* The target obviously doesn't support tagged
+ * queuing, even though it announced this ability in
+ * its INQUIRY data ?!? (maybe only this LUN?) Ok,
+ * clear 'tagged_supported' and lock the LUN, since
+ * the command is treated as untagged further on.
+ */
+ cmd->device->tagged_supported = 0;
+ hostdata->busy[cmd->target] |= (1 << cmd->lun);
+ cmd->tag = TAG_NONE;
+ TAG_PRINTK("scsi%d: target %d lun %d rejected "
+ "QUEUE_TAG message; tagged queuing "
+ "disabled\n",
+ HOSTNO, cmd->target, cmd->lun);
+ break;
+ }
+ break;
+ case DISCONNECT:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ save_flags(flags);
+ cli();
+ cmd->device->disconnect = 1;
+ LIST(cmd,hostdata->disconnected_queue);
+ NEXT(cmd) = hostdata->disconnected_queue;
+ hostdata->connected = NULL;
+ hostdata->disconnected_queue = cmd;
+ restore_flags(flags);
+ QU_PRINTK("scsi%d: command for target %d lun %d was "
+ "moved from connected to the "
+ "disconnected_queue\n", HOSTNO,
+ cmd->target, cmd->lun);
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
+ * arbitration can resume.
+ */
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /* Wait for bus free to avoid nasty timeouts */
+ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+ barrier();
+ return;
+ /*
+ * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+ * operation, in violation of the SCSI spec so we can safely
+ * ignore SAVE/RESTORE pointers calls.
+ *
+ * Unfortunately, some disks violate the SCSI spec and
+ * don't issue the required SAVE_POINTERS message before
+ * disconnecting, and we have to break spec to remain
+ * compatible.
+ */
+ case SAVE_POINTERS:
+ case RESTORE_POINTERS:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ break;
+ case EXTENDED_MESSAGE:
+/*
+ * Extended messages are sent in the following format :
+ * Byte
+ * 0 EXTENDED_MESSAGE == 1
+ * 1 length (includes one byte for code, doesn't
+ * include first two bytes)
+ * 2 code
+ * 3..length+1 arguments
+ *
+ * Start the extended message buffer with the EXTENDED_MESSAGE
+ * byte, since print_msg() wants the whole thing.
+ */
+ extended_msg[0] = EXTENDED_MESSAGE;
+ /* Accept first byte by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
+
+ len = 2;
+ data = extended_msg + 1;
+ phase = PHASE_MSGIN;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+ (int)extended_msg[1], (int)extended_msg[2]);
+
+ if (!len && extended_msg[1] <=
+ (sizeof (extended_msg) - 1)) {
+ /* Accept third byte by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ len = extended_msg[1] - 1;
+ data = extended_msg + 3;
+ phase = PHASE_MSGIN;
+
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ EXT_PRINTK("scsi%d: message received, residual %d\n",
+ HOSTNO, len);
+
+ switch (extended_msg[2]) {
+ case EXTENDED_SDTR:
+ case EXTENDED_WDTR:
+ case EXTENDED_MODIFY_DATA_POINTER:
+ case EXTENDED_EXTENDED_IDENTIFY:
+ tmp = 0;
+ }
+ } else if (len) {
+ printk(KERN_NOTICE "scsi%d: error receiving "
+ "extended message\n", HOSTNO);
+ tmp = 0;
+ } else {
+ printk(KERN_NOTICE "scsi%d: extended message "
+ "code %02x length %d is too long\n",
+ HOSTNO, extended_msg[2], extended_msg[1]);
+ tmp = 0;
+ }
+ /* Fall through to reject message */
+
+ /*
+ * If we get something weird that we aren't expecting,
+ * reject it.
+ */
+ default:
+ if (!tmp) {
+ printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
+ print_msg (extended_msg);
+ printk("\n");
+ } else if (tmp != EXTENDED_MESSAGE)
+ printk(KERN_DEBUG "scsi%d: rejecting unknown "
+ "message %02x from target %d, lun %d\n",
+ HOSTNO, tmp, cmd->target, cmd->lun);
+ else
+ printk(KERN_DEBUG "scsi%d: rejecting unknown "
+ "extended message "
+ "code %02x, length %d from target %d, lun %d\n",
+ HOSTNO, extended_msg[1], extended_msg[0],
+ cmd->target, cmd->lun);
+
+
+ msgout = MESSAGE_REJECT;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ break;
+ } /* switch (tmp) */
+ break;
+ case PHASE_MSGOUT:
+ len = 1;
+ data = &msgout;
+ hostdata->last_message = msgout;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ if (msgout == ABORT) {
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( cmd );
+#else
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+ hostdata->connected = NULL;
+ cmd->result = DID_ERROR << 16;
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
+ cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return;
+ }
+ msgout = NOP;
+ break;
+ case PHASE_CMDOUT:
+ len = cmd->cmd_len;
+ data = cmd->cmnd;
+ /*
+ * XXX for performance reasons, on machines with a
+ * PSEUDO-DMA architecture we should probably
+ * use the dma transfer function.
+ */
+ NCR5380_transfer_pio(instance, &phase, &len,
+ &data);
+ break;
+ case PHASE_STATIN:
+ len = 1;
+ data = &tmp;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ cmd->SCp.Status = tmp;
+ break;
+ default:
+ printk("scsi%d: unknown phase\n", HOSTNO);
+ NCR_PRINT(NDEBUG_ANY);
+ } /* switch(phase) */
+ } /* if (tmp * SR_REQ) */
+ } /* while (1) */
+}
+
+/*
+ * Function : void NCR5380_reselect (struct Scsi_Host *instance)
+ *
+ * Purpose : does reselection, initializing the instance->connected
+ * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
+ * nexus has been reestablished,
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+/* it might eventually prove necessary to do a dma setup on
+ reselection, but it doesn't seem to be needed now -- sam */
+
+static void NCR5380_reselect (struct Scsi_Host *instance)
+{
+ SETUP_HOSTDATA(instance);
+ unsigned char target_mask;
+ unsigned char lun;
+#ifdef SUPPORT_TAGS
+ unsigned char tag;
+#endif
+ unsigned char msg[3];
+ Scsi_Cmnd *tmp = NULL, *prev;
+/* unsigned long flags; */
+
+ /*
+ * Disable arbitration, etc. since the host adapter obviously
+ * lost, and tell an interrupted NCR5380_select() to restart.
+ */
+
+ NCR5380_write(MODE_REG, MR_BASE);
+ hostdata->restart_select = 1;
+
+ target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+
+ RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
+
+ /*
+ * At this point, we have detected that our SCSI ID is on the bus,
+ * SEL is true and BSY was false for at least one bus settle delay
+ * (400 ns).
+ *
+ * We must assert BSY ourselves, until the target drops the SEL
+ * signal.
+ */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+
+ while (NCR5380_read(STATUS_REG) & SR_SEL);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ /*
+ * Wait for target to go into MSGIN.
+ */
+
+ while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+#if 1
+ // acknowledge toggle to MSGIN
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN));
+
+ // peek at the byte without really hitting the bus
+ msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG);
+#endif
+
+ if (!msg[0] & 0x80) {
+ printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+ print_msg(msg);
+ do_abort(instance);
+ return;
+ }
+ lun = (msg[0] & 0x07);
+
+ /*
+ * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
+ * just reestablished, and remove it from the disconnected queue.
+ */
+
+ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
+ tmp; prev = tmp, tmp = NEXT(tmp) ) {
+ if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
+#ifdef SUPPORT_TAGS
+ && (tag == tmp->tag)
+#endif
+ ) {
+ if (prev) {
+ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+ NEXT(prev) = NEXT(tmp);
+ } else {
+ REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+ hostdata->disconnected_queue = NEXT(tmp);
+ }
+ NEXT(tmp) = NULL;
+ break;
+ }
+ }
+
+ if (!tmp) {
+ printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
+#ifdef SUPPORT_TAGS
+ "tag %d "
+#endif
+ "not in disconnected_queue.\n",
+ HOSTNO, target_mask, lun
+#ifdef SUPPORT_TAGS
+ , tag
+#endif
+ );
+ /*
+ * Since we have an established nexus that we can't do anything
+ * with, we must abort it.
+ */
+ do_abort(instance);
+ return;
+ }
+#if 1
+ /* engage dma setup for the command we just saw */
+ {
+ void *d;
+ unsigned long count;
+
+ if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) {
+ count = tmp->SCp.buffer->length;
+ d = tmp->SCp.buffer->address;
+ } else {
+ count = tmp->SCp.this_residual;
+ d = tmp->SCp.ptr;
+ }
+#ifdef REAL_DMA
+ /* setup this command for dma if not already */
+ if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
+ != tmp))
+ {
+ sun3scsi_dma_setup(d, count,
+ tmp->request.cmd);
+ sun3_dma_setup_done = tmp;
+ }
+#endif
+ }
+#endif
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+#ifdef SUPPORT_TAGS
+ /* If the phase is still MSGIN, the target wants to send some more
+ * messages. In case it supports tagged queuing, this is probably a
+ * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
+ */
+ tag = TAG_NONE;
+ if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+ /* Accept previous IDENTIFY message by clearing ACK */
+ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+ len = 2;
+ data = msg+1;
+ if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+ msg[1] == SIMPLE_QUEUE_TAG)
+ tag = msg[2];
+ TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
+ "reselection\n", HOSTNO, target_mask, lun, tag);
+ }
+#endif
+
+ hostdata->connected = tmp;
+ RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+ HOSTNO, tmp->target, tmp->lun, tmp->tag);
+}
+
+
+/*
+ * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : abort a command
+ *
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
+ * host byte of the result field to, if zero DID_ABORTED is
+ * used.
+ *
+ * Returns : 0 - success, -1 on failure.
+ *
+ * XXX - there is no way to abort the command that is currently
+ * connected, you have to wait for it to complete. If this is
+ * a problem, we could implement longjmp() / setjmp(), setjmp()
+ * called where the loop started in NCR5380_main().
+ */
+
+#ifndef NCR5380_abort
+static
+#endif
+int NCR5380_abort (Scsi_Cmnd *cmd)
+{
+ struct Scsi_Host *instance = cmd->host;
+ SETUP_HOSTDATA(instance);
+ Scsi_Cmnd *tmp, **prev;
+ unsigned long flags;
+
+ printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
+ print_Scsi_Cmnd (cmd);
+
+ NCR5380_print_status (instance);
+
+ save_flags(flags);
+ cli();
+
+ ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+ NCR5380_read(BUS_AND_STATUS_REG),
+ NCR5380_read(STATUS_REG));
+
+#if 1
+/*
+ * Case 1 : If the command is the currently executing command,
+ * we'll set the aborted flag and return control so that
+ * information transfer routine can exit cleanly.
+ */
+
+ if (hostdata->connected == cmd) {
+
+ ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
+/*
+ * We should perform BSY checking, and make sure we haven't slipped
+ * into BUS FREE.
+ */
+
+/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
+/*
+ * Since we can't change phases until we've completed the current
+ * handshake, we have to source or sink a byte of data if the current
+ * phase is not MSGOUT.
+ */
+
+/*
+ * Return control to the executing NCR drive so we can clear the
+ * aborted flag and get back into our main loop.
+ */
+
+ if (do_abort(instance) == 0) {
+ hostdata->aborted = 1;
+ hostdata->connected = NULL;
+ cmd->result = DID_ABORT << 16;
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( cmd );
+#else
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+ restore_flags(flags);
+ cmd->scsi_done(cmd);
+ return SCSI_ABORT_SUCCESS;
+ } else {
+/* restore_flags(flags); */
+ printk("scsi%d: abort of connected command failed!\n", HOSTNO);
+ return SCSI_ABORT_ERROR;
+ }
+ }
+#endif
+
+/*
+ * Case 2 : If the command hasn't been issued yet, we simply remove it
+ * from the issue queue.
+ */
+ for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue),
+ tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+ (*prev) = NEXT(tmp);
+ NEXT(tmp) = NULL;
+ tmp->result = DID_ABORT << 16;
+ restore_flags(flags);
+ ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+ HOSTNO);
+ /* Tagged queuing note: no tag to free here, hasn't been assigned
+ * yet... */
+ tmp->scsi_done(tmp);
+ return SCSI_ABORT_SUCCESS;
+ }
+
+/*
+ * Case 3 : If any commands are connected, we're going to fail the abort
+ * and let the high level SCSI driver retry at a later time or
+ * issue a reset.
+ *
+ * Timeouts, and therefore aborted commands, will be highly unlikely
+ * and handling them cleanly in this situation would make the common
+ * case of noresets less efficient, and would pollute our code. So,
+ * we fail.
+ */
+
+ if (hostdata->connected) {
+ restore_flags(flags);
+ ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
+ return SCSI_ABORT_SNOOZE;
+ }
+
+/*
+ * Case 4: If the command is currently disconnected from the bus, and
+ * there are no connected commands, we reconnect the I_T_L or
+ * I_T_L_Q nexus associated with it, go into message out, and send
+ * an abort message.
+ *
+ * This case is especially ugly. In order to reestablish the nexus, we
+ * need to call NCR5380_select(). The easiest way to implement this
+ * function was to abort if the bus was busy, and let the interrupt
+ * handler triggered on the SEL for reselect take care of lost arbitrations
+ * where necessary, meaning interrupts need to be enabled.
+ *
+ * When interrupts are enabled, the queues may change - so we
+ * can't remove it from the disconnected queue before selecting it
+ * because that could cause a failure in hashing the nexus if that
+ * device reselected.
+ *
+ * Since the queues may change, we can't use the pointers from when we
+ * first locate it.
+ *
+ * So, we must first locate the command, and if NCR5380_select()
+ * succeeds, then issue the abort, relocate the command and remove
+ * it from the disconnected queue.
+ */
+
+ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+ tmp = NEXT(tmp))
+ if (cmd == tmp) {
+ restore_flags(flags);
+ ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
+
+ if (NCR5380_select (instance, cmd, (int) cmd->tag))
+ return SCSI_ABORT_BUSY;
+
+ ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
+
+ do_abort (instance);
+
+ save_flags(flags);
+ cli();
+ for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue),
+ tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
+ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+ *prev = NEXT(tmp);
+ NEXT(tmp) = NULL;
+ tmp->result = DID_ABORT << 16;
+ /* We must unlock the tag/LUN immediately here, since the
+ * target goes to BUS FREE and doesn't send us another
+ * message (COMMAND_COMPLETE or the like)
+ */
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( tmp );
+#else
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+ restore_flags(flags);
+ tmp->scsi_done(tmp);
+ return SCSI_ABORT_SUCCESS;
+ }
+ }
+
+/*
+ * Case 5 : If we reached this point, the command was not found in any of
+ * the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
+
+ restore_flags(flags);
+ printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
+ KERN_INFO " before abortion\n", HOSTNO);
+
+ return SCSI_ABORT_NOT_RUNNING;
+}
+
+
+/*
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
+ *
+ * Purpose : reset the SCSI bus.
+ *
+ * Returns : SCSI_RESET_WAKEUP
+ *
+ */
+
+int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+{
+ SETUP_HOSTDATA(cmd->host);
+ int i;
+ unsigned long flags;
+#if 1
+ Scsi_Cmnd *connected, *disconnected_queue;
+#endif
+
+
+ NCR5380_print_status (cmd->host);
+
+ /* get in phase */
+ NCR5380_write( TARGET_COMMAND_REG,
+ PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+ /* assert RST */
+ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+ udelay (40);
+ /* reset NCR registers */
+ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+ NCR5380_write( MODE_REG, MR_BASE );
+ NCR5380_write( TARGET_COMMAND_REG, 0 );
+ NCR5380_write( SELECT_ENABLE_REG, 0 );
+ /* ++roman: reset interrupt condition! otherwise no interrupts don't get
+ * through anymore ... */
+ (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
+ /* XXX see below XXX */
+
+ /* MSch: old-style reset: actually abort all command processing here */
+
+ /* After the reset, there are no more connected or disconnected commands
+ * and no busy units; to avoid problems with re-inserting the commands
+ * into the issue_queue (via scsi_done()), the aborted commands are
+ * remembered in local variables first.
+ */
+ save_flags(flags);
+ cli();
+ connected = (Scsi_Cmnd *)hostdata->connected;
+ hostdata->connected = NULL;
+ disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+ hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+ free_all_tags();
+#endif
+ for( i = 0; i < 8; ++i )
+ hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
+#endif
+ restore_flags(flags);
+
+ /* In order to tell the mid-level code which commands were aborted,
+ * set the command status to DID_RESET and call scsi_done() !!!
+ * This ultimately aborts processing of these commands in the mid-level.
+ */
+
+ if ((cmd = connected)) {
+ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+ cmd->scsi_done( cmd );
+ }
+
+ for (i = 0; (cmd = disconnected_queue); ++i) {
+ disconnected_queue = NEXT(cmd);
+ NEXT(cmd) = NULL;
+ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+ cmd->scsi_done( cmd );
+ }
+ if (i > 0)
+ ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
+
+
+ /* since all commands have been explicitly terminated, we need to tell
+ * the midlevel code that the reset was SUCCESSFUL, and there is no
+ * need to 'wake up' the commands by a request_sense
+ */
+ return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+#else /* 1 */
+
+ /* MSch: new-style reset handling: let the mid-level do what it can */
+
+ /* ++guenther: MID-LEVEL IS STILL BROKEN.
+ * Mid-level is supposed to requeue all commands that were active on the
+ * various low-level queues. In fact it does this, but that's not enough
+ * because all these commands are subject to timeout. And if a timeout
+ * happens for any removed command, *_abort() is called but all queues
+ * are now empty. Abort then gives up the falcon lock, which is fatal,
+ * since the mid-level will queue more commands and must have the lock
+ * (it's all happening inside timer interrupt handler!!).
+ * Even worse, abort will return NOT_RUNNING for all those commands not
+ * on any queue, so they won't be retried ...
+ *
+ * Conclusion: either scsi.c disables timeout for all resetted commands
+ * immediately, or we loose! As of linux-2.0.20 it doesn't.
+ */
+
+ /* After the reset, there are no more connected or disconnected commands
+ * and no busy units; so clear the low-level status here to avoid
+ * conflicts when the mid-level code tries to wake up the affected
+ * commands!
+ */
+
+ if (hostdata->issue_queue)
+ ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
+ if (hostdata->connected)
+ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+ if (hostdata->disconnected_queue)
+ ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+
+ save_flags(flags);
+ cli();
+ hostdata->issue_queue = NULL;
+ hostdata->connected = NULL;
+ hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+ free_all_tags();
+#endif
+ for( i = 0; i < 8; ++i )
+ hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
+#endif
+ restore_flags(flags);
+
+ /* we did no complete reset of all commands, so a wakeup is required */
+ return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
+#endif /* 1 */
+}
+
+/* Local Variables: */
+/* tab-width: 8 */
+/* End: */
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index ba0be94dd..45f504fa3 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -1,6 +1,8 @@
/*
* Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
*
+ * Sun3 DMA routines added by Sam Creasey (sammy@oh.verio.com)
+ *
* Adapted from mac_scsinew.c:
*/
/*
@@ -44,13 +46,10 @@
*/
/*
- * $Log: mac_NCR5380.c,v $
+ * $Log: sun3_NCR5380.c,v $
*/
#define AUTOSENSE
-#if 0
-#define PSEUDO_DMA
-#endif
#include <linux/types.h>
#include <linux/stddef.h>
@@ -68,6 +67,9 @@
#include <asm/system.h>
#include <asm/sun3ints.h>
+#include <asm/dvma.h>
+/* dma on! */
+#define REAL_DMA
#include "scsi.h"
#include "hosts.h"
@@ -75,17 +77,12 @@
#include "NCR5380.h"
#include "constants.h"
-#if 0
-#define NDEBUG (NDEBUG_INTR | NDEBUG_PSEUDO_DMA | NDEBUG_ARBITRATION | NDEBUG_SELECTION | NDEBUG_RESELECTION)
-#define NCR_TIMEOUT 100
-#else
-#define NDEBUG (NDEBUG_ABORT)
-#endif
-
#define USE_WRAPPER
#define RESET_BOOT
#define DRIVER_SETUP
+#define NDEBUG 0
+
/*
* BUG can be used to trigger a strange code-size related hang on 2.1 kernels
*/
@@ -94,14 +91,14 @@
#undef DRIVER_SETUP
#endif
-#define ENABLE_IRQ() sun3_enable_irq( IRQ_SUN3_SCSI );
-#define DISABLE_IRQ() sun3_enable_irq( IRQ_SUN3_SCSI );
+#undef SUPPORT_TAGS
+
+#define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI );
-/* extern void via_scsi_clear(void); */
static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
-static char sun3scsi_read(struct Scsi_Host *instance, int reg);
-static void sun3scsi_write(struct Scsi_Host *instance, int reg, int value);
+static inline unsigned char sun3scsi_read(int reg);
+static inline void sun3scsi_write(int reg, int value);
static int setup_can_queue = -1;
static int setup_cmd_per_lun = -1;
@@ -111,38 +108,65 @@ static int setup_use_tagged_queuing = -1;
#endif
static int setup_hostid = -1;
-static int polled_scsi_on = 0;
+static Scsi_Cmnd *sun3_dma_setup_done = NULL;
#define AFTER_RESET_DELAY (HZ/2)
-static volatile unsigned char *sun3_scsi_regp = IOBASE_SUN3_SCSI;
-/*
-static volatile unsigned char *sun3_scsi_drq = NULL;
-static volatile unsigned char *sun3_scsi_nodrq = NULL;
-*/
+/* ms to wait after hitting dma regs */
+#define SUN3_DMA_DELAY 5
+
+/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
+#define SUN3_DVMA_BUFSIZE 0xe000
+
+/* minimum number of bytes to to dma on */
+#define SUN3_DMA_MINSIZE 128
+
+static struct proc_dir_entry proc_scsi_sun3_5380 = {
+ PROC_SCSI_MAC, 13, "Sun3 5380 SCSI", S_IFDIR | S_IRUGO, S_IXUGO, 2
+};
+
+static volatile unsigned char *sun3_scsi_regp;
+static volatile struct sun3_dma_regs *dregs;
+static unsigned char *dmabuf = NULL; /* dma memory buffer */
+static struct sun3_udc_regs *udc_regs = NULL;
+static void *sun3_dma_orig_addr = NULL;
+static unsigned long sun3_dma_orig_count = 0;
+static int sun3_dma_active = 0;
/*
- * Function : sun3_scsi_setup(char *str, int *ints)
- *
- * Purpose : booter command line initialization of the overrides array,
- *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- * equal to the number of ints.
- *
- * TODO: make it actually work!
- *
+ * NCR 5380 register access functions
*/
-void sun3_scsi_setup(char *str, int *ints) {
- printk("sun3_scsi_setup() called\n");
- setup_can_queue = -1;
- setup_cmd_per_lun = -1;
- setup_sg_tablesize = -1;
- setup_hostid = -1;
-#ifdef SUPPORT_TAGS
- setup_use_tagged_queuing = -1;
-#endif
- printk("sun3_scsi_setup() done\n");
+static inline unsigned char sun3scsi_read(int reg)
+{
+ return( sun3_scsi_regp[reg] );
+}
+
+static inline void sun3scsi_write(int reg, int value)
+{
+ sun3_scsi_regp[reg] = value;
+}
+
+/* dma controller register access functions */
+
+static inline unsigned short sun3_udc_read(unsigned char reg)
+{
+ unsigned short ret;
+
+ dregs->udc_addr = UDC_CSR;
+ udelay(SUN3_DMA_DELAY);
+ ret = dregs->udc_data;
+ udelay(SUN3_DMA_DELAY);
+
+ return ret;
+}
+
+static inline void sun3_udc_write(unsigned short val, unsigned char reg)
+{
+ dregs->udc_addr = reg;
+ udelay(SUN3_DMA_DELAY);
+ dregs->udc_data = val;
+ udelay(SUN3_DMA_DELAY);
}
/*
@@ -165,7 +189,6 @@ static struct Scsi_Host *default_instance;
int sun3scsi_detect(Scsi_Host_Template * tpnt)
{
unsigned long ioaddr, iopte;
- unsigned short *ioptr;
int count = 0;
static int called = 0;
struct Scsi_Host *instance;
@@ -173,9 +196,7 @@ int sun3scsi_detect(Scsi_Host_Template * tpnt)
if(called)
return 0;
-printk("sun3scsi_detect(0x%p)\n",tpnt);
-
- tpnt->proc_name = "Sun3 5380 SCSI"; /* Could you spell "ewww..."? */
+ tpnt->proc_dir = &proc_scsi_sun3_5380;
/* setup variables */
tpnt->can_queue =
@@ -204,7 +225,6 @@ printk("sun3scsi_detect(0x%p)\n",tpnt);
if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
IOBASE_SUN3_SCSI) {
count = 1;
-printk("Found ioaddr in pmeg\n");
break;
}
}
@@ -214,22 +234,19 @@ printk("Found ioaddr in pmeg\n");
return 0;
}
- sun3_scsi_regp = ioaddr;
-
- /* doing some stuff like resetting DVMA: */
- ioptr = ioaddr;
- *(ioptr+8) = 0;
- udelay(10);
- *(ioptr+9) = 0;
- udelay(10);
- *(ioptr+12) = 0;
- udelay(10);
- *(ioptr+12) = 0x7;
- udelay(10);
- printk("SCSI status reg = %x\n", *(ioptr+12));
- udelay(10);
- *(ioptr+13) = 0;
- udelay(10);
+ sun3_scsi_regp = (unsigned char *)ioaddr;
+ dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
+
+ if((dmabuf = sun3_dvma_malloc(SUN3_DVMA_BUFSIZE)) == NULL) {
+ printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
+ return 0;
+ }
+
+ if((udc_regs = sun3_dvma_malloc(sizeof(struct sun3_udc_regs)))
+ == NULL) {
+ printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
+ return 0;
+ }
#ifdef SUPPORT_TAGS
if (setup_use_tagged_queuing < 0)
@@ -239,18 +256,6 @@ printk("Found ioaddr in pmeg\n");
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
default_instance = instance;
-/*
- if (macintosh_config->ident == MAC_MODEL_IIFX) {
- mac_scsi_regp = via1_regp+0x8000;
- mac_scsi_drq = via1_regp+0x6000;
- mac_scsi_nodrq = via1_regp+0x12000;
- } else {
- mac_scsi_regp = via1_regp+0x10000;
- mac_scsi_drq = via1_regp+0x6000;
- mac_scsi_nodrq = via1_regp+0x12000;
- }
-*/
-
instance->io_port = (unsigned long) ioaddr;
instance->irq = IRQ_SUN3_SCSI;
@@ -260,15 +265,20 @@ printk("Found ioaddr in pmeg\n");
((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
- if (instance->irq != IRQ_NONE)
- if (sun3_request_irq(instance->irq, sun3scsi_intr,
- 0, "Sun3SCSI-5380", NULL)) {
- printk("scsi%d: IRQ%d not free, interrupts disabled\n",
- instance->host_no, instance->irq);
- instance->irq = IRQ_NONE;
- }
-
- printk("scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
+ if (request_irq(instance->irq, scsi_sun3_intr,
+ 0, "Sun3SCSI-5380", NULL)) {
+#ifndef REAL_DMA
+ printk("scsi%d: IRQ%d not free, interrupts disabled\n",
+ instance->host_no, instance->irq);
+ instance->irq = IRQ_NONE;
+#else
+ printk("scsi%d: IRQ%d not free, bailing out\n",
+ instance->host_no, instance->irq);
+ return 0;
+#endif
+ }
+
+ printk("scsi%d: Sun3 5380 at port %lX irq", instance->host_no, instance->io_port);
if (instance->irq == IRQ_NONE)
printk ("s disabled");
else
@@ -280,6 +290,12 @@ printk("Found ioaddr in pmeg\n");
NCR5380_print_options(instance);
printk("\n");
+ dregs->csr = 0;
+ udelay(SUN3_DMA_DELAY);
+ dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
+ udelay(SUN3_DMA_DELAY);
+ dregs->fifo_count = 0;
+
called = 1;
return 1;
}
@@ -342,34 +358,34 @@ const char * sun3scsi_info (struct Scsi_Host *spnt) {
return "";
}
+// safe bits for the CSR
+#define CSR_GOOD 0x060f
-/*
- * NCR 5380 register access functions
- */
-
-static char sun3scsi_read(struct Scsi_Host *instance, int reg)
+static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
{
-/*
-printk("sun3scsi_read(instance=0x%p, reg=0x%x): @0x%p= %d\n",instance,reg,sun3_scsi_regp,sun3_scsi_regp[reg]);
-*/
- return( sun3_scsi_regp[reg] );
-}
+ unsigned short csr = dregs->csr;
-static void sun3scsi_write(struct Scsi_Host *instance, int reg, int value)
-{
-/*
- printk("sun3scsi_write(instance=0x%p, reg=0x%x, value=0x%x)\n", instance, reg, value);
-*/
- sun3_scsi_regp[reg] = value;
-}
+ if(csr & ~CSR_GOOD) {
+ if(csr & CSR_DMA_BUSERR) {
+ printk("scsi%d: bus error in dma\n", default_instance->host_no);
+ }
-#include "NCR5380.c"
+ if(csr & CSR_DMA_CONFLICT) {
+ printk("scsi%d: dma conflict\n", default_instance->host_no);
+ }
+ }
+
+ if(csr & (CSR_SDB_INT | CSR_DMA_INT))
+ NCR5380_intr(irq, dummy, fp);
+}
/*
* Debug stuff - to be called on NMI, or sysrq key. Use at your own risk;
* reentering NCR5380_print_status seems to have ugly side effects
*/
+/* this doesn't seem to get used at all -- sam */
+#if 0
void sun3_sun3_debug (void)
{
unsigned long flags;
@@ -381,32 +397,141 @@ void sun3_sun3_debug (void)
NCR5380_print_status(default_instance);
restore_flags(flags);
}
-#if 0
- polled_scsi_on = 1;
-#endif
}
-/*
- * Helper function for interrupt trouble. More ugly side effects here.
- */
+#endif
+
-void scsi_sun3_polled (void)
+/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
+static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
{
- unsigned long flags;
- NCR5380_local_declare();
- struct Scsi_Host *instance;
+ if(write_flag)
+ memcpy(dmabuf, data, count);
+ else {
+ sun3_dma_orig_addr = data;
+ sun3_dma_orig_count = count;
+ }
+
+ dregs->fifo_count = 0;
+ sun3_udc_write(UDC_RESET, UDC_CSR);
- instance = default_instance;
- NCR5380_setup(instance);
- if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
- {
- printk("SCSI poll\n");
- save_flags(flags);
- cli();
- sun3scsi_intr(IRQ_SUN3_SCSI, instance, NULL);
- restore_flags(flags);
+ /* reset fifo */
+ dregs->csr &= ~CSR_FIFO;
+ dregs->csr |= CSR_FIFO;
+
+ /* set direction */
+ if(write_flag)
+ dregs->csr |= CSR_SEND;
+ else
+ dregs->csr &= ~CSR_SEND;
+
+ /* byte count for fifo */
+ dregs->fifo_count = count;
+
+ sun3_udc_write(UDC_RESET, UDC_CSR);
+
+ /* reset fifo */
+ dregs->csr &= ~CSR_FIFO;
+ dregs->csr |= CSR_FIFO;
+
+
+ if(dregs->fifo_count != count) {
+ printk("scsi%d: fifo_mismatch %04x not %04x\n",
+ default_instance->host_no, dregs->fifo_count,
+ (unsigned int) count);
+ NCR5380_print(default_instance);
+ }
+
+ /* setup udc */
+ udc_regs->addr_hi = ((sun3_dvma_vtop(dmabuf) & 0xff0000) >> 8);
+ udc_regs->addr_lo = (sun3_dvma_vtop(dmabuf) & 0xffff);
+ udc_regs->count = count/2; /* count in words */
+ udc_regs->mode_hi = UDC_MODE_HIWORD;
+ if(write_flag) {
+ if(count & 1)
+ udc_regs->count++;
+ udc_regs->mode_lo = UDC_MODE_LSEND;
+ udc_regs->rsel = UDC_RSEL_SEND;
+ } else {
+ udc_regs->mode_lo = UDC_MODE_LRECV;
+ udc_regs->rsel = UDC_RSEL_RECV;
}
+
+ /* announce location of regs block */
+ sun3_udc_write(((sun3_dvma_vtop(udc_regs) & 0xff0000) >> 8),
+ UDC_CHN_HI);
+
+ sun3_udc_write((sun3_dvma_vtop(udc_regs) & 0xffff), UDC_CHN_LO);
+
+ /* set dma master on */
+ sun3_udc_write(0xd, UDC_MODE);
+
+ /* interrupt enable */
+ sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
+
+ return count;
+
+}
+
+static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
+{
+ unsigned short resid;
+
+ dregs->udc_addr = 0x32;
+ udelay(SUN3_DMA_DELAY);
+ resid = dregs->udc_data;
+ udelay(SUN3_DMA_DELAY);
+ resid *= 2;
+
+ return (unsigned long) resid;
+}
+
+static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
+ int write_flag)
+{
+ return wanted;
}
+/* clean up after our dma is done */
+static int sun3scsi_dma_finish(void)
+{
+ unsigned short count;
+ int ret = 0;
+
+ count = sun3scsi_dma_residual(default_instance);
+
+ sun3_dma_active = 0;
+
+ /* if we've finished a read, copy out the data we read */
+ if(sun3_dma_orig_addr) {
+ /* check for residual bytes after dma end */
+ if(count && (NCR5380_read(BUS_AND_STATUS_REG) &
+ (BASR_PHASE_MATCH | BASR_ACK))) {
+ printk("scsi%d: sun3_scsi_finish: read overrun baby... ", default_instance->host_no);
+ printk("basr now %02x\n", NCR5380_read(BUS_AND_STATUS_REG));
+ ret = count;
+ }
+
+ /* copy in what we dma'd no matter what */
+ memcpy(sun3_dma_orig_addr, dmabuf, sun3_dma_orig_count);
+ sun3_dma_orig_addr = NULL;
+
+ }
+
+ sun3_udc_write(UDC_RESET, UDC_CSR);
+
+ dregs->csr &= ~CSR_SEND;
+
+ /* reset fifo */
+ dregs->csr &= ~CSR_FIFO;
+ dregs->csr |= CSR_FIFO;
+
+ sun3_dma_setup_done = NULL;
+
+ return ret;
+
+}
+
+#include "sun3_NCR5380.c"
#ifdef MODULE
@@ -414,3 +539,4 @@ Scsi_Host_Template driver_template = SUN3_NCR5380;
#include "scsi_module.c"
#endif
+
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
index c677bfbf6..b94f586aa 100644
--- a/drivers/scsi/sun3_scsi.h
+++ b/drivers/scsi/sun3_scsi.h
@@ -1,6 +1,8 @@
/*
* Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
*
+ * Sun3 DMA additions by Sam Creasey (sammy@oh.verio.com)
+ *
* Adapted from mac_scsinew.h:
*/
/*
@@ -102,18 +104,272 @@ use_clustering: DISABLE_CLUSTERING \
#define NCR5380_setup(instance) \
_instance = instance
-#define NCR5380_read(reg) sun3scsi_read(_instance, reg)
-#define NCR5380_write(reg, value) sun3scsi_write(_instance, reg, value)
+#define NCR5380_read(reg) sun3scsi_read(reg)
+#define NCR5380_write(reg, value) sun3scsi_write(reg, value)
#define NCR5380_intr sun3scsi_intr
#define NCR5380_queue_command sun3scsi_queue_command
-#define NCR5380_abort sun3scsi_abort
#define NCR5380_reset sun3scsi_reset
+#define NCR5380_abort sun3scsi_abort
#define NCR5380_proc_info sun3scsi_proc_info
+#define NCR5380_dma_xfer_len(i, cmd, phase) \
+ sun3scsi_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
+
+#define NCR5380_dma_write_setup(instance, data, count) sun3scsi_dma_setup(data, count, 1)
+#define NCR5380_dma_read_setup(instance, data, count) sun3scsi_dma_setup(data, count, 0)
+#define NCR5380_dma_residual sun3scsi_dma_residual
#define BOARD_NORMAL 0
#define BOARD_NCR53C400 1
+/* additional registers - mainly DMA control regs */
+/* these start at regbase + 8 -- directly after the NCR regs */
+struct sun3_dma_regs {
+ unsigned short vmeregs[4]; /* unimpl vme stuff */
+ unsigned short udc_data; /* udc dma data reg */
+ unsigned short udc_addr; /* uda dma addr reg */
+ unsigned short fifo_data; /* fifo data reg, holds extra byte on
+ odd dma reads */
+ unsigned short fifo_count;
+ unsigned short csr; /* control/status reg */
+};
+
+/* ucd chip specific regs - live in dvma space */
+struct sun3_udc_regs {
+ unsigned short rsel; /* select regs to load */
+ unsigned short addr_hi; /* high word of addr */
+ unsigned short addr_lo; /* low word */
+ unsigned short count; /* words to be xfer'd */
+ unsigned short mode_hi; /* high word of channel mode */
+ unsigned short mode_lo; /* low word of channel mode */
+};
+
+/* addresses of the udc registers */
+#define UDC_MODE 0x38
+#define UDC_CSR 0x2e /* command/status */
+#define UDC_CHN_HI 0x26 /* chain high word */
+#define UDC_CHN_LO 0x22 /* chain lo word */
+#define UDC_CURA_HI 0x1a /* cur reg A high */
+#define UDC_CURA_LO 0x0a /* cur reg A low */
+#define UDC_CURB_HI 0x12 /* cur reg B high */
+#define UDC_CURB_LO 0x02 /* cur reg B low */
+#define UDC_MODE_HI 0x56 /* mode reg high */
+#define UDC_MODE_LO 0x52 /* mode reg low */
+#define UDC_COUNT 0x32 /* words to xfer */
+
+/* some udc commands */
+#define UDC_RESET 0
+#define UDC_CHN_START 0xa0 /* start chain */
+#define UDC_INT_ENABLE 0x32 /* channel 1 int on */
+
+/* udc mode words */
+#define UDC_MODE_HIWORD 0x40
+#define UDC_MODE_LSEND 0xc2
+#define UDC_MODE_LRECV 0xd2
+
+/* udc reg selections */
+#define UDC_RSEL_SEND 0x282
+#define UDC_RSEL_RECV 0x182
+
+/* bits in csr reg */
+#define CSR_DMA_ACTIVE 0x8000
+#define CSR_DMA_CONFLICT 0x4000
+#define CSR_DMA_BUSERR 0x2000
+
+#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */
+#define CSR_SDB_INT 0x200 /* sbc interrupt pending */
+#define CSR_DMA_INT 0x100 /* dma interrupt pending */
+
+#define CSR_SEND 0x8 /* 1 = send 0 = recv */
+#define CSR_FIFO 0x2 /* reset fifo */
+#define CSR_INTR 0x4 /* interrupt enable */
+#define CSR_SCSI 0x1
+
+// debugging printk's, taken from atari_scsi.h
+/* Debugging printk definitions:
+ *
+ * ARB -> arbitration
+ * ASEN -> auto-sense
+ * DMA -> DMA
+ * HSH -> PIO handshake
+ * INF -> information transfer
+ * INI -> initialization
+ * INT -> interrupt
+ * LNK -> linked commands
+ * MAIN -> NCR5380_main() control flow
+ * NDAT -> no data-out phase
+ * NWR -> no write commands
+ * PIO -> PIO transfers
+ * PDMA -> pseudo DMA (unused on Atari)
+ * QU -> queues
+ * RSL -> reselections
+ * SEL -> selections
+ * USL -> usleep cpde (unused on Atari)
+ * LBS -> last byte sent (unused on Atari)
+ * RSS -> restarting of selections
+ * EXT -> extended messages
+ * ABRT -> aborting and resetting
+ * TAG -> queue tag handling
+ * MER -> merging of consec. buffers
+ *
+ */
+
+
+
+#if NDEBUG & NDEBUG_ARBITRATION
+#define ARB_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define ARB_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_AUTOSENSE
+#define ASEN_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define ASEN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_DMA
+#define DMA_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define DMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_HANDSHAKE
+#define HSH_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define HSH_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INFORMATION
+#define INF_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define INF_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INIT
+#define INI_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define INI_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INTR
+#define INT_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define INT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LINKED
+#define LNK_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define LNK_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MAIN
+#define MAIN_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define MAIN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_DATAOUT
+#define NDAT_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define NDAT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_WRITE
+#define NWR_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define NWR_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PIO
+#define PIO_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define PIO_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PSEUDO_DMA
+#define PDMA_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define PDMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_QUEUES
+#define QU_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define QU_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESELECTION
+#define RSL_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define RSL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_SELECTION
+#define SEL_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define SEL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_USLEEP
+#define USL_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define USL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LAST_BYTE_SENT
+#define LBS_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define LBS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESTART_SELECT
+#define RSS_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define RSS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_EXTENDED
+#define EXT_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define EXT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_ABORT
+#define ABRT_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define ABRT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_TAGS
+#define TAG_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define TAG_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MERGING
+#define MER_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define MER_PRINTK(format, args...)
+#endif
+
+/* conditional macros for NCR5380_print_{,phase,status} */
+
+#define NCR_PRINT(mask) \
+ ((NDEBUG & (mask)) ? NCR5380_print(instance) : (void)0)
+
+#define NCR_PRINT_PHASE(mask) \
+ ((NDEBUG & (mask)) ? NCR5380_print_phase(instance) : (void)0)
+
+#define NCR_PRINT_STATUS(mask) \
+ ((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0)
+
+#define NDEBUG_ANY 0xffffffff
+
+
+
#endif /* ndef HOSTS_C */
#endif /* SUN3_NCR5380_H */