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

📄 wd7000.c

📁 linux0.99源代码用于研究linux操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
    /* 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 = (*cdb <= 0x1f ? 6 : 10);    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 = 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) {	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};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;    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;    /* 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;}void wd7000_set_sync(int id){    volatile unchar icb[ICB_LEN] = {0x8a};    unchar speedval = 0x2c; 	/* Sets 4MHz for SBIC Revision A */    any2scsi(icb+2,1);		/* Transfer 1 byte */    any2scsi(icb+5,&speedval);	/* The speed buffer address */    icb[8]=0; icb[9]=2*id;      /* The index into the table */    icb[ICB_PHASE] = 1;    mail_out( (struct scb *) icb );    while (icb[ICB_PHASE]) /* wait for completion */;}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 < (*cdbj <= 0x1f?6:10);  j++)  printk(" %02x", *(cdbj++));       printk(" result %08x\n", SCpnt->result);    }#endif    return 0;}int wd7000_reset(void){#ifdef DEBUG    printk("wd7000_reset\n");#endif    return 0;}int wd7000_biosparam(int size, int dev, int* info)/* *  This is borrowed directly from aha1542.c, but my disks are organized *   this way, so I think it will work OK. */{  info[0] = 32;  info[1] = 64;  info[2] = (size + 2047) >> 11;  if (info[2] >= 1024) info[2] = 1024;  return 0;}

⌨️ 快捷键说明

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