📄 sdata.c
字号:
return SDok; case 0x9E: /* long read capacity */ if((cmd[1] & 0x01) || cmd[2] || cmd[3]) return atasetsense(drive, SDcheck, 0x05, 0x24, 0); if(drive->data == nil || drive->dlen < 8) return atasetsense(drive, SDcheck, 0x05, 0x20, 1); /* * Read capacity returns the LBA of the last sector. */ len = drive->sectors-1; p = drive->data; *p++ = len>>56; *p++ = len>>48; *p++ = len>>40; *p++ = len>>32; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; len = drive->secsize; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p = len; drive->data += 8; return SDok; case 0x28: /* read */ case 0x2A: /* write */ break; case 0x5A: return atamodesense(drive, cmd); } ctlr = drive->ctlr; lba = (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5]; count = (cmd[7]<<8)|cmd[8]; if(drive->data == nil) return SDok; if(drive->dlen < count*drive->secsize) count = drive->dlen/drive->secsize; qlock(ctlr); if(ctlr->maxio) maxio = ctlr->maxio; else if(drive->flags & Lba48) maxio = 65536; else maxio = 256; while(count){ if(count > maxio) drive->count = maxio; else drive->count = count; if(atageniostart(drive, lba)){ ilock(ctlr); atanop(drive, 0); iunlock(ctlr); qunlock(ctlr); return atagenioretry(drive); } while(waserror()) ; tsleep(ctlr, atadone, ctlr, 60*1000); poperror(); if(!ctlr->done){ /* * What should the above timeout be? In * standby and sleep modes it could take as * long as 30 seconds for a drive to respond. * Very hard to get out of this cleanly. */ atadumpstate(drive, cmd, lba, count); ataabort(drive, 1); qunlock(ctlr); return atagenioretry(drive); } if(drive->status & Err){ qunlock(ctlr); return atasetsense(drive, SDcheck, 4, 8, drive->error); } count -= drive->count; lba += drive->count; } qunlock(ctlr); return SDok;}static intatario(SDreq* r){ Ctlr *ctlr; Drive *drive; SDunit *unit; uchar cmd10[10], *cmdp, *p; int clen, reqstatus, status; unit = r->unit; if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil){ r->status = SDtimeout; return SDtimeout; } drive = ctlr->drive[unit->subno]; /* * Most SCSI commands can be passed unchanged except for * the padding on the end. The few which require munging * are not used internally. Mode select/sense(6) could be * converted to the 10-byte form but it's not worth the * effort. Read/write(6) are easy. */ switch(r->cmd[0]){ case 0x08: /* read */ case 0x0A: /* write */ cmdp = cmd10; memset(cmdp, 0, sizeof(cmd10)); cmdp[0] = r->cmd[0]|0x20; cmdp[1] = r->cmd[1] & 0xE0; cmdp[5] = r->cmd[3]; cmdp[4] = r->cmd[2]; cmdp[3] = r->cmd[1] & 0x0F; cmdp[8] = r->cmd[4]; clen = sizeof(cmd10); break; default: cmdp = r->cmd; clen = r->clen; break; } qlock(drive);retry: drive->write = r->write; drive->data = r->data; drive->dlen = r->dlen; drive->status = 0; drive->error = 0; if(drive->pkt) status = atapktio(drive, cmdp, clen); else status = atagenio(drive, cmdp, clen); if(status == SDretry){ if(DEBUG & DbgDEBUG) print("%s: retry: dma %8.8uX rwm %4.4uX\n", unit->name, drive->dmactl, drive->rwmctl); goto retry; } if(status == SDok){ atasetsense(drive, SDok, 0, 0, 0); if(drive->data){ p = r->data; r->rlen = drive->data - p; } else r->rlen = 0; } else if(status == SDcheck && !(r->flags & SDnosense)){ drive->write = 0; memset(cmd10, 0, sizeof(cmd10)); 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; static int done; if (done) return nil; done = 1; legacy[0] = legacy[1] = head = tail = nil; if(sdev = ataprobe(Ctlr0cmd, Ctlr0ctl, IrqATA0)){ head = tail = sdev; legacy[0] = sdev; } if(sdev = ataprobe(Ctlr1cmd, Ctlr1ctl, 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; /* * file server special: ccru is a short in the FS kernel, * thus the cast to uchar. */ switch ((uchar)p->ccru) { case 1: case 4: case 0x80: break; default: 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); 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 */ /* * 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 (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) */ 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; } } return head;}static SDev*atalegacy(int port, int irq){ return ataprobe(port, port+Ctl2cmd, irq);}static SDev*ataid(SDev* sdev){ int i; Ctlr *ctlr; char name[32]; /* * Legacy controllers are always 'C' and 'D' and if * they exist and have drives will be first in the list. * If there are no active legacy controllers, native * controllers start at 'C'. */ if(sdev == nil) return nil; ctlr = sdev->ctlr; if(ctlr->cmdport == Ctlr0cmd || ctlr->cmdport == Ctlr1cmd) i = 2; else i = 0; while(sdev){ if(sdev->ifc == &sdataifc){ ctlr = sdev->ctlr; if(ctlr->cmdport == Ctlr0cmd) sdev->idno = 'C'; else if(ctlr->cmdport == Ctlr1cmd) sdev->idno = 'D'; else{ sdev->idno = 'C'+i; i++; } snprint(name, sizeof(name), "sd%c", sdev->idno); kstrdup(&sdev->name, name); } sdev = sdev->next; } return nil;}static int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -