📄 sdata.c
字号:
cmd10[0] = 0x03; cmd10[1] = r->lun<<5; cmd10[4] = sizeof(r->sense)-1; drive->data = r->sense; drive->dlen = sizeof(r->sense)-1; drive->status = 0; drive->error = 0; if(drive->pkt) reqstatus = atapktio(drive, cmd10, 6); else reqstatus = atagenio(drive, cmd10, 6); if(reqstatus == SDok){ r->flags |= SDvalidsense; atasetsense(drive, SDok, 0, 0, 0); } } qunlock(drive); r->status = status; if(status != SDok) return status; /* * Fix up any results. * Many ATAPI CD-ROMs ignore the LUN field completely and * return valid INQUIRY data. Patch the response to indicate * 'logical unit not supported' if the LUN is non-zero. */ switch(cmdp[0]){ case 0x12: /* inquiry */ if((p = r->data) == nil) break; if((cmdp[1]>>5) && (!drive->pkt || (p[0] & 0x1F) == 0x05)) p[0] = 0x7F; /*FALLTHROUGH*/ default: break; } return SDok;}static voidatainterrupt(Ureg*, void* arg){ Ctlr *ctlr; Drive *drive; int cmdport, len, status; ctlr = arg; ilock(ctlr); if(inb(ctlr->ctlport+As) & Bsy){ iunlock(ctlr); if(DEBUG & DbgBsy) print("IBsy+"); return; } cmdport = ctlr->cmdport; status = inb(cmdport+Status); if((drive = ctlr->curdrive) == nil){ iunlock(ctlr); if((DEBUG & DbgINL) && ctlr->command != Cedd) print("Inil%2.2uX+", ctlr->command); return; } if(status & Err) drive->error = inb(cmdport+Error); else switch(drive->command){ default: drive->error = Abrt; break; case Crs: case Crsm: if(!(status & Drq)){ drive->error = Abrt; break; } len = drive->block; if(drive->data+len > drive->limit) len = drive->limit-drive->data; inss(cmdport+Data, drive->data, len/2); drive->data += len; if(drive->data >= drive->limit) ctlr->done = 1; break; case Cws: case Cwsm: len = drive->block; if(drive->data+len > drive->limit) len = drive->limit-drive->data; drive->data += len; if(drive->data >= drive->limit){ ctlr->done = 1; break; } if(!(status & Drq)){ drive->error = Abrt; break; } len = drive->block; if(drive->data+len > drive->limit) len = drive->limit-drive->data; outss(cmdport+Data, drive->data, len/2); break; case Cpkt: atapktinterrupt(drive); break; case Crd: case Cwd: atadmainterrupt(drive, drive->count*drive->secsize); break; case Cstandby: ctlr->done = 1; break; } iunlock(ctlr); if(drive->error){ status |= Err; ctlr->done = 1; } if(ctlr->done){ ctlr->curdrive = nil; drive->status = status; wakeup(ctlr); }}static SDev*atapnp(void){ Ctlr *ctlr; Pcidev *p; SDev *legacy[2], *sdev, *head, *tail; int channel, ispc87415, maxio, pi, r, span; legacy[0] = legacy[1] = head = tail = nil; if(sdev = ataprobe(0x1F0, 0x3F4, IrqATA0)){ head = tail = sdev; legacy[0] = sdev; } if(sdev = ataprobe(0x170, 0x374, IrqATA1)){ if(head != nil) tail->next = sdev; else head = sdev; tail = sdev; legacy[1] = sdev; } p = nil; while(p = pcimatch(p, 0, 0)){ /* * Look for devices with the correct class and sub-class * code and known device and vendor ID; add native-mode * channels to the list to be probed, save info for the * compatibility mode channels. * Note that the legacy devices should not be considered * PCI devices by the interrupt controller. * For both native and legacy, save info for busmastering * if capable. * Promise Ultra ATA/66 (PDC20262) appears to * 1) give a sub-class of 'other mass storage controller' * instead of 'IDE controller', regardless of whether it's * the only controller or not; * 2) put 0 in the programming interface byte (probably * as a consequence of 1) above). * Sub-class code 0x04 is 'RAID controller', e.g. VIA VT8237. */ if(p->ccrb != 0x01) continue; if(p->ccru != 0x01 && p->ccru != 0x04 && p->ccru != 0x80) continue; pi = p->ccrp; ispc87415 = 0; maxio = 0; span = BMspan; switch((p->did<<16)|p->vid){ default: continue; case (0x0002<<16)|0x100B: /* NS PC87415 */ /* * Disable interrupts on both channels until * after they are probed for drives. * This must be called before interrupts are * enabled because the IRQ may be shared. */ ispc87415 = 1; pcicfgw32(p, 0x40, 0x00000300); break; case (0x1000<<16)|0x1042: /* PC-Tech RZ1000 */ /* * Turn off prefetch. Overkill, but cheap. */ r = pcicfgr32(p, 0x40); r &= ~0x2000; pcicfgw32(p, 0x40, r); break; case (0x4D38<<16)|0x105A: /* Promise PDC20262 */ case (0x4D30<<16)|0x105A: /* Promise PDC202xx */ case (0x4D68<<16)|0x105A: /* Promise PDC20268 */ case (0x4D69<<16)|0x105A: /* Promise Ultra/133 TX2 */ case (0x3373<<16)|0x105A: /* Promise 20378 RAID */ case (0x3149<<16)|0x1106: /* VIA VT8237 SATA/RAID */ case (0x3112<<16)|0x1095: /* SiI 3112 SATA/RAID */ maxio = 15; span = 8*1024; /*FALLTHROUGH*/ case (0x3114<<16)|0x1095: /* SiI 3114 SATA/RAID */ pi = 0x85; break; case (0x0004<<16)|0x1103: /* HighPoint HPT366 */ pi = 0x85; /* * Turn off fast interrupt prediction. */ if((r = pcicfgr8(p, 0x51)) & 0x80) pcicfgw8(p, 0x51, r & ~0x80); if((r = pcicfgr8(p, 0x55)) & 0x80) pcicfgw8(p, 0x55, r & ~0x80); break; case (0x0640<<16)|0x1095: /* CMD 640B */ /* * Bugfix code here... */ break; case (0x7441<<16)|0x1022: /* AMD 768 */ /* * Set: * 0x41 prefetch, postwrite; * 0x43 FIFO configuration 1/2 and 1/2; * 0x44 status register read retry; * 0x46 DMA read and end of sector flush. */ r = pcicfgr8(p, 0x41); pcicfgw8(p, 0x41, r|0xF0); r = pcicfgr8(p, 0x43); pcicfgw8(p, 0x43, (r & 0x90)|0x2A); r = pcicfgr8(p, 0x44); pcicfgw8(p, 0x44, r|0x08); r = pcicfgr8(p, 0x46); pcicfgw8(p, 0x46, (r & 0x0C)|0xF0); /*FALLTHROUGH*/ case (0x7469<<16)|0x1022: /* AMD 3111 */ /* * This can probably be lumped in with the 768 above. */ /*FALLTHROUGH*/ case (0x01BC<<16)|0x10DE: /* nVidia nForce1 */ case (0x0065<<16)|0x10DE: /* nVidia nForce2 */ case (0x0085<<16)|0x10DE: /* nVidia nForce2 MCP */ case (0x00D5<<16)|0x10DE: /* nVidia nForce3 */ case (0x00E5<<16)|0x10DE: /* nVidia nForce3 Pro */ case (0x0035<<16)|0x10DE: /* nVidia nForce3 MCP */ case (0x0053<<16)|0x10DE: /* nVidia nForce4 */ case (0x0054<<16)|0x10DE: /* nVidia nForce4 SATA */ case (0x0055<<16)|0x10DE: /* nVidia nForce4 SATA */ case (0x0266<<16)|0x10DE: /* nVidia nForce4 430 SATA */ case (0x0267<<16)|0x10DE: /* nVidia nForce4 430 SATA */ /* * Ditto, although it may have a different base * address for the registers (0x50?). */ /*FALLTHROUGH*/ case (0x4376<<16)|0x1002: /* ATI Radeon Xpress 200M */ break; case (0x0211<<16)|0x1166: /* ServerWorks IB6566 */ { Pcidev *sb; sb = pcimatch(nil, 0x1166, 0x0200); if(sb == nil) break; r = pcicfgr32(sb, 0x64); r &= ~0x2000; pcicfgw32(sb, 0x64, r); } span = 32*1024; break; case (0x5229<<16)|0x10B9: /* ALi M1543 */ case (0x5288<<16)|0x10B9: /* ALi M5288 SATA */ /*FALLTHROUGH*/ case (0x5513<<16)|0x1039: /* SiS 962 */ case (0x0646<<16)|0x1095: /* CMD 646 */ case (0x0571<<16)|0x1106: /* VIA 82C686 */ case (0x1230<<16)|0x8086: /* 82371FB (PIIX) */ case (0x7010<<16)|0x8086: /* 82371SB (PIIX3) */ case (0x7111<<16)|0x8086: /* 82371[AE]B (PIIX4[E]) */ case (0x2411<<16)|0x8086: /* 82801AA (ICH) */ case (0x2421<<16)|0x8086: /* 82801AB (ICH0) */ case (0x244A<<16)|0x8086: /* 82801BA (ICH2, Mobile) */ case (0x244B<<16)|0x8086: /* 82801BA (ICH2, High-End) */ case (0x248A<<16)|0x8086: /* 82801CA (ICH3, Mobile) */ case (0x248B<<16)|0x8086: /* 82801CA (ICH3, High-End) */ case (0x24CA<<16)|0x8086: /* 82801DBM (ICH4, Mobile) */ case (0x24CB<<16)|0x8086: /* 82801DB (ICH4, High-End) */ case (0x24DB<<16)|0x8086: /* 82801EB (ICH5) */ case (0x266F<<16)|0x8086: /* 82801FB (ICH6) */ case (0x27C4<<16)|0x8086: /* 82801GBM SATA (ICH7) */ case (0x27C5<<16)|0x8086: /* 82801GBM SATA AHCI (ICH7) */ break; } for(channel = 0; channel < 2; channel++){ if(pi & (1<<(2*channel))){ sdev = ataprobe(p->mem[0+2*channel].bar & ~0x01, p->mem[1+2*channel].bar & ~0x01, p->intl); if(sdev == nil) continue; ctlr = sdev->ctlr; if(ispc87415) { ctlr->ienable = pc87415ienable; print("pc87415disable: not yet implemented\n"); } if(head != nil) tail->next = sdev; else head = sdev; tail = sdev; ctlr->tbdf = p->tbdf; } else if((sdev = legacy[channel]) == nil) continue; else ctlr = sdev->ctlr; ctlr->pcidev = p; ctlr->maxio = maxio; ctlr->span = span; if(!(pi & 0x80)) continue; ctlr->bmiba = (p->mem[4].bar & ~0x01) + channel*8; } }if(0){ int port; ISAConf isa; /* * Hack for PCMCIA drives. * This will be tidied once we figure out how the whole * removeable device thing is going to work. */ memset(&isa, 0, sizeof(isa)); isa.port = 0x180; /* change this for your machine */ isa.irq = 11; /* change this for your machine */ port = isa.port+0x0C; channel = pcmspecial("MK2001MPL", &isa); if(channel == -1) channel = pcmspecial("SunDisk", &isa); if(channel == -1){ isa.irq = 10; channel = pcmspecial("CF", &isa); } if(channel == -1){ isa.irq = 10; channel = pcmspecial("OLYMPUS", &isa); } if(channel == -1){ port = isa.port+0x204; channel = pcmspecial("ATA/ATAPI", &isa); } if(channel >= 0 && (sdev = ataprobe(isa.port, port, isa.irq)) != nil){ if(head != nil) tail->next = sdev; else head = sdev; }} return head;}static SDev*atalegacy(int port, int irq){ return ataprobe(port, port+0x204, irq);}static intataenable(SDev* sdev){ Ctlr *ctlr; char name[32]; ctlr = sdev->ctlr; if(ctlr->bmiba){#define ALIGN (4 * 1024) if(ctlr->pcidev != nil) pcisetbme(ctlr->pcidev); ctlr->prdt = mallocalign(Nprd*sizeof(Prd), 4, 0, 4*1024); } snprint(name, sizeof(name), "%s (%s)", sdev->name, sdev->ifc->name); intrenable(ctlr->irq, atainterrupt, ctlr, ctlr->tbdf, name); outb(ctlr->ctlport+Dc, 0); if(ctlr->ienable) ctlr->ienable(ctlr); return 1;}static intatadisable(SDev *sdev){ Ctlr *ctlr; char name[32]; ctlr = sdev->ctlr; outb(ctlr->ctlport+Dc, Nien); /* disable interrupts */ if (ctlr->idisable) ctlr->idisable(ctlr); snprint(name, sizeof(name), "%s (%s)", sdev->name, sdev->ifc->name); intrdisable(ctlr->irq, atainterrupt, ctlr, ctlr->tbdf, name); if (ctlr->bmiba) { if (ctlr->pcidev) pciclrbme(ctlr->pcidev); free(ctlr->prdt); } return 0;}static intatarctl(SDunit* unit, char* p, int l){ int n; Ctlr *ctlr; Drive *drive; if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil) return 0; drive = ctlr->drive[unit->subno]; qlock(drive); n = snprint(p, l, "config %4.4uX capabilities %4.4uX", drive->info[Iconfig], drive->info[Icapabilities]); if(drive->dma) n += snprint(p+n, l-n, " dma %8.8uX dmactl %8.8uX", drive->dma, drive->dmactl); if(drive->rwm) n += snprint(p+n, l-n, " rwm %ud rwmctl %ud", drive->rwm, drive->rwmctl); if(drive->flags&Lba48) n += snprint(p+n, l-n, " lba48always %s", (drive->flags&Lba48always) ? "on" : "off"); n += snprint(p+n, l-n, "\n"); if(drive->sectors){ n += snprint(p+n, l-n, "geometry %lld %d", drive->sectors, drive->secsize); if(drive->pkt == 0) n += snprint(p+n, l-n, " %d %d %d", drive->c, drive->h, drive->s); n += snprint(p+n, l-n, "\n"); } qunlock(drive); return n;}static intatawctl(SDunit* unit, Cmdbuf* cb){ int period; Ctlr *ctlr; Drive *drive; if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil) return 0; drive = ctlr->drive[unit->subno]; qlock(drive); if(waserror()){ qunlock(drive); nexterror(); } /* * Dma and rwm control is passive at the moment, * i.e. it is assumed that the hardware is set up * correctly already either by the BIOS or when * the drive was initially identified. */ if(strcmp(cb->f[0], "dma") == 0){ if(cb->nf != 2 || drive->dma == 0) error(Ebadctl); if(strcmp(cb->f[1], "on") == 0) drive->dmactl = drive->dma; else if(strcmp(cb->f[1], "off") == 0) drive->dmactl = 0; else error(Ebadctl); } else if(strcmp(cb->f[0], "rwm") == 0){ if(cb->nf != 2 || drive->rwm == 0) error(Ebadctl); if(strcmp(cb->f[1], "on") == 0) drive->rwmctl = drive->rwm; else if(strcmp(cb->f[1], "off") == 0) drive->rwmctl = 0; else error(Ebadctl); } else if(strcmp(cb->f[0], "standby") == 0){ switch(cb->nf){ default: error(Ebadctl); case 2: period = strtol(cb->f[1], 0, 0); if(period && (period < 30 || period > 240*5)) error(Ebadctl); period /= 5; break; } if(atastandby(drive, period) != SDok) error(Ebadctl); } else if(strcmp(cb->f[0], "lba48always") == 0){ if(cb->nf != 2 || !(drive->flags&Lba48)) error(Ebadctl); if(strcmp(cb->f[1], "on") == 0) drive->flags |= Lba48always; else if(strcmp(cb->f[1], "off") == 0) drive->flags &= ~Lba48always; else error(Ebadctl); } else error(Ebadctl); qunlock(drive); poperror(); return 0;}SDifc sdataifc = { "ata", /* name */ atapnp, /* pnp */ atalegacy, /* legacy */ ataenable, /* enable */ atadisable, /* disable */ scsiverify, /* verify */ scsionline, /* online */ atario, /* rio */ atarctl, /* rctl */ atawctl, /* wctl */ scsibio, /* bio */ ataprobew, /* probe */ ataclear, /* clear */ atastat, /* stat */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -