diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-12-16 05:34:03 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-12-16 05:34:03 +0000 |
commit | 967c65a99059fd459b956c1588ce0ba227912c4e (patch) | |
tree | 8224d013ff5d255420713d05610c7efebd204d2a /drivers/scsi/aic7xxx.c | |
parent | e20c1cc1656a66a2773bca4591a895cbc12696ff (diff) |
Merge with Linux 2.1.72, part 1.
Diffstat (limited to 'drivers/scsi/aic7xxx.c')
-rw-r--r-- | drivers/scsi/aic7xxx.c | 115 |
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: */ - |