⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wd7000.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
{    register unsigned long flags;    save_flags (flags);    cli ();    memset (scb, 0, sizeof (Scb));    scb->next = scbfree;    scbfree = scb;    freescbs++;    restore_flags (flags);}static inline void init_scbs (void){    int i;    unsigned long flags;    save_flags (flags);    cli ();    scbfree = &(scbs[0]);    memset (scbs, 0, sizeof (scbs));    for (i = 0; i < MAX_SCBS - 1; i++) {	scbs[i].next = &(scbs[i + 1]);	scbs[i].SCpnt = NULL;    }    scbs[MAX_SCBS - 1].next = NULL;    scbs[MAX_SCBS - 1].SCpnt = NULL;    restore_flags (flags);}static int mail_out (Adapter *host, Scb *scbptr)/* *  Note: this can also be used for ICBs; just cast to the parm type. */{    register int i, ogmb;    register unsigned long flags;    unchar start_ogmb;    Mailbox *ogmbs = host->mb.ogmb;    int *next_ogmb = &(host->next_ogmb);#ifdef WD7000_DEBUG    printk ("wd7000_mail_out: 0x%06lx", (long) scbptr);#endif    /* We first look for a free outgoing mailbox */    save_flags (flags);    cli ();    ogmb = *next_ogmb;    for (i = 0; i < OGMB_CNT; i++) {	if (ogmbs[ogmb].status == 0) {#ifdef WD7000_DEBUG	    printk (" using OGMB 0x%x", ogmb);#endif	    ogmbs[ogmb].status = 1;	    any2scsi ((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);	    *next_ogmb = (ogmb + 1) % OGMB_CNT;	    break;	}	else	    ogmb = (++ogmb) % OGMB_CNT;    }    restore_flags (flags);#ifdef WD7000_DEBUG    printk (", scb is 0x%06lx", (long) scbptr);#endif    if (i >= OGMB_CNT) {	/*	 *  Alternatively, we might issue the "interrupt on free OGMB",	 *  and sleep, but it must be ensured that it isn't the init	 *  task running.  Instead, this version assumes that the caller	 *  will be persistent, and try again.  Since it's the adapter	 *  that marks OGMB's free, waiting even with interrupts off	 *  should work, since they are freed very quickly in most cases.	 */#ifdef WD7000_DEBUG	printk (", no free OGMBs.\n");#endif	return (0);    }    wd7000_enable_intr (host);    start_ogmb = START_OGMB | ogmb;    command_out (host, &start_ogmb, 1);#ifdef WD7000_DEBUG    printk (", awaiting interrupt.\n");#endif    return (1);}int make_code (unsigned hosterr, unsigned scsierr){#ifdef WD7000_DEBUG    int in_error = hosterr;#endif    switch ((hosterr >> 8) & 0xff) {	case 0:  /* Reserved */                 hosterr = DID_ERROR;                 break;	case 1:  /* Command Complete, no errors */                 hosterr = DID_OK;                 break;	case 2:  /* Command complete, error logged in scb status (scsierr) */                 hosterr = DID_OK;                 break;	case 4:  /* Command failed to complete - timeout */                 hosterr = DID_TIME_OUT;                 break;	case 5:  /* Command terminated; Bus reset by external device */                 hosterr = DID_RESET;                 break;	case 6:  /* Unexpected Command Received w/ host as target */                 hosterr = DID_BAD_TARGET;                 break;	case 80: /* Unexpected Reselection */	case 81: /* Unexpected Selection */                 hosterr = DID_BAD_INTR;                 break;	case 82: /* Abort Command Message  */                 hosterr = DID_ABORT;                 break;	case 83: /* SCSI Bus Software Reset */	case 84: /* SCSI Bus Hardware Reset */                 hosterr = DID_RESET;                 break;	default: /* Reserved */                 hosterr = DID_ERROR;    }#ifdef WD7000_DEBUG    if (scsierr || hosterr)	printk ("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",		scsierr, in_error, hosterr);#endif    return (scsierr | (hosterr << 16));}static void wd7000_scsi_done (Scsi_Cmnd *SCpnt){#ifdef WD7000_DEBUG    printk ("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt);#endif    SCpnt->SCp.phase = 0;}#define wd7000_intr_ack(host)   outb (0, host->iobase + ASC_INTR_ACK)void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs){    register int flag, icmb, errstatus, icmb_status;    register int host_error, scsi_error;    register Scb *scb;		/* for SCSI commands */    register IcbAny *icb;	/* for host commands */    register Scsi_Cmnd *SCpnt;    Adapter *host = (Adapter *) wd7000_host[irq - IRQ_MIN]->hostdata;	/* This MUST be set!!! */    Mailbox *icmbs = host->mb.icmb;    host->int_counter++;#ifdef WD7000_DEBUG    printk ("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);#endif    flag = inb (host->iobase + ASC_INTR_STAT);#ifdef WD7000_DEBUG    printk ("wd7000_intr_handle: intr stat = 0x%02x\n", flag);#endif    if (!(inb (host->iobase + ASC_STAT) & INT_IM)) {	/* NB: these are _very_ possible if IRQ 15 is being used, since	 * it's the "garbage collector" on the 2nd 8259 PIC.  Specifically,	 * any interrupt signal into the 8259 which can't be identified	 * comes out as 7 from the 8259, which is 15 to the host.  Thus, it	 * is a good thing the WD7000 has an interrupt status port, so we	 * can sort these out.  Otherwise, electrical noise and other such	 * problems would be indistinguishable from valid interrupts...	 */#ifdef WD7000_DEBUG	printk ("wd7000_intr_handle: phantom interrupt...\n");#endif	wd7000_intr_ack (host);	return;    }    if (flag & MB_INTR) {	/* The interrupt is for a mailbox */	if (!(flag & IMB_INTR)) {#ifdef WD7000_DEBUG	    printk ("wd7000_intr_handle: free outgoing mailbox\n");#endif	    /*	     * If sleep_on() and the "interrupt on free OGMB" command are	     * used in mail_out(), wake_up() should correspondingly be called	     * here.  For now, we don't need to do anything special.	     */	    wd7000_intr_ack (host);	    return;	}	else {	    /* The interrupt is for an incoming mailbox */	    icmb = flag & MB_MASK;	    icmb_status = icmbs[icmb].status;	    if (icmb_status & 0x80) {	/* unsolicited - result in ICMB */#ifdef WD7000_DEBUG		printk ("wd7000_intr_handle: unsolicited interrupt 0x%02x\n",			icmb_status);#endif		wd7000_intr_ack (host);		return;	    }	    /* Aaaargh! (Zaga) */	    scb = bus_to_virt(scsi2int ((unchar *) icmbs[icmb].scbptr));	    icmbs[icmb].status = 0;	    if (!(scb->op & ICB_OP_MASK)) {	/* an SCB is done */		SCpnt = scb->SCpnt;		if (--(SCpnt->SCp.phase) <= 0) {	/* all scbs are done */		    host_error = scb->vue | (icmb_status << 8);		    scsi_error = scb->status;		    errstatus = make_code (host_error, scsi_error);		    SCpnt->result = errstatus;		    free_scb (scb);		    SCpnt->scsi_done (SCpnt);		}	    }	    else {		/* an ICB is done */		icb = (IcbAny *) scb;		icb->status = icmb_status;		icb->phase = 0;	    }	}			/* incoming mailbox */    }    wd7000_intr_ack (host);#ifdef WD7000_DEBUG    printk ("wd7000_intr_handle: return from interrupt handler\n");#endif}void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs){    unsigned long flags;    spin_lock_irqsave(&io_request_lock, flags);    wd7000_intr_handle(irq, dev_id, regs);    spin_unlock_irqrestore(&io_request_lock, flags);}int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *)){    register Scb *scb;    register Sgb *sgb;    register unchar *cdb = (unchar *) SCpnt->cmnd;    register unchar idlun;    register short cdblen;    Adapter *host = (Adapter *) SCpnt->host->hostdata;    cdblen = SCpnt->cmd_len;    idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);    SCpnt->scsi_done = done;    SCpnt->SCp.phase = 1;    scb = alloc_scbs (1);    scb->idlun = idlun;    memcpy (scb->cdb, cdb, cdblen);    scb->direc = 0x40;		/* Disable direction check */    scb->SCpnt = SCpnt;		/* so we can find stuff later */    SCpnt->host_scribble = (unchar *) scb;    scb->host = host;    if (SCpnt->use_sg) {	struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;	unsigned i;	if (SCpnt->host->sg_tablesize == SG_NONE) {	    panic ("wd7000_queuecommand: scatter/gather not supported.\n");	}#ifdef WD7000_DEBUG	printk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg);#endif	sgb = scb->sgb;	scb->op = 1;	any2scsi (scb->dataptr, (int) sgb);	any2scsi (scb->maxlen, SCpnt->use_sg * sizeof (Sgb));	for (i = 0; i < SCpnt->use_sg; i++) {	    any2scsi (sgb[i].ptr, (int) sg[i].address);	    any2scsi (sgb[i].len, sg[i].length);	}    }    else {	scb->op = 0;	any2scsi (scb->dataptr, (int) SCpnt->request_buffer);	any2scsi (scb->maxlen, SCpnt->request_bufflen);    }    while (!mail_out (host, scb));	/* keep trying */    return (1);}int wd7000_command (Scsi_Cmnd *SCpnt){    wd7000_queuecommand (SCpnt, wd7000_scsi_done);    while (SCpnt->SCp.phase > 0)	barrier ();		/* phase counts scbs down to 0 */    return (SCpnt->result);}int wd7000_diagnostics (Adapter *host, int code){    static IcbDiag icb = {ICB_OP_DIAGNOSTICS};    static unchar buf[256];    unsigned long timeout;    icb.type = code;    any2scsi (icb.len, sizeof (buf));    any2scsi (icb.ptr, (int) &buf);    icb.phase = 1;    /*     * This routine is only called at init, so there should be OGMBs     * available.  I'm assuming so here.  If this is going to     * fail, I can just let the timeout catch the failure.     */    mail_out (host, (struct scb *) &icb);    timeout = jiffies + WAITnexttimeout;	/* wait up to 2 seconds */    while (icb.phase && time_before(jiffies, timeout))	barrier ();		/* wait for completion */    if (icb.phase) {	printk ("wd7000_diagnostics: timed out.\n");	return (0);    }    if (make_code (icb.vue | (icb.status << 8), 0)) {	printk ("wd7000_diagnostics: failed (0x%02x,0x%02x)\n",		icb.vue, icb.status);	return (0);    }    return (1);}int wd7000_init (Adapter *host){    InitCmd init_cmd =    {	INITIALIZATION, 	7,	host->bus_on,	host->bus_off,	0,	{ 0, 0, 0 },	OGMB_CNT,	ICMB_CNT    };    int diag;    /*     *  Reset the adapter - only.  The SCSI bus was initialized at power-up,     *  and we need to do this just so we control the mailboxes, etc.     */    outb (ASC_RES, host->iobase + ASC_CONTROL);    delay (1);			/* reset pulse: this is 10ms, only need 25us */    outb (0, host->iobase + ASC_CONTROL);    host->control = 0;		/* this must always shadow ASC_CONTROL */    if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {	printk ("wd7000_init: WAIT timed out.\n");	return (0);		/* 0 = not ok */    }    if ((diag = inb (host->iobase + ASC_INTR_STAT)) != 1) {	printk ("wd7000_init: ");	switch (diag) {	    case 2:  printk ("RAM failure.\n");		     break;	    case 3:  printk ("FIFO R/W failed\n");		     break;	    case 4:  printk ("SBIC register R/W failed\n");		     break;	    case 5:  printk ("Initialization D-FF failed.\n");		     break;	    case 6:  printk ("Host IRQ D-FF failed.\n");		     break;	    case 7:  printk ("ROM checksum error.\n");		     break;	    default: printk ("diagnostic code 0x%02Xh received.\n", diag);	}	return (0);    }    /* Clear mailboxes */    memset (&(host->mb), 0, sizeof (host->mb));    /* Execute init command */    any2scsi ((unchar *) & (init_cmd.mailboxes), (int) &(host->mb));    if (!command_out (host, (unchar *) &init_cmd, sizeof (init_cmd))) {	printk ("wd7000_init: adapter initialization failed.\n");	return (0);    }    if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {	printk ("wd7000_init: WAIT timed out.\n");	return (0);    }    if (request_irq (host->irq, do_wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {	printk ("wd7000_init: can't get IRQ %d.\n", host->irq);	return (0);    }    if (request_dma (host->dma, "wd7000")) {	printk ("wd7000_init: can't get DMA channel %d.\n", host->dma);	free_irq (host->irq, NULL);	return (0);    }    wd7000_enable_dma (host);    wd7000_enable_intr (host);    if (!wd7000_diagnostics (host, ICB_DIAG_FULL)) {	free_dma (host->dma);	free_irq (host->irq, NULL);	return (0);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -