📄 eata_dma.c
字号:
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 + -