summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic7xxx.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
commit967c65a99059fd459b956c1588ce0ba227912c4e (patch)
tree8224d013ff5d255420713d05610c7efebd204d2a /drivers/scsi/aic7xxx.c
parente20c1cc1656a66a2773bca4591a895cbc12696ff (diff)
Merge with Linux 2.1.72, part 1.
Diffstat (limited to 'drivers/scsi/aic7xxx.c')
-rw-r--r--drivers/scsi/aic7xxx.c115
1 files changed, 89 insertions, 26 deletions
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
index 5551cbad8..051dedaac 100644
--- a/drivers/scsi/aic7xxx.c
+++ b/drivers/scsi/aic7xxx.c
@@ -147,6 +147,8 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
#define ALL_TARGETS -1
#define ALL_CHANNELS '\0'
#define ALL_LUNS -1
+#define MAX_TARGETS 16
+#define MAX_LUNS 8
#ifndef TRUE
# define TRUE 1
#endif
@@ -301,7 +303,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
typedef struct
{
- char tag_commands[16]; /* Allow for wide/twin channel adapters. */
+ unsigned char tag_commands[16]; /* Allow for wide/twin channel adapters. */
} adapter_tag_info_t;
/*
@@ -871,7 +873,7 @@ struct aic7xxx_host {
long r_total; /* total reads */
long r_total512; /* 512 byte blocks read */
long r_bins[10]; /* binned reads */
- } stats[2][16][8]; /* channel, target, lun */
+ } stats[MAX_TARGETS][MAX_LUNS]; /* [(channel << 3)|target][lun] */
#endif /* AIC7XXX_PROC_STATS */
};
@@ -969,6 +971,7 @@ static int aic7xxx_verbose = 0; /* verbose messages */
* IO, we'll use them then.
*
***************************************************************************/
+
static inline unsigned char
aic_inb(struct aic7xxx_host *p, long port)
{
@@ -992,15 +995,24 @@ aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
{
if (p->maddr != NULL)
{
+#ifdef __alpha__
+ int i;
+
+ for (i=0; i < size; i++)
+ {
+ p->maddr[port] = valp[i];
+ }
+#else
__asm __volatile("
cld;
1: lodsb;
movb %%al,(%0);
loop 1b" :
:
- "r" ((p)->maddr + (port)),
- "S" ((valp)), "c" ((size)) :
+ "r" (p->maddr + port),
+ "S" (valp), "c" (size) :
"%esi", "%ecx", "%eax");
+#endif
}
else
{
@@ -1439,7 +1451,7 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
* If the offset is 0, then the device is requesting asynchronous
* transfers.
*/
- if ((*period >= aic7xxx_syncrates[i].period) && *offset != 0)
+ if ((*period <= aic7xxx_syncrates[i - 1].period) && *offset != 0)
{
for (i = 0; i < num_aic7xxx_syncrates; i++)
{
@@ -1970,21 +1982,46 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
{
unsigned short mask;
+ int message_error = FALSE;
mask = 0x01 << TARGET_INDEX(scb->cmd);
+
+ /*
+ * Check to see if we get an invalid message or a message error
+ * after failing to negotiate a wide or sync transfer message.
+ */
+ if ((scb->flags & SCB_SENSE) &&
+ ((scb->cmd->sense_buffer[12] == 0x43) || /* INVALID_MESSAGE */
+ (scb->cmd->sense_buffer[12] == 0x49))) /* MESSAGE_ERROR */
+ {
+ message_error = TRUE;
+ }
+
if (scb->flags & SCB_MSGOUT_WDTR)
{
p->wdtr_pending &= ~mask;
+ if (message_error)
+ {
+ p->needwdtr &= ~mask;
+ p->needwdtr_copy &= ~mask;
+ }
}
if (scb->flags & SCB_MSGOUT_SDTR)
{
p->sdtr_pending &= ~mask;
+ if (message_error)
+ {
+ p->needsdtr &= ~mask;
+ p->needsdtr_copy &= ~mask;
+ }
}
}
aic7xxx_free_scb(p, scb);
aic7xxx_queue_cmd_complete(p, cmd);
#ifdef AIC7XXX_PROC_STATS
+ if ( (cmd->cmnd[0] != TEST_UNIT_READY) &&
+ (cmd->cmnd[0] != INQUIRY) )
{
int actual;
@@ -2000,7 +2037,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
long *ptr;
int x;
- sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
+ sp = &p->stats[TARGET_INDEX(cmd)][cmd->lun & 0x7];
sp->xfers++;
if (cmd->request.cmd == WRITE)
@@ -3088,6 +3125,8 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
}
else
{
+ int send_reject = FALSE;
+
/*
* Send our own WDTR in reply.
*/
@@ -3110,14 +3149,25 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
{
bus_width = BUS_8_BIT;
scratch &= 0x7F; /* XXX - FreeBSD doesn't do this. */
+ send_reject = TRUE;
}
break;
default:
break;
}
- aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
- outb(SEND_MSG, p->base + RETURN_1);
+ if (send_reject)
+ {
+ outb(SEND_REJ, p->base + RETURN_1);
+ printk(KERN_WARNING "scsi%d: Target %d, channel %c, initiating "
+ "wide negotiation on a narrow bus - rejecting!",
+ p->host_no, target, channel);
+ }
+ else
+ {
+ aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
+ outb(SEND_MSG, p->base + RETURN_1);
+ }
}
p->needwdtr &= ~target_mask;
outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
@@ -4062,7 +4112,7 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
device->queue_depth = default_depth;
#else
- if (p->instance > NUMBER(aic7xxx_tag_info))
+ if (p->instance >= NUMBER(aic7xxx_tag_info))
{
device->queue_depth = default_depth;
}
@@ -5022,7 +5072,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
scbq_init(&p->scb_data->free_scbs);
scbq_init(&p->waiting_scbs);
- for (i = 0; i <= NUMBER(p->device_status); i++)
+ for (i = 0; i < NUMBER(p->device_status); i++)
{
p->device_status[i].commands_sent = 0;
p->device_status[i].flags = 0;
@@ -5305,8 +5355,17 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
*/
outb(p->qcntmask, p->base + QCNTMASK);
- outb(p->qfullcount, p->base + FIFODEPTH);
- outb(0, p->base + CMDOUTCNT);
+ /*
+ * Set FIFO depth and command out count. These are only used when
+ * paging is enabled and should not be touched for AIC-7770 based
+ * adapters; FIFODEPTH and CMDOUTCNT overlay SCSICONF and SCSICONF+1
+ * which are used to control termination.
+ */
+ if (p->flags & PAGE_ENABLED)
+ {
+ outb(p->qfullcount, p->base + FIFODEPTH);
+ outb(0, p->base + CMDOUTCNT);
+ }
/*
* We don't have any waiting selections or disconnected SCBs.
@@ -5537,7 +5596,6 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
{
case AIC_7770: /* None of these adapters have seeproms. */
case AIC_7771:
- case AIC_7850:
case AIC_7855:
break;
@@ -5545,6 +5603,7 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
break;
+ case AIC_7850: /* The 2910B is a 7850 with a seeprom. */
case AIC_7861:
case AIC_7870:
case AIC_7871:
@@ -5654,7 +5713,11 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
scsi_conf = (p->scsi_id & 0x7);
if (sc->adapter_control & CFSPARITY)
scsi_conf |= ENSPCHK;
- if (sc->adapter_control & CFRESETB)
+ /*
+ * The 7850 controllers with a seeprom, do not honor the CFRESETB
+ * flag in the seeprom. Assume that we want to reset the SCSI bus.
+ */
+ if ((sc->adapter_control & CFRESETB) || (p->chip_class == AIC_7850))
scsi_conf |= RESET_SCSI;
if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
@@ -5721,7 +5784,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
* a NULL entry to indicate that no prior hosts have
* been found/registered for that IRQ.
*/
- for (i = 0; i <= NUMBER(aic7xxx_boards); i++)
+ for (i = 0; i < NUMBER(aic7xxx_boards); i++)
{
aic7xxx_boards[i] = NULL;
}
@@ -5787,6 +5850,14 @@ aic7xxx_detect(Scsi_Host_Template *template)
hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
outb(hcntrl | PAUSE, base + HCNTRL);
+ p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
+ if (p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+ continue;
+ }
+ aic7xxx_chip_reset(p);
+
irq = inb(INTDEF + base) & 0x0F;
switch (irq)
{
@@ -5800,19 +5871,14 @@ aic7xxx_detect(Scsi_Host_Template *template)
default:
printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
- "level, ignoring.\n");
+ "level %d, ignoring.\n", irq);
irq = 0;
+ aic7xxx_free(p);
break;
}
if (irq != 0)
{
- p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
- if (p == NULL)
- {
- printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
- continue;
- }
p->irq = irq & 0x0F;
p->chip_class = AIC_777x;
#ifdef AIC7XXX_PAGE_ENABLE
@@ -5823,7 +5889,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
{
p->flags |= EXTENDED_TRANSLATION;
}
- aic7xxx_chip_reset(p);
switch (p->chip_type)
{
@@ -5985,7 +6050,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
flags = 0;
switch (aic7xxx_pci_devices[i].chip_type)
{
- case AIC_7850:
case AIC_7855:
flags |= USE_DEFAULTS;
break;
@@ -6887,7 +6951,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
base = p->base;
channel = cmd->channel ? 'B': 'A';
- tindex = (cmd->channel << 4) | cmd->target;
+ tindex = TARGET_INDEX(cmd);
#ifdef 0 /* AIC7XXX_DEBUG_ABORT */
if (scb != NULL)
@@ -7128,4 +7192,3 @@ Scsi_Host_Template driver_template = AIC7XXX;
* tab-width: 8
* End:
*/
-