aic7xxx_old.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:392k
- if((new_offset == 0) && (offset != 0))
- {
- /*
- * Oops, the syncrate went to low for this card and we fell off
- * to async (should never happen with a device that uses PPR
- * messages, but have to be complete)
- */
- reply = TRUE;
- }
- if(reply)
- {
- scb->flags &= ~SCB_MSGOUT_BITS;
- scb->flags |= SCB_MSGOUT_PPR;
- aic_outb(p, HOST_MSG, MSG_OUT);
- aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
- }
- else
- {
- p->needppr &= ~target_mask;
- }
- done = TRUE;
- break;
- }
- default:
- {
- reject = TRUE;
- break;
- }
- } /* end of switch(p->msg_type) */
- } /* end of if (!reject && (p->msg_len > 2)) */
- if (!reply && reject)
- {
- aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
- aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
- done = TRUE;
- }
- return(done);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_handle_reqinit
- *
- * Description:
- * Interrupt handler for REQINIT interrupts (used to transfer messages to
- * and from devices).
- *_F*************************************************************************/
- static void
- aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
- {
- unsigned char lastbyte;
- unsigned char phasemis;
- int done = FALSE;
- switch(p->msg_type)
- {
- case MSG_TYPE_INITIATOR_MSGOUT:
- {
- if (p->msg_len == 0)
- panic("aic7xxx: REQINIT with no active message!n");
- lastbyte = (p->msg_index == (p->msg_len - 1));
- phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT;
- if (lastbyte || phasemis)
- {
- /* Time to end the message */
- p->msg_len = 0;
- p->msg_type = MSG_TYPE_NONE;
- /*
- * NOTE-TO-MYSELF: If you clear the REQINIT after you
- * disable REQINITs, then cases of REJECT_MSG stop working
- * and hang the bus
- */
- aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
- aic_outb(p, CLRSCSIINT, CLRINT);
- p->flags &= ~AHC_HANDLING_REQINITS;
- if (phasemis == 0)
- {
- aic_outb(p, p->msg_buf[p->msg_index], SINDEX);
- aic_outb(p, 0, RETURN_1);
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- printk(INFO_LEAD "Completed sending of REQINIT message.n",
- p->host_no, CTL_OF_SCB(scb));
- #endif
- }
- else
- {
- aic_outb(p, MSGOUT_PHASEMIS, RETURN_1);
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- printk(INFO_LEAD "PHASEMIS while sending REQINIT message.n",
- p->host_no, CTL_OF_SCB(scb));
- #endif
- }
- unpause_sequencer(p, TRUE);
- }
- else
- {
- /*
- * Present the byte on the bus (clearing REQINIT) but don't
- * unpause the sequencer.
- */
- aic_outb(p, CLRREQINIT, CLRSINT1);
- aic_outb(p, CLRSCSIINT, CLRINT);
- aic_outb(p, p->msg_buf[p->msg_index++], SCSIDATL);
- }
- break;
- }
- case MSG_TYPE_INITIATOR_MSGIN:
- {
- phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN;
- if (phasemis == 0)
- {
- p->msg_len++;
- /* Pull the byte in without acking it */
- p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL);
- done = aic7xxx_parse_msg(p, scb);
- /* Ack the byte */
- aic_outb(p, CLRREQINIT, CLRSINT1);
- aic_outb(p, CLRSCSIINT, CLRINT);
- aic_inb(p, SCSIDATL);
- p->msg_index++;
- }
- if (phasemis || done)
- {
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- {
- if (phasemis)
- printk(INFO_LEAD "PHASEMIS while receiving REQINIT message.n",
- p->host_no, CTL_OF_SCB(scb));
- else
- printk(INFO_LEAD "Completed receipt of REQINIT message.n",
- p->host_no, CTL_OF_SCB(scb));
- }
- #endif
- /* Time to end our message session */
- p->msg_len = 0;
- p->msg_type = MSG_TYPE_NONE;
- aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
- aic_outb(p, CLRSCSIINT, CLRINT);
- p->flags &= ~AHC_HANDLING_REQINITS;
- unpause_sequencer(p, TRUE);
- }
- break;
- }
- default:
- {
- panic("aic7xxx: Unknown REQINIT message type.n");
- break;
- }
- } /* End of switch(p->msg_type) */
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_handle_scsiint
- *
- * Description:
- * Interrupt handler for SCSI interrupts (SCSIINT).
- *-F*************************************************************************/
- static void
- aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
- {
- unsigned char scb_index;
- unsigned char status;
- struct aic7xxx_scb *scb;
- scb_index = aic_inb(p, SCB_TAG);
- status = aic_inb(p, SSTAT1);
- if (scb_index < p->scb_data->numscbs)
- {
- scb = p->scb_data->scb_array[scb_index];
- if ((scb->flags & SCB_ACTIVE) == 0)
- {
- scb = NULL;
- }
- }
- else
- {
- scb = NULL;
- }
- if ((status & SCSIRSTI) != 0)
- {
- int channel;
- if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
- channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
- else
- channel = 0;
- if (aic7xxx_verbose & VERBOSE_RESET)
- printk(WARN_LEAD "Someone else reset the channel!!n",
- p->host_no, channel, -1, -1);
- if (aic7xxx_panic_on_abort)
- aic7xxx_panic_abort(p, NULL);
- /*
- * Go through and abort all commands for the channel, but do not
- * reset the channel again.
- */
- aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
- aic7xxx_run_done_queue(p, TRUE);
- scb = NULL;
- }
- else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
- {
- /*
- * First look at what phase we were last in. If it's message-out,
- * chances are pretty good that the bus free was in response to
- * one of our abort requests.
- */
- unsigned char lastphase = aic_inb(p, LASTPHASE);
- unsigned char saved_tcl = aic_inb(p, SAVED_TCL);
- unsigned char target = (saved_tcl >> 4) & 0x0F;
- int channel;
- int printerror = TRUE;
- if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
- channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
- else
- channel = 0;
- aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP),
- SCSISEQ);
- if (lastphase == P_MESGOUT)
- {
- unsigned char message;
- message = aic_inb(p, SINDEX);
- if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG))
- {
- if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
- printk(INFO_LEAD "SCB %d abort delivered.n", p->host_no,
- CTL_OF_SCB(scb), scb->hscb->tag);
- aic7xxx_reset_device(p, target, channel, ALL_LUNS,
- (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
- aic7xxx_run_done_queue(p, TRUE);
- scb = NULL;
- printerror = 0;
- }
- else if (message == MSG_BUS_DEV_RESET)
- {
- aic7xxx_handle_device_reset(p, target, channel);
- scb = NULL;
- printerror = 0;
- }
- }
- if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) )
- {
- /*
- * Hmmm...error during a negotiation command. Either we have a
- * borken bus, or the device doesn't like our negotiation message.
- * Since we check the INQUIRY data of a device before sending it
- * negotiation messages, assume the bus is borken for whatever
- * reason. Complete the command.
- */
- printerror = 0;
- aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
- aic7xxx_run_done_queue(p, TRUE);
- scb = NULL;
- }
- if (printerror != 0)
- {
- if (scb != NULL)
- {
- unsigned char tag;
- if ((scb->hscb->control & TAG_ENB) != 0)
- {
- tag = scb->hscb->tag;
- }
- else
- {
- tag = SCB_LIST_NULL;
- }
- aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
- aic7xxx_run_done_queue(p, TRUE);
- }
- else
- {
- aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
- aic7xxx_run_done_queue(p, TRUE);
- }
- printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
- "SEQADDR = 0x%xn", p->host_no, channel, target, -1, lastphase,
- (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
- scb = NULL;
- }
- aic_outb(p, MSG_NOOP, MSG_OUT);
- aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
- SIMODE1);
- p->flags &= ~AHC_HANDLING_REQINITS;
- aic_outb(p, CLRBUSFREE, CLRSINT1);
- aic_outb(p, CLRSCSIINT, CLRINT);
- restart_sequencer(p);
- unpause_sequencer(p, TRUE);
- }
- else if ((status & SELTO) != 0)
- {
- unsigned char scbptr;
- unsigned char nextscb;
- Scsi_Cmnd *cmd;
- scbptr = aic_inb(p, WAITING_SCBH);
- if (scbptr > p->scb_data->maxhscbs)
- {
- /*
- * I'm still trying to track down exactly how this happens, but until
- * I find it, this code will make sure we aren't passing bogus values
- * into the SCBPTR register, even if that register will just wrap
- * things around, we still don't like having out of range variables.
- *
- * NOTE: Don't check the aic7xxx_verbose variable, I want this message
- * to always be displayed.
- */
- printk(INFO_LEAD "Invalid WAITING_SCBH value %d, improvising.n",
- p->host_no, -1, -1, -1, scbptr);
- if (p->scb_data->maxhscbs > 4)
- scbptr &= (p->scb_data->maxhscbs - 1);
- else
- scbptr &= 0x03;
- }
- aic_outb(p, scbptr, SCBPTR);
- scb_index = aic_inb(p, SCB_TAG);
- scb = NULL;
- if (scb_index < p->scb_data->numscbs)
- {
- scb = p->scb_data->scb_array[scb_index];
- if ((scb->flags & SCB_ACTIVE) == 0)
- {
- scb = NULL;
- }
- }
- if (scb == NULL)
- {
- printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.n",
- p->host_no, -1, -1, -1, scb_index);
- printk(KERN_WARNING " SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
- "SSTAT1 = 0x%xn", aic_inb(p, SCSISEQ),
- aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
- aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
- if (aic7xxx_panic_on_abort)
- aic7xxx_panic_abort(p, NULL);
- }
- else
- {
- cmd = scb->cmd;
- cmd->result = (DID_TIME_OUT << 16);
- /*
- * Clear out this hardware SCB
- */
- aic_outb(p, 0, SCB_CONTROL);
- /*
- * Clear out a few values in the card that are in an undetermined
- * state.
- */
- aic_outb(p, MSG_NOOP, MSG_OUT);
- /*
- * Shift the waiting for selection queue forward
- */
- nextscb = aic_inb(p, SCB_NEXT);
- aic_outb(p, nextscb, WAITING_SCBH);
- /*
- * Put this SCB back on the free list.
- */
- aic7xxx_add_curscb_to_free_list(p);
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- printk(INFO_LEAD "Selection Timeout.n", p->host_no, CTL_OF_SCB(scb));
- #endif
- if (scb->flags & SCB_QUEUED_ABORT)
- {
- /*
- * We know that this particular SCB had to be the queued abort since
- * the disconnected SCB would have gotten a reconnect instead.
- * What we need to do then is to let the command timeout again so
- * we get a reset since this abort just failed.
- */
- cmd->result = 0;
- scb = NULL;
- }
- }
- /*
- * Keep the sequencer from trying to restart any selections
- */
- aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
- /*
- * Make sure the data bits on the bus are released
- * Don't do this on 7770 chipsets, it makes them give us
- * a BRKADDRINT and kills the card.
- */
- if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
- aic_outb(p, 0, SCSIBUSL);
- /*
- * Delay for the selection timeout delay period then stop the selection
- */
- udelay(301);
- aic_outb(p, CLRSELINGO, CLRSINT0);
- /*
- * Clear out all the interrupt status bits
- */
- aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
- p->flags &= ~AHC_HANDLING_REQINITS;
- aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1);
- aic_outb(p, CLRSCSIINT, CLRINT);
- /*
- * Restarting the sequencer will stop the selection and make sure devices
- * are allowed to reselect in.
- */
- restart_sequencer(p);
- unpause_sequencer(p, TRUE);
- }
- else if (scb == NULL)
- {
- printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid "
- "during scsiint 0x%x scb(%d)n"
- " SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%xn",
- p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0),
- aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
- (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
- /*
- * Turn off the interrupt and set status to zero, so that it
- * falls through the rest of the SCSIINT code.
- */
- aic_outb(p, status, CLRSINT1);
- aic_outb(p, CLRSCSIINT, CLRINT);
- unpause_sequencer(p, /* unpause always */ TRUE);
- scb = NULL;
- }
- else if (status & SCSIPERR)
- {
- /*
- * Determine the bus phase and queue an appropriate message.
- */
- char *phase;
- Scsi_Cmnd *cmd;
- unsigned char mesg_out = MSG_NOOP;
- unsigned char lastphase = aic_inb(p, LASTPHASE);
- unsigned char sstat2 = aic_inb(p, SSTAT2);
- unsigned char tindex = TARGET_INDEX(scb->cmd);
- cmd = scb->cmd;
- switch (lastphase)
- {
- case P_DATAOUT:
- phase = "Data-Out";
- break;
- case P_DATAIN:
- phase = "Data-In";
- mesg_out = MSG_INITIATOR_DET_ERR;
- break;
- case P_COMMAND:
- phase = "Command";
- break;
- case P_MESGOUT:
- phase = "Message-Out";
- break;
- case P_STATUS:
- phase = "Status";
- mesg_out = MSG_INITIATOR_DET_ERR;
- break;
- case P_MESGIN:
- phase = "Message-In";
- mesg_out = MSG_PARITY_ERROR;
- break;
- default:
- phase = "unknown";
- break;
- }
- /*
- * A parity error has occurred during a data
- * transfer phase. Flag it and continue.
- */
- if( (p->features & AHC_ULTRA3) &&
- (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) &&
- (lastphase == P_DATAIN) )
- {
- printk(WARN_LEAD "CRC error during %s phase.n",
- p->host_no, CTL_OF_SCB(scb), phase);
- if(sstat2 & CRCVALERR)
- {
- printk(WARN_LEAD " CRC error in intermediate CRC packet.n",
- p->host_no, CTL_OF_SCB(scb));
- }
- if(sstat2 & CRCENDERR)
- {
- printk(WARN_LEAD " CRC error in ending CRC packet.n",
- p->host_no, CTL_OF_SCB(scb));
- }
- if(sstat2 & CRCREQERR)
- {
- printk(WARN_LEAD " Target incorrectly requested a CRC packet.n",
- p->host_no, CTL_OF_SCB(scb));
- }
- if(sstat2 & DUAL_EDGE_ERROR)
- {
- printk(WARN_LEAD " Dual Edge transmission error.n",
- p->host_no, CTL_OF_SCB(scb));
- }
- }
- else if( (lastphase == P_MESGOUT) &&
- (scb->flags & SCB_MSGOUT_PPR) )
- {
- /*
- * As per the draft specs, any device capable of supporting any of
- * the option values other than 0 are not allowed to reject the
- * PPR message. Instead, they must negotiate out what they do
- * support instead of rejecting our offering or else they cause
- * a parity error during msg_out phase to signal that they don't
- * like our settings.
- */
- p->needppr &= ~(1 << tindex);
- p->needppr_copy &= ~(1 << tindex);
- aic7xxx_set_width(p, scb->cmd->target, scb->cmd->channel, scb->cmd->lun,
- MSG_EXT_WDTR_BUS_8_BIT,
- (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
- aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
- 0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
- p->transinfo[tindex].goal_options = 0;
- scb->flags &= ~SCB_MSGOUT_BITS;
- if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
- {
- printk(INFO_LEAD "parity error during PPR message, reverting "
- "to WDTR/SDTRn", p->host_no, CTL_OF_SCB(scb));
- }
- if ( p->transinfo[tindex].goal_width )
- {
- p->needwdtr |= (1 << tindex);
- p->needwdtr_copy |= (1 << tindex);
- }
- if ( p->transinfo[tindex].goal_offset )
- {
- if( p->transinfo[tindex].goal_period <= 9 )
- {
- p->transinfo[tindex].goal_period = 10;
- }
- p->needsdtr |= (1 << tindex);
- p->needsdtr_copy |= (1 << tindex);
- }
- scb = NULL;
- }
- /*
- * We've set the hardware to assert ATN if we get a parity
- * error on "in" phases, so all we need to do is stuff the
- * message buffer with the appropriate message. "In" phases
- * have set mesg_out to something other than MSG_NOP.
- */
- if (mesg_out != MSG_NOOP)
- {
- aic_outb(p, mesg_out, MSG_OUT);
- aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
- scb = NULL;
- }
- aic_outb(p, CLRSCSIPERR, CLRSINT1);
- aic_outb(p, CLRSCSIINT, CLRINT);
- unpause_sequencer(p, /* unpause_always */ TRUE);
- }
- else if ( (status & REQINIT) &&
- (p->flags & AHC_HANDLING_REQINITS) )
- {
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- printk(INFO_LEAD "Handling REQINIT, SSTAT1=0x%x.n", p->host_no,
- CTL_OF_SCB(scb), aic_inb(p, SSTAT1));
- #endif
- aic7xxx_handle_reqinit(p, scb);
- return;
- }
- else
- {
- /*
- * We don't know what's going on. Turn off the
- * interrupt source and try to continue.
- */
- if (aic7xxx_verbose & VERBOSE_SCSIINT)
- printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).n",
- p->host_no, -1, -1, -1, status);
- aic_outb(p, status, CLRSINT1);
- aic_outb(p, CLRSCSIINT, CLRINT);
- unpause_sequencer(p, /* unpause always */ TRUE);
- scb = NULL;
- }
- if (scb != NULL)
- {
- aic7xxx_done(p, scb);
- }
- }
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- static void
- aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer)
- {
- unsigned char saved_scbptr, free_scbh, dis_scbh, wait_scbh, temp;
- int i, bogus, lost;
- static unsigned char scb_status[AIC7XXX_MAXSCB];
- #define SCB_NO_LIST 0
- #define SCB_FREE_LIST 1
- #define SCB_WAITING_LIST 2
- #define SCB_DISCONNECTED_LIST 4
- #define SCB_CURRENTLY_ACTIVE 8
- /*
- * Note, these checks will fail on a regular basis once the machine moves
- * beyond the bus scan phase. The problem is race conditions concerning
- * the scbs and where they are linked in. When you have 30 or so commands
- * outstanding on the bus, and run this twice with every interrupt, the
- * chances get pretty good that you'll catch the sequencer with an SCB
- * only partially linked in. Therefore, once we pass the scan phase
- * of the bus, we really should disable this function.
- */
- bogus = FALSE;
- memset(&scb_status[0], 0, sizeof(scb_status));
- pause_sequencer(p);
- saved_scbptr = aic_inb(p, SCBPTR);
- if (saved_scbptr >= p->scb_data->maxhscbs)
- {
- printk("Bogus SCBPTR %dn", saved_scbptr);
- bogus = TRUE;
- }
- scb_status[saved_scbptr] = SCB_CURRENTLY_ACTIVE;
- free_scbh = aic_inb(p, FREE_SCBH);
- if ( (free_scbh != SCB_LIST_NULL) &&
- (free_scbh >= p->scb_data->maxhscbs) )
- {
- printk("Bogus FREE_SCBH %dn", free_scbh);
- bogus = TRUE;
- }
- else
- {
- temp = free_scbh;
- while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
- {
- if(scb_status[temp] & 0x07)
- {
- printk("HSCB %d on multiple lists, status 0x%02x", temp,
- scb_status[temp] | SCB_FREE_LIST);
- bogus = TRUE;
- }
- scb_status[temp] |= SCB_FREE_LIST;
- aic_outb(p, temp, SCBPTR);
- temp = aic_inb(p, SCB_NEXT);
- }
- }
- dis_scbh = aic_inb(p, DISCONNECTED_SCBH);
- if ( (dis_scbh != SCB_LIST_NULL) &&
- (dis_scbh >= p->scb_data->maxhscbs) )
- {
- printk("Bogus DISCONNECTED_SCBH %dn", dis_scbh);
- bogus = TRUE;
- }
- else
- {
- temp = dis_scbh;
- while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
- {
- if(scb_status[temp] & 0x07)
- {
- printk("HSCB %d on multiple lists, status 0x%02x", temp,
- scb_status[temp] | SCB_DISCONNECTED_LIST);
- bogus = TRUE;
- }
- scb_status[temp] |= SCB_DISCONNECTED_LIST;
- aic_outb(p, temp, SCBPTR);
- temp = aic_inb(p, SCB_NEXT);
- }
- }
-
- wait_scbh = aic_inb(p, WAITING_SCBH);
- if ( (wait_scbh != SCB_LIST_NULL) &&
- (wait_scbh >= p->scb_data->maxhscbs) )
- {
- printk("Bogus WAITING_SCBH %dn", wait_scbh);
- bogus = TRUE;
- }
- else
- {
- temp = wait_scbh;
- while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
- {
- if(scb_status[temp] & 0x07)
- {
- printk("HSCB %d on multiple lists, status 0x%02x", temp,
- scb_status[temp] | SCB_WAITING_LIST);
- bogus = TRUE;
- }
- scb_status[temp] |= SCB_WAITING_LIST;
- aic_outb(p, temp, SCBPTR);
- temp = aic_inb(p, SCB_NEXT);
- }
- }
- lost=0;
- for(i=0; i < p->scb_data->maxhscbs; i++)
- {
- aic_outb(p, i, SCBPTR);
- temp = aic_inb(p, SCB_NEXT);
- if ( ((temp != SCB_LIST_NULL) &&
- (temp >= p->scb_data->maxhscbs)) )
- {
- printk("HSCB %d bad, SCB_NEXT invalid(%d).n", i, temp);
- bogus = TRUE;
- }
- if ( temp == i )
- {
- printk("HSCB %d bad, SCB_NEXT points to self.n", i);
- bogus = TRUE;
- }
- if (scb_status[i] == 0)
- lost++;
- if (lost > 1)
- {
- printk("Too many lost scbs.n");
- bogus=TRUE;
- }
- }
- aic_outb(p, saved_scbptr, SCBPTR);
- unpause_sequencer(p, FALSE);
- if (bogus)
- {
- printk("Bogus parameters found in card SCB array structures.n");
- printk("%sn", buffer);
- aic7xxx_panic_abort(p, NULL);
- }
- return;
- }
- #endif
- /*+F*************************************************************************
- * Function:
- * aic7xxx_handle_command_completion_intr
- *
- * Description:
- * SCSI command completion interrupt handler.
- *-F*************************************************************************/
- static void
- aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
- {
- struct aic7xxx_scb *scb = NULL;
- Scsi_Cmnd *cmd;
- unsigned char scb_index, tindex;
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
- printk(INFO_LEAD "Command Complete Int.n", p->host_no, -1, -1, -1);
- #endif
-
- /*
- * Read the INTSTAT location after clearing the CMDINT bit. This forces
- * any posted PCI writes to flush to memory. Gerard Roudier suggested
- * this fix to the possible race of clearing the CMDINT bit but not
- * having all command bytes flushed onto the qoutfifo.
- */
- aic_outb(p, CLRCMDINT, CLRINT);
- aic_inb(p, INTSTAT);
- /*
- * The sequencer will continue running when it
- * issues this interrupt. There may be >1 commands
- * finished, so loop until we've processed them all.
- */
- while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
- {
- scb_index = p->qoutfifo[p->qoutfifonext];
- p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
- if ( scb_index >= p->scb_data->numscbs )
- {
- printk(WARN_LEAD "CMDCMPLT with invalid SCB index %dn", p->host_no,
- -1, -1, -1, scb_index);
- continue;
- }
- scb = p->scb_data->scb_array[scb_index];
- if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
- "0x%x, cmd 0x%lxn", p->host_no, -1, -1, -1, scb_index, scb->flags,
- (unsigned long) scb->cmd);
- continue;
- }
- tindex = TARGET_INDEX(scb->cmd);
- if (scb->flags & SCB_QUEUED_ABORT)
- {
- pause_sequencer(p);
- if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
- (aic_inb(p, SCB_TAG) == scb->hscb->tag) )
- {
- unpause_sequencer(p, FALSE);
- continue;
- }
- aic7xxx_reset_device(p, scb->cmd->target, scb->cmd->channel,
- scb->cmd->lun, scb->hscb->tag);
- scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT |
- SCB_QUEUED_ABORT);
- unpause_sequencer(p, FALSE);
- }
- else if (scb->flags & SCB_ABORT)
- {
- /*
- * We started to abort this, but it completed on us, let it
- * through as successful
- */
- scb->flags &= ~(SCB_ABORT|SCB_RESET);
- }
- else if (scb->flags & SCB_SENSE)
- {
- char *buffer = &scb->cmd->sense_buffer[0];
- if (buffer[12] == 0x47 || buffer[12] == 0x54)
- {
- /*
- * Signal that we need to re-negotiate things.
- */
- p->needppr |= (p->needppr_copy & (1<<tindex));
- p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
- p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
- }
- }
- switch (status_byte(scb->hscb->target_status))
- {
- case QUEUE_FULL:
- case BUSY:
- scb->hscb->target_status = 0;
- scb->cmd->result = 0;
- scb->hscb->residual_SG_segment_count = 0;
- scb->hscb->residual_data_count[0] = 0;
- scb->hscb->residual_data_count[1] = 0;
- scb->hscb->residual_data_count[2] = 0;
- aic7xxx_error(scb->cmd) = DID_OK;
- aic7xxx_status(scb->cmd) = 0;
- /*
- * The QUEUE_FULL/BUSY handler in aic7xxx_seqint takes care of putting
- * this command on a timer and allowing us to retry it. Here, we
- * just 0 out a few values so that they don't carry through to when
- * the command finally does complete.
- */
- break;
- default:
- cmd = scb->cmd;
- if (scb->hscb->residual_SG_segment_count != 0)
- {
- aic7xxx_calculate_residual(p, scb);
- }
- cmd->result |= (aic7xxx_error(cmd) << 16);
- aic7xxx_done(p, scb);
- break;
- }
- }
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_isr
- *
- * Description:
- * SCSI controller interrupt handler.
- *-F*************************************************************************/
- static void
- aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
- {
- struct aic7xxx_host *p;
- unsigned char intstat;
- p = (struct aic7xxx_host *)dev_id;
- /*
- * Just a few sanity checks. Make sure that we have an int pending.
- * Also, if PCI, then we are going to check for a PCI bus error status
- * should we get too many spurious interrupts.
- */
- if (!((intstat = aic_inb(p, INTSTAT)) & INT_PEND))
- {
- #ifdef CONFIG_PCI
- if ( (p->chip & AHC_PCI) && (p->spurious_int > 500) &&
- !(p->flags & AHC_HANDLING_REQINITS) )
- {
- if ( aic_inb(p, ERROR) & PCIERRSTAT )
- {
- aic7xxx_pci_intr(p);
- }
- p->spurious_int = 0;
- }
- else if ( !(p->flags & AHC_HANDLING_REQINITS) )
- {
- p->spurious_int++;
- }
- #endif
- return;
- }
- p->spurious_int = 0;
- /*
- * Keep track of interrupts for /proc/scsi
- */
- p->isr_count++;
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) &&
- (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) )
- aic7xxx_check_scbs(p, "Bogus settings at start of interrupt.");
- #endif
- /*
- * Handle all the interrupt sources - especially for SCSI
- * interrupts, we won't get a second chance at them.
- */
- if (intstat & CMDCMPLT)
- {
- aic7xxx_handle_command_completion_intr(p);
- }
- if (intstat & BRKADRINT)
- {
- int i;
- unsigned char errno = aic_inb(p, ERROR);
- printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):n", p->host_no, errno);
- for (i = 0; i < NUMBER(hard_error); i++)
- {
- if (errno & hard_error[i].errno)
- {
- printk(KERN_ERR " %sn", hard_error[i].errmesg);
- }
- }
- printk(KERN_ERR "(scsi%d) SEQADDR=0x%xn", p->host_no,
- (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0)));
- if (aic7xxx_panic_on_abort)
- aic7xxx_panic_abort(p, NULL);
- #ifdef CONFIG_PCI
- if (errno & PCIERRSTAT)
- aic7xxx_pci_intr(p);
- #endif
- if (errno & (SQPARERR | ILLOPCODE | ILLSADDR))
- {
- sti();
- panic("aic7xxx: unrecoverable BRKADRINT.n");
- }
- if (errno & ILLHADDR)
- {
- printk(KERN_ERR "(scsi%d) BUG! Driver accessed chip without first "
- "pausing controller!n", p->host_no);
- }
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (errno & DPARERR)
- {
- if (aic_inb(p, DMAPARAMS) & DIRECTION)
- printk("(scsi%d) while DMAing SCB from host to card.n", p->host_no);
- else
- printk("(scsi%d) while DMAing SCB from card to host.n", p->host_no);
- }
- #endif
- aic_outb(p, CLRPARERR | CLRBRKADRINT, CLRINT);
- unpause_sequencer(p, FALSE);
- }
- if (intstat & SEQINT)
- {
- /*
- * Read the CCSCBCTL register to work around a bug in the Ultra2 cards
- */
- if(p->features & AHC_ULTRA2)
- {
- aic_inb(p, CCSCBCTL);
- }
- aic7xxx_handle_seqint(p, intstat);
- }
- if (intstat & SCSIINT)
- {
- aic7xxx_handle_scsiint(p, intstat);
- }
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) &&
- (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) )
- aic7xxx_check_scbs(p, "Bogus settings at end of interrupt.");
- #endif
- }
- /*+F*************************************************************************
- * Function:
- * do_aic7xxx_isr
- *
- * Description:
- * This is a gross hack to solve a problem in linux kernels 2.1.85 and
- * above. Please, children, do not try this at home, and if you ever see
- * anything like it, please inform the Gross Hack Police immediately
- *-F*************************************************************************/
- static void
- do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
- {
- unsigned long cpu_flags;
- struct aic7xxx_host *p;
-
- p = (struct aic7xxx_host *)dev_id;
- if(!p)
- return;
- spin_lock_irqsave(&io_request_lock, cpu_flags);
- p->flags |= AHC_IN_ISR;
- do
- {
- aic7xxx_isr(irq, dev_id, regs);
- } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
- aic7xxx_done_cmds_complete(p);
- aic7xxx_run_waiting_queues(p);
- p->flags &= ~AHC_IN_ISR;
- spin_unlock_irqrestore(&io_request_lock, cpu_flags);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_device_queue_depth
- *
- * Description:
- * Determines the queue depth for a given device. There are two ways
- * a queue depth can be obtained for a tagged queueing device. One
- * way is the default queue depth which is determined by whether
- * AIC7XXX_CMDS_PER_DEVICE is defined. If it is defined, then it is used
- * as the default queue depth. Otherwise, we use either 4 or 8 as the
- * default queue depth (dependent on the number of hardware SCBs).
- * The other way we determine queue depth is through the use of the
- * aic7xxx_tag_info array which is enabled by defining
- * AIC7XXX_TAGGED_QUEUEING_BY_DEVICE. This array can be initialized
- * with queue depths for individual devices. It also allows tagged
- * queueing to be [en|dis]abled for a specific adapter.
- *-F*************************************************************************/
- static int
- aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
- {
- int default_depth = 3;
- unsigned char tindex;
- unsigned short target_mask;
- tindex = device->id | (device->channel << 3);
- target_mask = (1 << tindex);
- if (p->dev_max_queue_depth[tindex] > 1)
- {
- /*
- * We've already scanned this device, leave it alone
- */
- return(p->dev_max_queue_depth[tindex]);
- }
- device->queue_depth = default_depth;
- p->dev_temp_queue_depth[tindex] = 1;
- p->dev_max_queue_depth[tindex] = 1;
- p->tagenable &= ~target_mask;
- if (device->tagged_supported)
- {
- int tag_enabled = TRUE;
- default_depth = AIC7XXX_CMDS_PER_DEVICE;
-
- if (!(p->discenable & target_mask))
- {
- if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
- printk(INFO_LEAD "Disconnection disabled, unable to "
- "enable tagged queueing.n",
- p->host_no, device->channel, device->id, device->lun);
- }
- else
- {
- if (p->instance >= NUMBER(aic7xxx_tag_info))
- {
- static int print_warning = TRUE;
- if(print_warning)
- {
- printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for"
- " installed controllers.n");
- printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in"
- " the aic7xxx.c source file.n");
- print_warning = FALSE;
- }
- device->queue_depth = default_depth;
- }
- else
- {
- if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255)
- {
- tag_enabled = FALSE;
- device->queue_depth = 3; /* Tagged queueing is disabled. */
- }
- else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
- {
- device->queue_depth = default_depth;
- }
- else
- {
- device->queue_depth =
- aic7xxx_tag_info[p->instance].tag_commands[tindex];
- }
- }
- if ((device->tagged_queue == 0) && tag_enabled)
- {
- if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
- {
- printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.n",
- p->host_no, device->channel, device->id,
- device->lun, device->queue_depth);
- }
- p->dev_max_queue_depth[tindex] = device->queue_depth;
- p->dev_temp_queue_depth[tindex] = device->queue_depth;
- p->tagenable |= target_mask;
- p->orderedtag |= target_mask;
- device->tagged_queue = 1;
- device->current_tag = SCB_LIST_NULL;
- }
- }
- }
- return(p->dev_max_queue_depth[tindex]);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_select_queue_depth
- *
- * Description:
- * Sets the queue depth for each SCSI device hanging off the input
- * host adapter. We use a queue depth of 2 for devices that do not
- * support tagged queueing. If AIC7XXX_CMDS_PER_LUN is defined, we
- * use that for tagged queueing devices; otherwise we use our own
- * algorithm for determining the queue depth based on the maximum
- * SCBs for the controller.
- *-F*************************************************************************/
- static void
- aic7xxx_select_queue_depth(struct Scsi_Host *host,
- Scsi_Device *scsi_devs)
- {
- Scsi_Device *device;
- struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
- int scbnum;
- scbnum = 0;
- for (device = scsi_devs; device != NULL; device = device->next)
- {
- if (device->host == host)
- {
- scbnum += aic7xxx_device_queue_depth(p, device);
- }
- }
- while (scbnum > p->scb_data->numscbs)
- {
- /*
- * Pre-allocate the needed SCBs to get around the possibility of having
- * to allocate some when memory is more or less exhausted and we need
- * the SCB in order to perform a swap operation (possible deadlock)
- */
- if ( aic7xxx_allocate_scb(p) == 0 )
- return;
- }
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_probe
- *
- * Description:
- * Probing for EISA boards: it looks like the first two bytes
- * are a manufacturer code - three characters, five bits each:
- *
- * BYTE 0 BYTE 1 BYTE 2 BYTE 3
- * ?1111122 22233333 PPPPPPPP RRRRRRRR
- *
- * The characters are baselined off ASCII '@', so add that value
- * to each to get the real ASCII code for it. The next two bytes
- * appear to be a product and revision number, probably vendor-
- * specific. This is what is being searched for at each port,
- * and what should probably correspond to the ID= field in the
- * ECU's .cfg file for the card - if your card is not detected,
- * make sure your signature is listed in the array.
- *
- * The fourth byte's lowest bit seems to be an enabled/disabled
- * flag (rest of the bits are reserved?).
- *
- * NOTE: This function is only needed on Intel and Alpha platforms,
- * the other platforms we support don't have EISA/VLB busses. So,
- * we #ifdef this entire function to avoid compiler warnings about
- * an unused function.
- *-F*************************************************************************/
- #if defined(__i386__) || defined(__alpha__)
- static int
- aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
- {
- int i;
- unsigned char buf[4];
- static struct {
- int n;
- unsigned char signature[sizeof(buf)];
- ahc_chip type;
- int bios_disabled;
- } AIC7xxx[] = {
- { 4, { 0x04, 0x90, 0x77, 0x70 },
- AHC_AIC7770|AHC_EISA, FALSE }, /* mb 7770 */
- { 4, { 0x04, 0x90, 0x77, 0x71 },
- AHC_AIC7770|AHC_EISA, FALSE }, /* host adapter 274x */
- { 4, { 0x04, 0x90, 0x77, 0x56 },
- AHC_AIC7770|AHC_VL, FALSE }, /* 284x BIOS enabled */
- { 4, { 0x04, 0x90, 0x77, 0x57 },
- AHC_AIC7770|AHC_VL, TRUE } /* 284x BIOS disabled */
- };
- /*
- * The VL-bus cards need to be primed by
- * writing before a signature check.
- */
- for (i = 0; i < sizeof(buf); i++)
- {
- outb(0x80 + i, base);
- buf[i] = inb(base + i);
- }
- for (i = 0; i < NUMBER(AIC7xxx); i++)
- {
- /*
- * Signature match on enabled card?
- */
- if (!memcmp(buf, AIC7xxx[i].signature, AIC7xxx[i].n))
- {
- if (inb(base + 4) & 1)
- {
- if (AIC7xxx[i].bios_disabled)
- {
- *flags |= AHC_USEDEFAULTS;
- }
- else
- {
- *flags |= AHC_BIOS_ENABLED;
- }
- return (i);
- }
- printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
- "disabled at slot %d, ignored.n", slot);
- }
- }
- return (-1);
- }
- #endif /* (__i386__) || (__alpha__) */
- /*+F*************************************************************************
- * Function:
- * read_2840_seeprom
- *
- * Description:
- * Reads the 2840 serial EEPROM and returns 1 if successful and 0 if
- * not successful.
- *
- * See read_seeprom (for the 2940) for the instruction set of the 93C46
- * chip.
- *
- * The 2840 interface to the 93C46 serial EEPROM is through the
- * STATUS_2840 and SEECTL_2840 registers. The CS_2840, CK_2840, and
- * DO_2840 bits of the SEECTL_2840 register are connected to the chip
- * select, clock, and data out lines respectively of the serial EEPROM.
- * The DI_2840 bit of the STATUS_2840 is connected to the data in line
- * of the serial EEPROM. The EEPROM_TF bit of STATUS_2840 register is
- * useful in that it gives us an 800 nsec timer. After a read from the
- * SEECTL_2840 register the timing flag is cleared and goes high 800 nsec
- * later.
- *-F*************************************************************************/
- static int
- read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
- {
- int i = 0, k = 0;
- unsigned char temp;
- unsigned short checksum = 0;
- unsigned short *seeprom = (unsigned short *) sc;
- struct seeprom_cmd {
- unsigned char len;
- unsigned char bits[3];
- };
- struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
- #define CLOCK_PULSE(p)
- while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0)
- {
- ; /* Do nothing */
- }
- (void) aic_inb(p, SEECTL_2840);
- /*
- * Read the first 32 registers of the seeprom. For the 2840,
- * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
- * but only the first 32 are used by Adaptec BIOS. The loop
- * will range from 0 to 31.
- */
- for (k = 0; k < (sizeof(*sc) / 2); k++)
- {
- /*
- * Send chip select for one clock cycle.
- */
- aic_outb(p, CK_2840 | CS_2840, SEECTL_2840);
- CLOCK_PULSE(p);
- /*
- * Now we're ready to send the read command followed by the
- * address of the 16-bit register we want to read.
- */
- for (i = 0; i < seeprom_read.len; i++)
- {
- temp = CS_2840 | seeprom_read.bits[i];
- aic_outb(p, temp, SEECTL_2840);
- CLOCK_PULSE(p);
- temp = temp ^ CK_2840;
- aic_outb(p, temp, SEECTL_2840);
- CLOCK_PULSE(p);
- }
- /*
- * Send the 6 bit address (MSB first, LSB last).
- */
- for (i = 5; i >= 0; i--)
- {
- temp = k;
- temp = (temp >> i) & 1; /* Mask out all but lower bit. */
- temp = CS_2840 | temp;
- aic_outb(p, temp, SEECTL_2840);
- CLOCK_PULSE(p);
- temp = temp ^ CK_2840;
- aic_outb(p, temp, SEECTL_2840);
- CLOCK_PULSE(p);
- }
- /*
- * Now read the 16 bit register. An initial 0 precedes the
- * register contents which begins with bit 15 (MSB) and ends
- * with bit 0 (LSB). The initial 0 will be shifted off the
- * top of our word as we let the loop run from 0 to 16.
- */
- for (i = 0; i <= 16; i++)
- {
- temp = CS_2840;
- aic_outb(p, temp, SEECTL_2840);
- CLOCK_PULSE(p);
- temp = temp ^ CK_2840;
- seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840);
- aic_outb(p, temp, SEECTL_2840);
- CLOCK_PULSE(p);
- }
- /*
- * The serial EEPROM has a checksum in the last word. Keep a
- * running checksum for all words read except for the last
- * word. We'll verify the checksum after all words have been
- * read.
- */
- if (k < (sizeof(*sc) / 2) - 1)
- {
- checksum = checksum + seeprom[k];
- }
- /*
- * Reset the chip select for the next command cycle.
- */
- aic_outb(p, 0, SEECTL_2840);
- CLOCK_PULSE(p);
- aic_outb(p, CK_2840, SEECTL_2840);
- CLOCK_PULSE(p);
- aic_outb(p, 0, SEECTL_2840);
- CLOCK_PULSE(p);
- }
- #if 0
- printk("Computed checksum 0x%x, checksum read 0x%xn", checksum, sc->checksum);
- printk("Serial EEPROM:");
- for (k = 0; k < (sizeof(*sc) / 2); k++)
- {
- if (((k % 8) == 0) && (k != 0))
- {
- printk("n ");
- }
- printk(" 0x%x", seeprom[k]);
- }
- printk("n");
- #endif
- if (checksum != sc->checksum)
- {
- printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.n");
- return (0);
- }
- return (1);
- #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
- *
- * Description:
- * Acquires access to the memory port on PCI controllers.
- *-F*************************************************************************/
- static int
- acquire_seeprom(struct aic7xxx_host *p)
- {
- /*
- * Request access of the memory port. When access is
- * granted, SEERDY will go high. We use a 1 second
- * timeout which should be near 1 second more than
- * is needed. Reason: after the 7870 chip reset, there
- * should be no contention.
- */
- aic_outb(p, SEEMS, SEECTL);
- CLOCK_PULSE(p);
- if ((aic_inb(p, SEECTL) & SEERDY) == 0)
- {
- aic_outb(p, 0, SEECTL);
- return (0);
- }
- return (1);
- }
- /*+F*************************************************************************
- * Function:
- * release_seeprom
- *
- * Description:
- * Releases access to the memory port on PCI controllers.
- *-F*************************************************************************/
- 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);
- }
- /*+F*************************************************************************
- * Function:
- * read_seeprom
- *
- * Description:
- * Reads the serial EEPROM and returns 1 if successful and 0 if
- * not successful.
- *
- * The instruction set of the 93C46/56/66 chips is as follows:
- *
- * Start OP
- * Function Bit Code Address Data Description
- * -------------------------------------------------------------------
- * READ 1 10 A5 - A0 Reads data stored in memory,
- * starting at specified address
- * EWEN 1 00 11XXXX Write enable must precede
- * all programming modes
- * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0
- * WRITE 1 01 A5 - A0 D15 - D0 Writes register
- * ERAL 1 00 10XXXX Erase all registers
- * WRAL 1 00 01XXXX D15 - D0 Writes to all registers
- * EWDS 1 00 00XXXX Disables all programming
- * instructions
- * *Note: A value of X for address is a don't care condition.
- * *Note: The 93C56 and 93C66 have 8 address bits.
- *
- *
- * The 93C46 has a four wire interface: clock, chip select, data in, and
- * data out. In order to perform one of the above functions, you need
- * to enable the chip select for a clock period (typically a minimum of
- * 1 usec, with the clock high and low a minimum of 750 and 250 nsec
- * respectively. While the chip select remains high, you can clock in
- * the instructions (above) starting with the start bit, followed by the
- * OP code, Address, and Data (if needed). For the READ instruction, the
- * requested 16-bit register contents is read from the data out line but
- * is preceded by an initial zero (leading 0, followed by 16-bits, MSB
- * first). The clock cycling from low to high initiates the next data
- * bit to be sent from the chip.
- *
- * The 78xx interface to the 93C46 serial EEPROM is through the SEECTL
- * register. After successful arbitration for the memory port, the
- * SEECS bit of the SEECTL register is connected to the chip select.
- * The SEECK, SEEDO, and SEEDI are connected to the clock, data out,
- * and data in lines respectively. The SEERDY bit of SEECTL is useful
- * in that it gives us an 800 nsec timer. After a write to the SEECTL
- * register, the SEERDY goes high 800 nsec later. The one exception
- * to this is when we first request access to the memory port. The
- * SEERDY goes high to signify that access has been granted and, for
- * this case, has no implied timing.
- *-F*************************************************************************/
- static int
- read_seeprom(struct aic7xxx_host *p, int offset,
- unsigned short *scarray, unsigned int len, seeprom_chip_type chip)
- {
- int i = 0, k;
- unsigned char temp;
- unsigned short checksum = 0;
- struct seeprom_cmd {
- unsigned char len;
- unsigned char bits[3];
- };
- struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
- /*
- * Request access of the memory port.
- */
- if (acquire_seeprom(p) == 0)
- {
- return (0);
- }
- /*
- * Read 'len' registers of the seeprom. For the 7870, the 93C46
- * SEEPROM is a 1024-bit device with 64 16-bit registers but only
- * the first 32 are used by Adaptec BIOS. Some adapters use the
- * 93C56 SEEPROM which is a 2048-bit device. The loop will range
- * from 0 to 'len' - 1.
- */
- for (k = 0; k < len; k++)
- {
- /*
- * Send chip select for one clock cycle.
- */
- aic_outb(p, SEEMS | SEECK | SEECS, SEECTL);
- CLOCK_PULSE(p);
- /*
- * Now we're ready to send the read command followed by the
- * address of the 16-bit register we want to read.
- */
- for (i = 0; i < seeprom_read.len; i++)
- {
- temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
- aic_outb(p, temp, SEECTL);
- CLOCK_PULSE(p);
- temp = temp ^ SEECK;
- aic_outb(p, temp, SEECTL);
- CLOCK_PULSE(p);
- }
- /*
- * Send the 6 or 8 bit address (MSB first, LSB last).
- */
- for (i = ((int) chip - 1); i >= 0; i--)
- {
- temp = k + offset;
- temp = (temp >> i) & 1; /* Mask out all but lower bit. */
- temp = SEEMS | SEECS | (temp << 1);
- aic_outb(p, temp, SEECTL);
- CLOCK_PULSE(p);
- temp = temp ^ SEECK;
- aic_outb(p, temp, SEECTL);
- CLOCK_PULSE(p);
- }
- /*
- * Now read the 16 bit register. An initial 0 precedes the
- * register contents which begins with bit 15 (MSB) and ends
- * with bit 0 (LSB). The initial 0 will be shifted off the
- * top of our word as we let the loop run from 0 to 16.
- */
- for (i = 0; i <= 16; i++)
- {
- temp = SEEMS | SEECS;
- aic_outb(p, temp, SEECTL);
- CLOCK_PULSE(p);
- temp = temp ^ SEECK;
- scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI);
- aic_outb(p, temp, SEECTL);
- CLOCK_PULSE(p);
- }
- /*
- * The serial EEPROM should have a checksum in the last word.
- * Keep a running checksum for all words read except for the
- * last word. We'll verify the checksum after all words have
- * been read.
- */
- if (k < (len - 1))
- {
- checksum = checksum + scarray[k];
- }
- /*
- * Reset the chip select for the next command cycle.
- */
- aic_outb(p, SEEMS, SEECTL);
- CLOCK_PULSE(p);
- aic_outb(p, SEEMS | SEECK, SEECTL);
- CLOCK_PULSE(p);
- aic_outb(p, SEEMS, SEECTL);
- CLOCK_PULSE(p);
- }
- /*
- * Release access to the memory port and the serial EEPROM.
- */
- release_seeprom(p);
- #if 0
- printk("Computed checksum 0x%x, checksum read 0x%xn",
- checksum, scarray[len - 1]);
- printk("Serial EEPROM:");
- for (k = 0; k < len; k++)
- {
- if (((k % 8) == 0) && (k != 0))
- {
- printk("n ");
- }
- printk(" 0x%x", scarray[k]);
- }
- printk("n");
- #endif
- if ( (checksum != scarray[len - 1]) || (checksum == 0) )
- {
- return (0);
- }
- return (1);
- }
- /*+F*************************************************************************
- * Function:
- * read_brdctl
- *
- * Description:
- * Reads the BRDCTL register.
- *-F*************************************************************************/
- static unsigned char
- 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);
- CLOCK_PULSE(p);
- value = aic_inb(p, BRDCTL);
- CLOCK_PULSE(p);
- return(value);
- }
- brdctl = BRDRW;
- if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
- (p->flags & AHC_CHNLB) )
- {
- brdctl |= BRDCS;
- }
- aic_outb(p, brdctl, BRDCTL);
- CLOCK_PULSE(p);
- value = aic_inb(p, BRDCTL);
- CLOCK_PULSE(p);
- aic_outb(p, 0, BRDCTL);
- CLOCK_PULSE(p);
- return (value);
- }
- /*+F*************************************************************************
- * Function:
- * write_brdctl
- *
- * Description:
- * Writes a value to the BRDCTL register.
- *-F*************************************************************************/
- static void
- 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);
- CLOCK_PULSE(p);
- brdctl |= BRDSTB_ULTRA2;
- aic_outb(p, brdctl, BRDCTL);
- CLOCK_PULSE(p);
- brdctl &= ~BRDSTB_ULTRA2;
- aic_outb(p, brdctl, BRDCTL);
- CLOCK_PULSE(p);
- read_brdctl(p);
- CLOCK_PULSE(p);
- }
- else
- {
- brdctl = BRDSTB;
- if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
- (p->flags & AHC_CHNLB) )
- {
- brdctl |= BRDCS;
- }
- brdctl = BRDSTB | BRDCS;
- aic_outb(p, brdctl, BRDCTL);
- CLOCK_PULSE(p);
- brdctl |= value;
- aic_outb(p, brdctl, BRDCTL);
- CLOCK_PULSE(p);
- brdctl &= ~BRDSTB;
- aic_outb(p, brdctl, BRDCTL);
- CLOCK_PULSE(p);
- brdctl &= ~BRDCS;
- aic_outb(p, brdctl, BRDCTL);
- CLOCK_PULSE(p);
- }
- }
- /*+F*************************************************************************
- * Function:
- * aic785x_cable_detect
- *
- * Description:
- * Detect the cables that are present on aic785x class controller chips
- *-F*************************************************************************/
- static void
- aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
- int *ext_present, int *eeprom)
- {
- unsigned char brdctl;
- aic_outb(p, BRDRW | BRDCS, BRDCTL);
- CLOCK_PULSE(p);
- aic_outb(p, 0, BRDCTL);
- CLOCK_PULSE(p);
- brdctl = aic_inb(p, BRDCTL);
- CLOCK_PULSE(p);
- *int_50 = !(brdctl & BRDDAT5);
- *ext_present = !(brdctl & BRDDAT6);
- *eeprom = (aic_inb(p, SPIOCAP) & EEPROM);
- }
- #undef CLOCK_PULSE
- /*+F*************************************************************************
- * Function:
- * aic2940_uwpro_cable_detect
- *
- * Description:
- * Detect the cables that are present on the 2940-UWPro cards
- *
- * NOTE: This function assumes the SEEPROM will have already been acquired
- * prior to invocation of this function.
- *-F*************************************************************************/
- static void
- aic2940_uwpro_wide_cable_detect(struct aic7xxx_host *p, int *int_68,
- int *ext_68, int *eeprom)
- {
- unsigned char brdctl;
- /*
- * First read the status of our cables. Set the rom bank to
- * 0 since the bank setting serves as a multiplexor for the
- * cable detection logic. BRDDAT5 controls the bank switch.
- */
- write_brdctl(p, 0);
- /*
- * Now we read the state of the internal 68 connector. BRDDAT6
- * is don't care, BRDDAT7 is internal 68. The cable is
- * present if the bit is 0
- */
- brdctl = read_brdctl(p);
- *int_68 = !(brdctl & BRDDAT7);
- /*
- * Set the bank bit in brdctl and then read the external cable state
- * and the EEPROM status
- */
- write_brdctl(p, BRDDAT5);
- brdctl = read_brdctl(p);
- *ext_68 = !(brdctl & BRDDAT6);
- *eeprom = !(brdctl & BRDDAT7);
- /*
- * We're done, the calling function will release the SEEPROM for us
- */
- }
- /*+F*************************************************************************
- * Function:
- * aic787x_cable_detect
- *
- * Description:
- * Detect the cables that are present on aic787x class controller chips
- *
- * NOTE: This function assumes the SEEPROM will have already been acquired
- * prior to invocation of this function.
- *-F*************************************************************************/
- static void
- aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68,
- int *ext_present, int *eeprom)
- {
- unsigned char brdctl;
- /*
- * First read the status of our cables. Set the rom bank to
- * 0 since the bank setting serves as a multiplexor for the
- * cable detection logic. BRDDAT5 controls the bank switch.
- */
- write_brdctl(p, 0);
- /*
- * Now we read the state of the two internal connectors. BRDDAT6
- * is internal 50, BRDDAT7 is internal 68. For each, the cable is
- * present if the bit is 0
- */
- brdctl = read_brdctl(p);
- *int_50 = !(brdctl & BRDDAT6);
- *int_68 = !(brdctl & BRDDAT7);
- /*
- * Set the bank bit in brdctl and then read the external cable state
- * and the EEPROM status
- */
- write_brdctl(p, BRDDAT5);
- brdctl = read_brdctl(p);
- *ext_present = !(brdctl & BRDDAT6);
- *eeprom = !(brdctl & BRDDAT7);
- /*
- * We're done, the calling function will release the SEEPROM for us
- */
- }
- /*+F*************************************************************************
- * Function:
- * aic787x_ultra2_term_detect
- *
- * Description:
- * Detect the termination settings present on ultra2 class controllers
- *
- * NOTE: This function assumes the SEEPROM will have already been acquired
- * prior to invocation of this function.
- *-F*************************************************************************/
- static void
- aic7xxx_ultra2_term_detect(struct aic7xxx_host *p, int *enableSE_low,
- int *enableSE_high, int *enableLVD_low,
- int *enableLVD_high, int *eprom_present)
- {
- unsigned char brdctl;
- brdctl = read_brdctl(p);
- *eprom_present = (brdctl & BRDDAT7);
- *enableSE_high = (brdctl & BRDDAT6);
- *enableSE_low = (brdctl & BRDDAT5);
- *enableLVD_high = (brdctl & BRDDAT4);
- *enableLVD_low = (brdctl & BRDDAT3);
- }
- /*+F*************************************************************************
- * Function:
- * configure_termination
- *
- * Description:
- * Configures the termination settings on PCI adapters that have
- * SEEPROMs available.
- *-F*************************************************************************/
- static void
- configure_termination(struct aic7xxx_host *p)
- {
- int internal50_present = 0;
- int internal68_present = 0;
- int external_present = 0;
- int eprom_present = 0;
- int enableSE_low = 0;
- int enableSE_high = 0;
- int enableLVD_low = 0;
- int enableLVD_high = 0;
- unsigned char brddat = 0;
- unsigned char max_target = 0;
- unsigned char sxfrctl1 = aic_inb(p, SXFRCTL1);
- if (acquire_seeprom(p))
- {
- if (p->features & (AHC_WIDE|AHC_TWIN))
- max_target = 16;
- else
- max_target = 8;
- aic_outb(p, SEEMS | SEECS, SEECTL);
- sxfrctl1 &= ~STPWEN;
- /*
- * The termination/cable detection logic is split into three distinct
- * groups. Ultra2 and later controllers, 2940UW-Pro controllers, and
- * older 7850, 7860, 7870, 7880, and 7895 controllers. Each has its
- * own unique way of detecting their cables and writing the results
- * back to the card.
- */
- if (p->features & AHC_ULTRA2)
- {
- /*
- * As long as user hasn't overridden term settings, always check the
- * cable detection logic
- */
- if (aic7xxx_override_term == -1)
- {
- aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high,
- &enableLVD_low, &enableLVD_high,
- &eprom_present);
- }
-
- /*
- * If the user is overriding settings, then they have been preserved
- * to here as fake adapter_control entries. Parse them and allow
- * them to override the detected settings (if we even did detection).
- */
- if (!(p->adapter_control & CFSEAUTOTERM))
- {
- enableSE_low = (p->adapter_control & CFSTERM);
- enableSE_high = (p->adapter_control & CFWSTERM);
- }
- if (!(p->adapter_control & CFAUTOTERM))
- {
- enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM);
- }
- /*
- * Now take those settings that we have and translate them into the
- * values that must be written into the registers.
- *
- * Flash Enable = BRDDAT7
- * Secondary High Term Enable = BRDDAT6
- * Secondary Low Term Enable = BRDDAT5
- * LVD/Primary High Term Enable = BRDDAT4
- * LVD/Primary Low Term Enable = STPWEN bit in SXFRCTL1
- */
- if (enableLVD_low != 0)
- {
- sxfrctl1 |= STPWEN;
- p->flags |= AHC_TERM_ENB_LVD;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) LVD/Primary Low byte termination "
- "Enabledn", p->host_no);
- }
-
- if (enableLVD_high != 0)
- {
- brddat |= BRDDAT4;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) LVD/Primary High byte termination "
- "Enabledn", p->host_no);
- }
- if (enableSE_low != 0)
- {
- brddat |= BRDDAT5;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) Secondary Low byte termination "
- "Enabledn", p->host_no);
- }
- if (enableSE_high != 0)
- {
- brddat |= BRDDAT6;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) Secondary High byte termination "
- "Enabledn", p->host_no);
- }
- }
- else if (p->features & AHC_NEW_AUTOTERM)
- {
- /*
- * The 50 pin connector termination is controlled by STPWEN in the
- * SXFRCTL1 register. Since the Adaptec docs typically say the
- * controller is not allowed to be in the middle of a cable and
- * this is the only connection on that stub of the bus, there is
- * no need to even check for narrow termination, it's simply
- * always on.
- */
- sxfrctl1 |= STPWEN;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) Narrow channel termination Enabledn",
- p->host_no);
- if (p->adapter_control & CFAUTOTERM)
- {
- aic2940_uwpro_wide_cable_detect(p, &internal68_present,
- &external_present,
- &eprom_present);
- printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, "
- "Ext-68 %s)n", p->host_no,
- "Don't Care",
- internal68_present ? "YES" : "NO",
- external_present ? "YES" : "NO");
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) EEPROM %s present.n", p->host_no,
- eprom_present ? "is" : "is not");
- if (internal68_present && external_present)
- {
- brddat = 0;
- p->flags &= ~AHC_TERM_ENB_SE_HIGH;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) Wide channel termination Disabledn",
- p->host_no);
- }
- else
- {
- brddat = BRDDAT6;
- p->flags |= AHC_TERM_ENB_SE_HIGH;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) Wide channel termination Enabledn",
- p->host_no);
- }
- }
- else
- {
- /*
- * The termination of the Wide channel is done more like normal
- * though, and the setting of this termination is done by writing
- * either a 0 or 1 to BRDDAT6 of the BRDDAT register
- */
- if (p->adapter_control & CFWSTERM)
- {
- brddat = BRDDAT6;
- p->flags |= AHC_TERM_ENB_SE_HIGH;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) Wide channel termination Enabledn",
- p->host_no);
- }
- else
- {
- brddat = 0;
- }
- }
- }
- else
- {
- if (p->adapter_control & CFAUTOTERM)
- {
- if (p->flags & AHC_MOTHERBOARD)
- {
- printk(KERN_INFO "(scsi%d) Warning - detected auto-terminationn",
- p->host_no);
- printk(KERN_INFO "(scsi%d) Please verify driver detected settings "
- "are correct.n", p->host_no);
- printk(KERN_INFO "(scsi%d) If not, then please properly set the "
- "device terminationn", p->host_no);
- printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting "
- "CTRL-A when promptedn", p->host_no);
- printk(KERN_INFO "(scsi%d) during machine bootup.n", p->host_no);
- }
- /* Configure auto termination. */
- if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 )
- {
- aic787x_cable_detect(p, &internal50_present, &internal68_present,
- &external_present, &eprom_present);
- }
- else
- {
- aic785x_cable_detect(p, &internal50_present, &external_present,
- &eprom_present);
- }
- if (max_target <= 8)
- internal68_present = 0;
- if (max_target > 8)
- {
- printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, "
- "Ext-68 %s)n", p->host_no,
- internal50_present ? "YES" : "NO",
- internal68_present ? "YES" : "NO",
- external_present ? "YES" : "NO");
- }
- else
- {
- printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Ext-50 %s)n",
- p->host_no,
- internal50_present ? "YES" : "NO",
- external_present ? "YES" : "NO");
- }
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) EEPROM %s present.n", p->host_no,
- eprom_present ? "is" : "is not");
- /*
- * Now set the termination based on what we found. BRDDAT6
- * controls wide termination enable.
- * Flash Enable = BRDDAT7
- * SE High Term Enable = BRDDAT6
- */
- if (internal50_present && internal68_present && external_present)
- {
- printk(KERN_INFO "(scsi%d) Illegal cable configuration!! Only twon",
- p->host_no);
- printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be "
- "in use at a time!n", p->host_no);
- /*
- * Force termination (low and high byte) on. This is safer than
- * leaving it completely off, especially since this message comes
- * most often from motherboard controllers that don't even have 3
- * connectors, but instead are failing the cable detection.
- */
- internal50_present = external_present = 0;
- enableSE_high = enableSE_low = 1;
- }
- if ((max_target > 8) &&
- ((external_present == 0) || (internal68_present == 0)) )
- {
- brddat |= BRDDAT6;
- p->flags |= AHC_TERM_ENB_SE_HIGH;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) SE High byte termination Enabledn",
- p->host_no);
- }
- if ( ((internal50_present ? 1 : 0) +
- (internal68_present ? 1 : 0) +
- (external_present ? 1 : 0)) <= 1 )
- {
- sxfrctl1 |= STPWEN;
- p->flags |= AHC_TERM_ENB_SE_LOW;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) SE Low byte termination Enabledn",
- p->host_no);
- }
- }
- else /* p->adapter_control & CFAUTOTERM */
- {
- if (p->adapter_control & CFSTERM)
- {
- sxfrctl1 |= STPWEN;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) SE Low byte termination Enabledn",
- p->host_no);
- }
- if (p->adapter_control & CFWSTERM)
- {
- brddat |= BRDDAT6;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) SE High byte termination Enabledn",
- p->host_no);
- }
- }
- }
- aic_outb(p, sxfrctl1, SXFRCTL1);
- write_brdctl(p, brddat);
- release_seeprom(p);
- }
- }
- /*+F*************************************************************************
- * Function:
- * detect_maxscb
- *
- * Description:
- * Detects the maximum number of SCBs for the controller and returns
- * the count and a mask in p (p->maxscbs, p->qcntmask).
- *-F*************************************************************************/
- static void
- detect_maxscb(struct aic7xxx_host *p)
- {
- int i;
- /*
- * It's possible that we've already done this for multichannel
- * adapters.
- */
- if (p->scb_data->maxhscbs == 0)
- {
- /*
- * We haven't initialized the SCB settings yet. Walk the SCBs to
- * determince how many there are.
- */
- aic_outb(p, 0, FREE_SCBH);
- for (i = 0; i < AIC7XXX_MAXSCB; i++)
- {
- aic_outb(p, i, SCBPTR);
- aic_outb(p, i, SCB_CONTROL);
- if (aic_inb(p, SCB_CONTROL) != i)
- break;
- aic_outb(p, 0, SCBPTR);
- if (aic_inb(p, SCB_CONTROL) != 0)
- break;
- aic_outb(p, i, SCBPTR);
- aic_outb(p, 0, SCB_CONTROL); /* Clear the control byte. */
- aic_outb(p, i + 1, SCB_NEXT); /* Set the next pointer. */
- aic_outb(p, SCB_LIST_NULL, SCB_TAG); /* Make the tag invalid. */
- aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS); /* no busy untagged */
- aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */
- aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+2);
- aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+3);
- }
- /* Make sure the last SCB terminates the free list. */
- aic_outb(p, i - 1, SCBPTR);
- aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
- /* Ensure we clear the first (0) SCBs control byte. */
- aic_outb(p, 0, SCBPTR);
- aic_outb(p, 0, SCB_CONTROL);
- p->scb_data->maxhscbs = i;
- /*
- * Use direct indexing instead for speed
- */
- if ( i == AIC7XXX_MAXSCB )
- p->flags &= ~AHC_PAGESCBS;
- }
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_register
- *
- * Description:
- * Register a Adaptec aic7xxx chip SCSI controller with the kernel.
- *-F*************************************************************************/
- static int
- aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
- int reset_delay)
- {
- int i, result;
- int max_targets;
- int found = 1;
- unsigned char term, scsi_conf;
- struct Scsi_Host *host;
- host = p->host;
- p->scb_data->maxscbs = AIC7XXX_MAXSCB;
- host->can_queue = AIC7XXX_MAXSCB;
- host->cmd_per_lun = 3;
- host->sg_tablesize = AIC7XXX_MAX_SG;
- host->select_queue_depths = aic7xxx_select_queue_depth;
- host->this_id = p->scsi_id;
- host->io_port = p->base;
- host->n_io_port = 0xFF;
- host->base = p->mbase;
- host->irq = p->irq;
- if (p->features & AHC_WIDE)
- {
- host->max_id = 16;
- }
- if (p->features & AHC_TWIN)
- {
- host->max_channel = 1;
- }
- p->host = host;
- p->host_no = host->host_no;
- host->unique_id = p->instance;
- p->isr_count = 0;
- p->next = NULL;
- p->completeq.head = NULL;
- p->completeq.tail = NULL;
- scbq_init(&p->scb_data->free_scbs);
- scbq_init(&p->waiting_scbs);
- init_timer(&p->dev_timer);
- p->dev_timer.data = (unsigned long)p;
- p->dev_timer.function = (void *)aic7xxx_timer;
- p->dev_timer_active = 0;
- /*
- * We currently have no commands of any type
- */
- p->qinfifonext = 0;
- p->qoutfifonext = 0;
- for (i = 0; i < MAX_TARGETS; i++)
- {
- p->dev_commands_sent[i] = 0;
- p->dev_flags[i] = 0;
- p->dev_active_cmds[i] = 0;
- p->dev_last_queue_full[i] = 0;
- p->dev_last_queue_full_count[i] = 0;
- p->dev_max_queue_depth[i] = 1;
- p->dev_temp_queue_depth[i] = 1;
- p->dev_expires[i] = 0;
- scbq_init(&p->delayed_scbs[i]);
- }
- printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
- board_names[p->board_name_index]);
- switch(p->chip)
- {
- case (AHC_AIC7770|AHC_EISA):
- printk("EISA slot %dn", p->pci_device_fn);
- break;
- case (AHC_AIC7770|AHC_VL):
- printk("VLB slot %dn", p->pci_device_fn);
- break;
- default:
- printk("PCI %d/%d/%dn", p->pci_bus, PCI_SLOT(p->pci_device_fn),
- PCI_FUNC(p->pci_device_fn));
- break;
- }
- if (p->features & AHC_TWIN)
- {
- printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
- p->host_no, p->scsi_id, p->scsi_id_b);
- }
- else
- {
- char *channel;
- channel = "";
- if ((p->flags & AHC_MULTI_CHANNEL) != 0)
- {
- channel = " A";
- if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 )
- {
- channel = (p->flags & AHC_CHNLB) ? " B" : " C";
- }
- }
- if (p->features & AHC_WIDE)
- {
- printk(KERN_INFO "(scsi%d) Wide ", p->host_no);
- }
- else
- {
- printk(KERN_INFO "(scsi%d) Narrow ", p->host_no);
- }
- printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id);
- }
- aic_outb(p, 0, SEQ_FLAGS);
- detect_maxscb(p);
- printk("%d/%d SCBsn", p->scb_data->maxhscbs, p->scb_data->maxscbs);
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %dn",
- p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
- p->base, p->irq);
- printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at 0x%lxn",
- p->host_no, p->mbase, (unsigned long)p->maddr);
- }
- #ifdef CONFIG_PCI
- /*
- * Now that we know our instance number, we can set the flags we need to
- * force termination if need be.
- */
- if (aic7xxx_stpwlev != -1)
- {
- /*
- * This option only applies to PCI controllers.
- */
- if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
- {
- unsigned char devconfig;
- pci_read_config_byte(p->pdev, DEVCONFIG, &devconfig);
- if ( (aic7xxx_stpwlev >> p->instance) & 0x01 )
- {
- devconfig |= STPWLEVEL;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("(scsi%d) Force setting STPWLEVEL bitn", p->host_no);
- }
- else
- {
- devconfig &= ~STPWLEVEL;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("(scsi%d) Force clearing STPWLEVEL bitn", p->host_no);
- }
- pci_write_config_byte(p->pdev, DEVCONFIG, devconfig);
- }
- }
- #endif
- /*
- * That took care of devconfig and stpwlev, now for the actual termination
- * settings.
- */
- if (aic7xxx_override_term != -1)
- {
- /*
- * Again, this only applies to PCI controllers. We don't have problems
- * with the termination on 274x controllers to the best of my knowledge.
- */
- if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
- {
- unsigned char term_override;
- term_override = ( (aic7xxx_override_term >> (p->instance * 4)) & 0x0f);
- p->adapter_control &=
- ~(CFSTERM|CFWSTERM|CFLVDSTERM|CFAUTOTERM|CFSEAUTOTERM);
- if ( (p->features & AHC_ULTRA2) && (term_override & 0x0c) )
- {
- p->adapter_control |= CFLVDSTERM;
- }
- if (term_override & 0x02)
- {
- p->adapter_control |= CFWSTERM;
- }
- if (term_override & 0x01)
- {
- p->adapter_control |= CFSTERM;
- }
- }
- }
- if ( (p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1) )
- {
- if (p->features & AHC_SPIOCAP)
- {
- if ( aic_inb(p, SPIOCAP) & SSPIOCPS )
- /*
- * Update the settings in sxfrctl1 to match the termination
- * settings.
- */
- configure_termination(p);
- }
- else if ((p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870)
- {
- configure_termination(p);
- }
- }
- /*
- * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
- */
- if (p->features & AHC_TWIN)
- {
- /* Select channel B */
- aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
- if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1))
- term = (aic_inb(p, SXFRCTL1) & STPWEN);
- else
- term = ((p->flags & AHC_TERM_ENB_B) ? STPWEN : 0);
- aic_outb(p, p->scsi_id_b, SCSIID);
- scsi_conf = aic_inb(p, SCSICONF + 1);
- aic_outb(p, DFON | SPIOEN, SXFRCTL0);
- aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term |
- ENSTIMER | ACTNEGEN, SXFRCTL1);
- aic_outb(p, 0, SIMODE0);
- aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
- aic_outb(p, 0, SCSIRATE);
- /* Select channel A */
- aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
- }
- if (p->features & AHC_ULTRA2)
- {
- aic_outb(p, p->scsi_id, SCSIID_ULTRA2);
- }
- else
- {
- aic_outb(p, p->scsi_id, SCSIID);
- }
- if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1))
- term = (aic_inb(p, SXFRCTL1) & STPWEN);
- else
- term = ((p->flags & (AHC_TERM_ENB_A|AHC_TERM_ENB_LVD)) ? STPWEN : 0);
- scsi_conf = aic_inb(p, SCSICONF);
- aic_outb(p, DFON | SPIOEN, SXFRCTL0);
- aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term |
- ENSTIMER | ACTNEGEN, SXFRCTL1);
- aic_outb(p, 0, SIMODE0);
- /*
- * 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_STPWEN)
- 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);
- /*
- * Look at the information that board initialization or the board
- * BIOS has left us. In the lower four bits of each target's
- * scratch space any value other than 0 indicates that we should
- * initiate synchronous transfers. If it's zero, the user or the
- * BIOS has decided to disable synchronous negotiation to that
- * target so we don't activate the needsdtr flag.
- */
- if ((p->features & (AHC_TWIN|AHC_WIDE)) == 0)
- {
- max_targets = 8;
- }
- else
- {
- max_targets = 16;
- }
- if (!(aic7xxx_no_reset))
- {
- /*
- * If we reset the bus, then clear the transfer settings, else leave
- * them be
- */
- for (i = 0; i < max_targets; i++)
- {
- aic_outb(p, 0, TARG_SCSIRATE + i);
- if (p->features & AHC_ULTRA2)
- {
- aic_outb(p, 0, TARG_OFFSET + i);
- }
- p->transinfo[i].cur_offset = 0;
- p->transinfo[i].cur_period = 0;
- p->transinfo[i].cur_width = MSG_EXT_WDTR_BUS_8_BIT;
- }
- /*
- * If we reset the bus, then clear the transfer settings, else leave
- * them be.
- */
- aic_outb(p, 0, ULTRA_ENB);
- aic_outb(p, 0, ULTRA_ENB + 1);
- p->ultraenb = 0;
- }
- /*
- * Allocate enough hardware scbs to handle the maximum number of
- * concurrent transactions we can have. We have to make sure that
- * the allocated memory is contiguous memory. The Linux kmalloc
- * routine should only allocate contiguous memory, but note that
- * this could be a problem if kmalloc() is changed.
- */
- {
- size_t array_size;
- unsigned int hscb_physaddr;
- array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
- if (p->scb_data->hscbs == NULL)
- {
- /* pci_alloc_consistent enforces the alignment already and
- * clears the area as well.
- */
- 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);
- p->irq = 0;
- return(0);
- }
- 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 */
- 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);
- aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3);
- }
- /* The Q-FIFOs we just set up are all empty */
- aic_outb(p, 0, QINPOS);
- aic_outb(p, 0, KERNEL_QINPOS);
- aic_outb(p, 0, QOUTPOS);
- if(p->features & AHC_QUEUE_REGS)
- {
- aic_outb(p, SCB_QSIZE_256, QOFF_CTLSTA);
- aic_outb(p, 0, SDSCB_QOFF);
- aic_outb(p, 0, SNSCB_QOFF);
- aic_outb(p, 0, HNSCB_QOFF);
- }
- /*
- * We don't have any waiting selections or disconnected SCBs.
- */
- aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
- aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
- /*
- * Message out buffer starts empty
- */
- aic_outb(p, MSG_NOOP, MSG_OUT);
- aic_outb(p, MSG_NOOP, LAST_MSG);
- /*
- * Set all the other asundry items that haven't been set yet.
- * This includes just dumping init values to a lot of registers simply
- * to make sure they've been touched and are ready for use parity wise
- * speaking.
- */
- aic_outb(p, 0, TMODE_CMDADDR);
- aic_outb(p, 0, TMODE_CMDADDR + 1);
- aic_outb(p, 0, TMODE_CMDADDR + 2);
- aic_outb(p, 0, TMODE_CMDADDR + 3);
- aic_outb(p, 0, TMODE_CMDADDR_NEXT);
- /*
- * Link us into the list of valid hosts
- */
- p->next = first_aic7xxx;
- first_aic7xxx = 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
- * soon as we register the IRQ for this card, we could get an interrupt that
- * includes possibly the SCSI_RSTI interrupt. If we catch that interrupt
- * then we are likely to segfault if we don't have at least one chunk of
- * SCBs allocated or add checks all through the reset code to make sure
- * that the SCBs have been allocated which is an invalid running condition
- * and therefore I think it's preferable to simply pre-allocate the first
- * chunk of SCBs.
- */
- aic7xxx_allocate_scb(p);
- /*
- * Load the sequencer program, then re-enable the board -
- * resetting the AIC-7770 disables it, leaving the lights
- * on with nobody home.
- */
- aic7xxx_loadseq(p);
- /*
- * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register
- */
- aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL);
- if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
- {
- aic_outb(p, ENABLE, BCTL); /* Enable the boards BUS drivers. */
- }
- if ( !(aic7xxx_no_reset) )
- {
- if (p->features & AHC_TWIN)
- {
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) Resetting channel Bn", p->host_no);
- aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
- aic7xxx_reset_current_bus(p);
- aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
- }
- /* Reset SCSI bus A. */
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- { /* In case we are a 3940, 3985, or 7895, print the right channel */
- char *channel = "";
- if (p->flags & AHC_MULTI_CHANNEL)
- {
- channel = " A";
- if (p->flags & (AHC_CHNLB|AHC_CHNLC))
- channel = (p->flags & AHC_CHNLB) ? " B" : " C";
- }
- printk(KERN_INFO "(scsi%d) Resetting channel%sn", p->host_no, channel);
- }
-
- aic7xxx_reset_current_bus(p);
- /*
- * Delay for the reset delay by setting the timer, this will delay
- * future commands sent to any devices.
- */
- 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
- {
- if (!reset_delay)
- {
- printk(KERN_INFO "(scsi%d) Not resetting SCSI bus. Note: Don't use "
- "the no_resetn", p->host_no);
- printk(KERN_INFO "(scsi%d) option unless you have a verifiable need "
- "for it.n", p->host_no);
- }
- }
-
- /*
- * Register IRQ with the kernel. Only allow sharing IRQs with
- * PCI devices.
- */
- if (!(p->chip & AHC_PCI))
- {
- result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p));
- }
- else
- {
- result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
- "aic7xxx", p));
- if (result < 0)
- {
- result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
- "aic7xxx", p));
- }
- }
- if (result < 0)
- {
- printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
- "controller.n", p->host_no, p->irq);
- aic_outb(p, 0, SIMODE1);
- 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);
- unpause_sequencer(p, /* unpause_always */ TRUE);
- return (found);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_chip_reset
- *
- * Description:
- * Perform a chip reset on the aic7xxx SCSI controller. The controller
- * is paused upon return.
- *-F*************************************************************************/
- int
- aic7xxx_chip_reset(struct aic7xxx_host *p)
- {
- unsigned char sblkctl;
- int wait;
- /*
- * For some 274x boards, we must clear the CHIPRST bit and pause
- * the sequencer. For some reason, this makes the driver work.
- */
- aic_outb(p, PAUSE | CHIPRST, HCNTRL);
- /*
- * In the future, we may call this function as a last resort for
- * error handling. Let's be nice and not do any unnecessary delays.
- */
- wait = 1000; /* 1 msec (1000 * 1 msec) */
- while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
- {
- udelay(1); /* 1 usec */
- }
- pause_sequencer(p);
- sblkctl = aic_inb(p, SBLKCTL) & (SELBUSB|SELWIDE);
- if (p->chip & AHC_PCI)
- sblkctl &= ~SELBUSB;
- switch( sblkctl )
- {
- case 0: /* normal narrow card */
- break;
- case 2: /* Wide card */
- p->features |= AHC_WIDE;
- break;
- case 8: /* Twin card */
- p->features |= AHC_TWIN;
- p->flags |= AHC_MULTI_CHANNEL;
- break;
- default: /* hmmm...we don't know what this is */
- printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.n",
- aic_inb(p, SBLKCTL) & 0x0a);
- return(-1);
- }
- return(0);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_alloc
- *
- * Description:
- * Allocate and initialize a host structure. Returns NULL upon error
- * and a pointer to a aic7xxx_host struct upon success.
- *-F*************************************************************************/
- static struct aic7xxx_host *
- aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
- {
- struct aic7xxx_host *p = NULL;
- struct Scsi_Host *host;
- int i;
- /*
- * Allocate a storage area by registering us with the mid-level
- * SCSI layer.
- */
- host = scsi_register(sht, sizeof(struct aic7xxx_host));
- if (host != NULL)
- {
- p = (struct aic7xxx_host *) host->hostdata;
- memset(p, 0, sizeof(struct aic7xxx_host));
- *p = *temp;
- p->host = host;
- host->max_sectors = 512;
- p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
- if (p->scb_data != NULL)
- {
- memset(p->scb_data, 0, sizeof(scb_data_type));
- scbq_init (&p->scb_data->free_scbs);
- }
- else
- {
- /*
- * For some reason we don't have enough memory. Free the
- * allocated memory for the aic7xxx_host struct, and return NULL.
- */
- release_region(p->base, MAXREG - MINREG);
- scsi_unregister(host);
- return(NULL);
- }
- p->host_no = host->host_no;
- p->tagenable = 0;
- p->orderedtag = 0;
- for (i=0; i<MAX_TARGETS; i++)
- {
- p->transinfo[i].goal_period = 255;
- p->transinfo[i].goal_offset = 0;
- p->transinfo[i].goal_options = 0;
- p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
- }
- DRIVER_LOCK_INIT
- }
- scsi_set_pci_device(host, p->pdev);
- return (p);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_free
- *
- * Description:
- * Frees and releases all resources associated with an instance of
- * the driver (struct aic7xxx_host *).
- *-F*************************************************************************/
- static void
- aic7xxx_free(struct aic7xxx_host *p)
- {
- int i;
- /*
- * Free the allocated hardware SCB space.
- */
- if (p->scb_data != NULL)
- {
- struct aic7xxx_scb_dma *scb_dma = NULL;
- if (p->scb_data->hscbs != NULL)
- {
- 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;
- }
- /*
- * Free the driver SCBs. These were allocated on an as-need
- * basis. We allocated these in groups depending on how many
- * we could fit into a given amount of RAM. The tail SCB for
- * these allocations has a pointer to the alloced area.
- */
- 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;
- }
-
- /*
- * Free the SCB data area.
- */
- kfree(p->scb_data);
- }
- pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_load_seeprom
- *
- * Description:
- * Load the seeprom and configure adapter and target settings.
- * Returns 1 if the load was successful and 0 otherwise.
- *-F*************************************************************************/
- static void
- aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
- {
- int have_seeprom = 0;
- int i, max_targets, mask;
- unsigned char scsirate, scsi_conf;
- unsigned short scarray[128];
- struct seeprom_config *sc = (struct seeprom_config *) scarray;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
- }
- switch (p->chip)
- {
- case (AHC_AIC7770|AHC_EISA): /* None of these adapters have seeproms. */
- if (aic_inb(p, SCSICONF) & TERM_ENB)
- p->flags |= AHC_TERM_ENB_A;
- if ( (p->features & AHC_TWIN) && (aic_inb(p, SCSICONF + 1) & TERM_ENB) )
- p->flags |= AHC_TERM_ENB_B;
- break;
- case (AHC_AIC7770|AHC_VL):
- have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
- break;
- default:
- have_seeprom = read_seeprom(p, (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)),