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

📄 eata_dma.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 4 页
字号:
        addr = virt_to_bus((void *)addr);    /*     * This is overkill.....but the MIPSen seem to need this     * and it will be optimized away for i86 and ALPHA machines.     */    flush_cache_all();    /* And now the address in nice little byte chunks */#ifdef __LITTLE_ENDIAN    outb(addr,       base + HA_WDMAADDR);    outb(addr >> 8,  base + HA_WDMAADDR + 1);    outb(addr >> 16, base + HA_WDMAADDR + 2);    outb(addr >> 24, base + HA_WDMAADDR + 3);#else    outb(addr >> 24, base + HA_WDMAADDR);    outb(addr >> 16, base + HA_WDMAADDR + 1);    outb(addr >> 8,  base + HA_WDMAADDR + 2);    outb(addr,       base + HA_WDMAADDR + 3);#endif    outb(command, base + HA_WCOMMAND);    return(TRUE);}inline int eata_send_immediate(u32 base, u32 addr, u8 ifc, u8 code, u8 code2){    if(addr != (u32) NULL)        addr = virt_to_bus((void *)addr);    /*     * This is overkill.....but the MIPSen seem to need this     * and it will be optimized away for i86 and ALPHA machines.     */    flush_cache_all();    outb(0x0, base + HA_WDMAADDR - 1);    if(addr){#ifdef __LITTLE_ENDIAN        outb(addr,       base + HA_WDMAADDR);	outb(addr >> 8,  base + HA_WDMAADDR + 1);	outb(addr >> 16, base + HA_WDMAADDR + 2);	outb(addr >> 24, base + HA_WDMAADDR + 3);#else        outb(addr >> 24, base + HA_WDMAADDR);	outb(addr >> 16, base + HA_WDMAADDR + 1);	outb(addr >> 8,  base + HA_WDMAADDR + 2);	outb(addr,       base + HA_WDMAADDR + 3);#endif    } else {        outb(0x0, base + HA_WDMAADDR);        outb(0x0, base + HA_WDMAADDR + 1); 	outb(code2, base + HA_WCODE2);	outb(code,  base + HA_WCODE);    }        outb(ifc, base + HA_WIFC);    outb(EATA_CMD_IMMEDIATE, base + HA_WCOMMAND);    return(TRUE);}int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *)){    unsigned int i, x, y;    ulong flags;    hostdata *hd;    struct Scsi_Host *sh;    struct eata_ccb *ccb;    struct scatterlist *sl;        save_flags(flags);    cli();#if 0    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {      if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {            printk("eata_dma: scsi%d interrupt pending in eata_queue.\n"		   "          Calling interrupt handler.\n", sh->host_no);            eata_int_handler(sh->irq, 0, 0);      }    }#endif        queue_counter++;    hd = HD(cmd);    sh = cmd->host;        if (cmd->cmnd[0] == REQUEST_SENSE && cmd->sense_buffer[0] != 0) {        DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n"));	cmd->result = DID_OK << 16;	done(cmd);	return(0);    }    /* check for free slot */    for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) { 	if (y >= sh->can_queue)	    y = 0;	if (hd->ccb[y].status == FREE)	    break;    }        hd->last_ccb = y;    if (x >= sh->can_queue) { 	cmd->result = DID_BUS_BUSY << 16;	DBG(DBG_QUEUE && DBG_ABNORM, 	    printk(KERN_CRIT "eata_queue pid %ld, HBA QUEUE FULL..., "		   "returning DID_BUS_BUSY\n", cmd->pid));	done(cmd);	restore_flags(flags);	return(0);    }    ccb = &hd->ccb[y];        memset(ccb, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *));        ccb->status = USED;			/* claim free slot */    restore_flags(flags);        DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n",			  cmd->pid, cmd->target, cmd->lun, y));    DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));        if(hd->do_latency == TRUE)         eata_latency_out(ccb, cmd);    cmd->scsi_done = (void *)done;        switch (cmd->cmnd[0]) {    case CHANGE_DEFINITION: case COMPARE:	  case COPY:    case COPY_VERIFY:	    case LOG_SELECT:	  case MODE_SELECT:    case MODE_SELECT_10:    case SEND_DIAGNOSTIC: case WRITE_BUFFER:    case FORMAT_UNIT:	    case REASSIGN_BLOCKS: case RESERVE:    case SEARCH_EQUAL:	    case SEARCH_HIGH:	  case SEARCH_LOW:    case WRITE_6:	    case WRITE_10:	  case WRITE_VERIFY:    case UPDATE_BLOCK:	    case WRITE_LONG:	  case WRITE_SAME:	    case SEARCH_HIGH_12:    case SEARCH_EQUAL_12: case SEARCH_LOW_12:    case WRITE_12:	    case WRITE_VERIFY_12: case SET_WINDOW:     case MEDIUM_SCAN:	    case SEND_VOLUME_TAG:	         case 0xea:	    /* alternate number for WRITE LONG */	ccb->DataOut = TRUE;	/* Output mode */	break;    case TEST_UNIT_READY:    default:	ccb->DataIn = TRUE;	/* Input mode  */    }    /* FIXME: This will have to be changed once the midlevel driver      *        allows different HBA IDs on every channel.     */    if (cmd->target == sh->this_id) 	ccb->Interpret = TRUE;	/* Interpret command */    if (cmd->use_sg) {	ccb->scatter = TRUE;	/* SG mode     */	if (ccb->sg_list == NULL) {	    ccb->sg_list = kmalloc(sh->sg_tablesize * sizeof(struct eata_sg_list),				  GFP_ATOMIC | GFP_DMA);	}	if (ccb->sg_list == NULL)	    panic("eata_dma: Run out of DMA memory for SG lists !\n");	ccb->cp_dataDMA = htonl(virt_to_bus(ccb->sg_list)); 		ccb->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list));	sl=(struct scatterlist *)cmd->request_buffer;	for(i = 0; i < cmd->use_sg; i++, sl++){	    ccb->sg_list[i].data = htonl(virt_to_bus(sl->address));	    ccb->sg_list[i].len = htonl((u32) sl->length);	}    } else {	ccb->scatter = FALSE;	ccb->cp_datalen = htonl(cmd->request_bufflen);	ccb->cp_dataDMA = htonl(virt_to_bus(cmd->request_buffer));    }        ccb->Auto_Req_Sen = TRUE;    ccb->cp_reqDMA = htonl(virt_to_bus(cmd->sense_buffer));    ccb->reqlen = sizeof(cmd->sense_buffer);        ccb->cp_id = cmd->target;    ccb->cp_channel = cmd->channel;    ccb->cp_lun = cmd->lun;    ccb->cp_dispri = TRUE;    ccb->cp_identify = TRUE;    memcpy(ccb->cp_cdb, cmd->cmnd, cmd->cmd_len);        ccb->cp_statDMA = htonl(virt_to_bus(&(hd->sp)));        ccb->cp_viraddr = ccb; /* This will be passed thru, so we don't need to 			    * convert it */    ccb->cmd = cmd;    cmd->host_scribble = (char *)&hd->ccb[y];	        if(eata_send_command((u32) ccb, (u32) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) {	cmd->result = DID_BUS_BUSY << 16;	DBG(DBG_QUEUE && DBG_ABNORM, 	    printk("eata_queue target %d, pid %ld, HBA busy, "		   "returning DID_BUS_BUSY\n",cmd->target, cmd->pid));	ccb->status = FREE;    	done(cmd);	return(0);    }    DBG(DBG_QUEUE, printk("Queued base %#.4x pid: %ld target: %x lun: %x "			 "slot %d irq %d\n", (s32)sh->base, cmd->pid, 			 cmd->target, cmd->lun, y, sh->irq));    DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));    return(0);}int eata_abort(Scsi_Cmnd * cmd){    ulong loop = HZ / 2;    ulong flags;    int x;    struct Scsi_Host *sh;     save_flags(flags);    cli();    DBG(DBG_ABNORM, printk("eata_abort called pid: %ld target: %x lun: %x"			   " reason %x\n", cmd->pid, cmd->target, cmd->lun, 			   cmd->abort_reason));    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));    /* Some interrupt controllers seem to loose interrupts */    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {        if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {            printk("eata_dma: scsi%d interrupt pending in eata_abort.\n"		   "          Calling interrupt handler.\n", sh->host_no);	    eata_int_handler(sh->irq, 0, 0);	}    }    while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) {	if (--loop == 0) {	    printk("eata_dma: abort, timeout error.\n");	    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	    restore_flags(flags);	    return (SCSI_ABORT_ERROR);	}    }    if (CD(cmd)->status == RESET) {	printk("eata_dma: abort, command reset error.\n");	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	restore_flags(flags);	return (SCSI_ABORT_ERROR);    }    if (CD(cmd)->status == LOCKED) {	DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n"));	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	restore_flags(flags);	return (SCSI_ABORT_NOT_RUNNING);    }    if (CD(cmd)->status == USED) {	DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n"));	restore_flags(flags);	return (SCSI_ABORT_BUSY);  /* SNOOZE */     }    if (CD(cmd)->status == FREE) {	DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n")); 	restore_flags(flags);	return (SCSI_ABORT_NOT_RUNNING);    }    restore_flags(flags);    panic("eata_dma: abort: invalid slot status\n");}int eata_reset(Scsi_Cmnd * cmd, unsigned int resetflags){    uint x;     ulong loop = loops_per_sec / 3;    ulong flags;    unchar success = FALSE;    Scsi_Cmnd *sp;     struct Scsi_Host *sh;        save_flags(flags);    cli();        DBG(DBG_ABNORM, printk("eata_reset called pid:%ld target: %x lun: %x"			   " reason %x\n", cmd->pid, cmd->target, cmd->lun, 			   cmd->abort_reason));	    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {        if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {            printk("eata_dma: scsi%d interrupt pending in eata_reset.\n"		   "          Calling interrupt handler.\n", sh->host_no);            eata_int_handler(sh->irq, 0, 0);      }    }    if (HD(cmd)->state == RESET) {	printk("eata_reset: exit, already in reset.\n");	restore_flags(flags);	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	return (SCSI_RESET_ERROR);    }        while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)	if (--loop == 0) {	    printk("eata_reset: exit, timeout error.\n");	    restore_flags(flags);	    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	    return (SCSI_RESET_ERROR);	}     for (x = 0; x < cmd->host->can_queue; x++) {	if (HD(cmd)->ccb[x].status == FREE)	    continue;	if (HD(cmd)->ccb[x].status == LOCKED) {	    HD(cmd)->ccb[x].status = FREE;	    printk("eata_reset: locked slot %d forced free.\n", x);	    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	    continue;	}	sp = HD(cmd)->ccb[x].cmd;	HD(cmd)->ccb[x].status = RESET;		if (sp == NULL)	    panic("eata_reset: slot %d, sp==NULL.\n", x);	printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid);	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));		if (sp == cmd)	    success = TRUE;    }        /* hard reset the HBA  */    inb((u32) (cmd->host->base) + HA_RSTATUS);	/* This might cause trouble */    eata_send_command(0, (u32) cmd->host->base, EATA_CMD_RESET);        HD(cmd)->state = RESET;    DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling "			   "interrupts.\n"));    DELAY(2); /* In theorie we should get interrupts and set free all	       * used queueslots */        DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled again.\n"));    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));        for (x = 0; x < cmd->host->can_queue; x++) {		/* Skip slots already set free by interrupt and those that          * are still LOCKED from the last reset */	if (HD(cmd)->ccb[x].status != RESET)	    continue;		sp = HD(cmd)->ccb[x].cmd;	sp->result = DID_RESET << 16;		/* This mailbox is still waiting for its interrupt */	HD(cmd)->ccb[x].status = LOCKED;		printk("eata_reset: slot %d locked, DID_RESET, pid %ld done.\n",	       x, sp->pid);	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	sp->scsi_done(sp);    }        HD(cmd)->state = FALSE;    restore_flags(flags);        if (success) {	DBG(DBG_ABNORM, printk("eata_reset: exit, pending.\n"));	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	return (SCSI_RESET_PENDING);    } else {	DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n"));	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	return (SCSI_RESET_PUNT);    }}/* Here we try to determine the optimum queue depth for * each attached device. * * At the moment the algorithm is rather simple */static void eata_select_queue_depths(struct Scsi_Host *host, 				     Scsi_Device *devicelist){    Scsi_Device *device;    int devcount = 0;     int factor = 0;#if CRIPPLE_QUEUE        for(device = devicelist; device != NULL; device = device->next) {        if(device->host == host)

⌨️ 快捷键说明

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