📄 sdata.c
字号:
} return SDok; case 0x12: /* inquiry */ if(cmd[4] < sizeof(drive->inquiry)) len = cmd[4]; else len = sizeof(drive->inquiry); if(drive->data && drive->dlen >= len){ memmove(drive->data, drive->inquiry, len); drive->data += len; } return SDok; case 0x1B: /* start/stop unit */ /* * NOP for now, can use the power management feature * set later. */ return SDok; case 0x25: /* 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>>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); while(count){ if(count > 256) drive->count = 256; else drive->count = count; drive->limit += drive->count*drive->secsize; if(atageniostart(drive, lba)){ qunlock(ctlr); return atasetsense(drive, SDcheck, 2, 5, 0); } lba += drive->count; tsleep(ctlr, atageniodone, ctlr, 10*1000); 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. * Let's see if it ever happens first... */ panic("atagenio"); } if(drive->status & Err){ qunlock(ctlr); return atasetsense(drive, SDcheck, 4, 8, drive->error); } if(drive->data != drive->limit) print("atagenio: %d != %d\n", (int)drive->data, (int)drive->limit); count -= 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); drive->write = r->write; drive->data = r->data; drive->dlen = r->dlen; drive->limit = r->data; drive->status = 0; drive->error = 0; if(drive->pkt) status = atapktio(drive, cmdp, clen); else status = atagenio(drive, cmdp, clen); 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->limit = r->sense; 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); return; } cmdport = ctlr->cmdport; status = inb(cmdport+Status); if((drive = ctlr->curdrive) == nil){ iunlock(ctlr); 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: panic("atadmainterrupt"); 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; int channel, ispc87415, pi; SDev *legacy[2], *sdev, *head, *tail; 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). */ if(p->ccrb != 0x01 || (p->ccru != 0x01 && p->ccru != 0x80)) continue; pi = p->ccrp; ispc87415 = 0; 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 (0x4D38<<16)|0x105A: /* Promise PDC20262 */ pi = 0x85; /*FALLTHROUGH*/ case (0x1230<<16)|0x8086: /* 82371FB (PIIX) */ case (0x7010<<16)|0x8086: /* 82371SB (PIIX3) */ case (0x7111<<16)|0x8086: /* 82371[AE]B (PIIX4[E]) */ case (0x0646<<16)|0x1095: /* CMD 646 */ case (0x0571<<16)|0x1106: /* VIA 82C686 */ 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; if(head != nil) tail->next = sdev; else head = sdev; tail = sdev; ctlr->pcidev = p; } } } return head;}static SDev*atalegacy(int port, int irq){ return ataprobe(port, port+0x204, irq);}static SDev*ataid(SDev* sdev){ int i; Ctlr *ctlr; /* * 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'. */ ctlr = sdev->ctlr; if(ctlr->cmdport == 0x1F0 || ctlr->cmdport == 0x170) i = 2; else i = 0; while(sdev){ if(sdev->ifc != &sdataifc) continue; ctlr = sdev->ctlr; if(ctlr->cmdport == 0x1F0) sdev->idno = 'C'; else if(ctlr->cmdport == 0x170) sdev->idno = 'D'; else{ sdev->idno = 'C'+i; i++; } sdev = sdev->next; } return nil;}static intataenable(SDev* sdev){ Ctlr *ctlr; ctlr = sdev->ctlr; setvec(ctlr->irq+VectorPIC, atainterrupt, ctlr); outb(ctlr->ctlport+Dc, 0); if(ctlr->ienable) ctlr->ienable(ctlr); return 1;}SDifc sdataifc = { "ata", /* name */ atapnp, /* pnp */ atalegacy, /* legacy */ ataid, /* id */ ataenable, /* enable */ nil, /* disable */ scsiverify, /* verify */ scsionline, /* online */ atario, /* rio */ nil, /* rctl */ nil, /* wctl */ scsibio, /* bio */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -