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

📄 wd7000.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 2 页
字号:
        wd7000_intr_ack();	return;    }    /* The interrupt is for an incoming mailbox */    icmb = flag & 0x3f;    scb = (struct scb *) scsi2int(mb.icmb[icmb].scbptr);    icmb_status = mb.icmb[icmb].status;    mb.icmb[icmb].status = 0;#ifdef DEBUG    printk(" ICMB %d posted for SCB/ICB %06x, status %02x, vue %02x", 	   icmb, scb, icmb_status, scb->vue );#endif    if (!(scb->op & 0x80))  {   /* an SCB is done */        SCpnt = scb->SCpnt;	if (--(SCpnt->SCp.phase) <= 0)  {  /* all scbs for SCpnt are done */	    host_error = scb->vue | (icmb_status << 8);	    scsi_error = scb->status;	    errstatus = make_code(host_error,scsi_error);    	    SCpnt->result = errstatus; 	    if (SCpnt->host_scribble != NULL) 	        scsi_free(SCpnt->host_scribble,WD7000_SCRIBBLE); 	    free_scb(scb);	    SCpnt->scsi_done(SCpnt);	}    }  else  {    /* an ICB is done */        icb = (unchar *) scb;        icb[ICB_STATUS] = icmb_status;	icb[ICB_PHASE] = 0;    }    wd7000_intr_ack();    DEB(printk(".\n");)    return;}int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)){    Scb *scb;    Sgb *sgb;    unchar *cdb;    unchar idlun;    short cdblen;    cdb = (unchar *) SCpnt->cmnd;    cdblen = COMMAND_SIZE(*cdb);    idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);    SCpnt->scsi_done = done;    SCpnt->SCp.phase = 1;    scb = alloc_scb();    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 = NULL;    DEB(printk("request_bufflen is %x, bufflen is %x\n",\        SCpnt->request_bufflen, SCpnt->bufflen);)    if (SCpnt->use_sg)  {        struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;        unsigned i;        if (scsi_hosts[wd7000_host].sg_tablesize <= 0)  {	    panic("wd7000_queuecommand: scatter/gather not supported.\n");	}#ifdef DEBUG 	printk("Using scatter/gather with %d elements.\n",SCpnt->use_sg);#endif  	/* 	    Allocate memory for a scatter/gather-list in wd7000 format. 	    Save the pointer at host_scribble.  	*/#ifdef DEBUG 	if (SCpnt->use_sg > WD7000_SG) 	    panic("WD7000: requesting too many scatterblocks\n");#endif 	SCpnt->host_scribble = (unsigned char *) scsi_malloc(WD7000_SCRIBBLE);	sgb = (Sgb *) SCpnt->host_scribble; 	if (sgb == NULL)            panic("wd7000_queuecommand: scsi_malloc() failed.\n"); 	scb->op = 1; 	any2scsi(scb->dataptr, sgb); 	any2scsi(scb->maxlen, SCpnt->use_sg * sizeof (Sgb) );	for (i = 0;  i < SCpnt->use_sg;  i++)  { 	    any2scsi(sgb->ptr, sg[i].address); 	    any2scsi(sgb->len, sg[i].length); 	    sgb++;        } 	DEB(printk("Using %d bytes for %d scatter/gather blocks\n",\ 	    scsi2int(scb->maxlen), SCpnt->use_sg);)    }  else  {	scb->op = 0;	any2scsi(scb->dataptr, SCpnt->request_buffer);	any2scsi(scb->maxlen, SCpnt->request_bufflen);    }    return mail_out(scb);}int wd7000_command(Scsi_Cmnd *SCpnt){    wd7000_queuecommand(SCpnt, wd7000_scsi_done);    while (SCpnt->SCp.phase > 0);  /* phase counts scbs down to 0 */    return SCpnt->result;}int wd7000_init(void){   int i;    unchar init_block[] = {        INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, 0, 0, 0, OGMB_CNT, ICMB_CNT    };    /* Reset the adapter. */    outb(SCSI_RES|ASC_RES, CONTROL);    delay(1);  /* reset pulse: this is 10ms, only need 25us */    outb(0,CONTROL);  controlstat = 0;    /*       Wait 2 seconds, then expect Command Port Ready.       I suspect something else needs to be done here, but I don't know       what.  The OEM doc says power-up diagnostics take 2 seconds, and       indeed, SCSI commands submitted before then will time out, but       none of what follows seems deterred by _not_ waiting 2 secs.    */    delay(200);    WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);    DEB(printk("wd7000_init: Power-on Diagnostics finished\n");)    if (((i=inb(INTR_STAT)) != 1) && (i != 7)) {	panic("wd7000_init: Power-on Diagnostics error\n"); 	return 0;    }        /* Clear mailboxes */    memset(&mb,0,sizeof (mb));    /* Set up SCB free list */    init_scbs();    /* Set up init block */    any2scsi(init_block+5,&mb);    /* Execute init command */    if (!command_out(init_block,sizeof(init_block)))  {	panic("WD-7000 Initialization failed.\n"); 	return 0;    }        /* Wait until init finished */    WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);    outb(DISABLE_UNS_INTR, COMMAND);     WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);    /* Enable Interrupt and DMA */    if (request_irq(IRQ_LVL, wd7000_intr_handle)) {      panic("Unable to allocate IRQ for WD-7000.\n");      return 0;    };    if(request_dma(DMA_CH)) {      panic("Unable to allocate DMA channel for WD-7000.\n");      free_irq(IRQ_LVL);      return 0;    };    wd7000_enable_dma();    wd7000_enable_intr();    printk("WD-7000 initialized.\n");    return 1;  fail:    return 0;					/* 0 = not ok */}void wd7000_revision(void){    volatile unchar icb[ICB_LEN] = {0x8c};  /* read firmware revision level */    icb[ICB_PHASE] = 1;    mail_out( (struct scb *) icb );    while (icb[ICB_PHASE]) /* wait for completion */;    rev_1 = icb[1];    rev_2 = icb[2];    /*        For boards at rev 7.0 or later, enable scatter/gather.    */    if (rev_1 >= 7)  scsi_hosts[wd7000_host].sg_tablesize = WD7000_SG;}static const char *wd_bases[] = {(char *)0xce000,(char *)0xd8000};typedef struct {    char * signature;    unsigned offset;    unsigned length;} Signature;static const Signature signatures[] = {{"SSTBIOS",0xd,0x7}};#define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))int wd7000_detect(int hostnum)/*  *  return non-zero on detection */{    int i,j;    char const *base_address = NULL;    if(check_region(IO_BASE, 4)) return 0;  /* IO ports in use */    for(i=0;i<(sizeof(wd_bases)/sizeof(char *));i++){	for(j=0;j<NUM_SIGNATURES;j++){	    if(!memcmp((void *)(wd_bases[i] + signatures[j].offset),		(void *) signatures[j].signature,signatures[j].length)){		    base_address=wd_bases[i];		    printk("WD-7000 detected.\n");	    }		}    }    if (base_address == NULL) return 0;    snarf_region(IO_BASE, 4); /* Register our ports */    /* Store our host number */    wd7000_host = hostnum;    wd7000_init();        wd7000_revision();  /* will set scatter/gather by rev level */    return 1;}static void wd7000_append_info( char *info, const char *fmt, ... )/* *  This is just so I can use vsprintf... */{    va_list args;    extern int vsprintf(char *buf, const char *fmt, va_list args);    va_start(args, fmt);    vsprintf(info, fmt, args);    va_end(args);    return;}const char *wd7000_info(void){    static char info[80] = "Western Digital WD-7000, Firmware Revision ";    wd7000_revision();    wd7000_append_info( info+strlen(info), "%d.%d.\n", rev_1, rev_2 );    return info;}int wd7000_abort(Scsi_Cmnd * SCpnt, int i){#ifdef DEBUG    printk("wd7000_abort: Scsi_Cmnd = 0x%08x, code = %d ", SCpnt, i);    printk("id %d lun %d cdb", SCpnt->target, SCpnt->lun);    {  int j;  unchar *cdbj = (unchar *) SCpnt->cmnd;       for (j=0; j < COMMAND_SIZE(*cdbj);  j++)  printk(" %02x", *(cdbj++));       printk(" result %08x\n", SCpnt->result);    }#endif    return 0;}/* We do not implement a reset function here, but the upper level code assumes   that it will get some kind of response for the command in SCpnt.  We must   oblige, or the command will hang the scsi system */int wd7000_reset(Scsi_Cmnd * SCpnt){#ifdef DEBUG    printk("wd7000_reset\n");#endif    if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;    return 0;}int wd7000_biosparam(int size, int dev, int* ip)/* *  This is borrowed directly from aha1542.c, but my disks are organized *   this way, so I think it will work OK. */{  ip[0] = 64;  ip[1] = 32;  ip[2] = size >> 11;/*  if (ip[2] >= 1024) ip[2] = 1024; */  return 0;}

⌨️ 快捷键说明

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