7 typedef struct IDE IDE;
8 typedef struct IDEIO IDEIO;
15 u16int rbufrp, rbufwp;
16 u16int wbufrp, wbufwp;
19 u8int err, scratched, wr;
41 int pcyl, phead, psec;
42 int lcyl, lhead, lsec;
67 if((d->flags & IDEPRESENT) != 0){
69 while(d->io.state != IIOIDLE){
74 d->io.rbufrp = d->io.rbufwp = 0;
77 d->stat = IDEDRDY | IDEDSC;
79 d->flags &= IDEPRESENT | IDEKEEPFEAT;
94 s = (d - ide & ~1) + (d->head >> 4 & 1) + ide;
95 irqline(14 + (d - ide)/2, s->irq && (s->ctrl & IDENIEN) == 0);
103 if((d->head & 0x40) != 0)
104 return d->sec | d->cyl << 8 | (d->head & 0xf) << 16;
105 if(d->sec == 0 || d->sec > d->lsec)
108 if(d->cyl >= d->lcyl || he >= d->lhead)
110 return d->sec - 1 + (he + d->cyl * d->lhead) * d->lsec;
115 idegoio(IDE *d, int wr)
121 vmerror("ide%d: access to invalid sector address (access to CHS=(%#.4ux,%#ux,%#.2ux); geometry is (%#.4ux,%#ux,%#.2ux)", d-ide, d->cyl, d->head&0xf, d->sec, d->lcyl, d->lhead, d->lsec);
122 postexc("#bp", NOERRC);
123 d->stat = IDEDRDY | IDEDSC | IDEDRQ | IDEERR;
129 d->stat = IDEDRDY | IDEDRQ | IDEDSC;
130 d->flags |= IDEPIOWRITE;
132 d->stat = IDEDRDY | IDEBUSY | IDEDSC;
133 d->flags |= IDEPIOREAD;
136 while(d->io.state != IIOIDLE)
139 d->io.cnt = (d->cnt - 1 & 0xff) + 1;
142 d->io.state = IIOBUSY;
150 if((d->head & 0x40) != 0){
151 if(d->sec++ == 255 && d->cyl++ == 65535)
152 d->head = d->head + 1 & 0xf | d->head & 0xf0;
154 if(d->sec++ == d->lsec){
156 if((d->head & 0xf) == d->lhead-1){
158 if(d->cyl++ == d->lcyl)
169 if((d->flags & IDEPIOREAD) == 0){
174 if(d->io.rbufwp == (u16int)(d->io.rbufrp + sizeof(d->io.rbuf) - 512))
177 d->stat &= ~(IDEBUSY|IDEDRQ);
178 d->flags &= ~IDEPIOREAD;
179 }else if(d->io.rbufrp == d->io.rbufwp){
181 d->stat = d->stat | IDEERR;
185 d->stat = d->stat & ~IDEDRQ | IDEBUSY;
191 idesecrdone(void *dp)
197 d->stat = d->stat & ~IDEBUSY | IDEDRQ;
211 if((u16int)(d->io.wbufwp - 512) == d->io.wbufrp)
213 if(d->io.wbufwp == (u16int)(d->io.wbufrp + sizeof(d->io.wbuf))){
214 d->stat = d->stat & ~IDEDRQ | IDEBUSY;
217 d->stat = d->stat & ~(IDEDRQ|IDEBUSY);
223 idesecwdone(void *dp)
230 d->stat = d->stat & ~(IDEDRQ|IDEBUSY);
232 d->stat = d->stat & ~IDEBUSY | IDEDRQ;
237 typedef struct Sector Sector;
246 getsector(vlong a, uchar *p)
250 for(s = sectors; s != nil; s = s->next)
252 vmdebug("reading updated sector %lld", a);
253 memmove(p, s->data, 512);
260 putsector(vlong a, uchar *dp)
264 for(p = §ors; s = *p, s != nil; p = &s->next)
266 memmove(s->data, dp, 512);
269 s = emalloc(sizeof(Sector));
271 memmove(s->data, dp, 512);
286 threadsetname("ide");
291 while(io->state == IIOIDLE)
298 for(i = 0; i < n; i++){
300 while(!io->scratched && io->wbufrp == (io->wbufwp & ~511))
306 p = io->wbuf + (io->wbufrp & sizeof(io->wbuf) - 1);
310 if(io->wbufwp == (u16int)(io->wbufrp + sizeof(io->wbuf)))
311 sendnotif(idesecwdone, d);
316 for(i = 0; i < n; i++){
318 while(!io->scratched && io->rbufwp == (u16int)((io->rbufrp & ~511) + sizeof(io->rbuf)))
324 p = io->rbuf + (io->rbufwp & sizeof(io->rbuf) - 1);
327 if(getsector(a+i, p) < 0 && pread(d->fd, p, 512, (a+i)*512) < 512){
328 vmerror("ide%d: read: %r", d - ide);
332 sendnotif(idesecrdone, d);
336 if(io->rbufrp == io->rbufwp)
337 sendnotif(idesecrdone, d);
346 idecmd(IDE *d, u8int cmd)
357 if((d->flags & IDEPRESENT) == 0){
358 vmerror("ide%d: command %#ux issued to absent drive", d-ide, cmd);
362 if(cmd >> 4 == 1 || cmd >> 4 == 7){
363 /* relibrate / seek */
364 d->stat = IDEDRDY|IDEDSC;
369 case 0x20: case 0x21: /* read (pio) */
372 case 0x30: case 0x31: /* write (pio) */
375 case 0x40: case 0x41: /* read verify */
378 d->stat = IDEDRDY|IDEDSC;
381 case 0x90: /* diagnostics */
382 d = (d - ide & ~1) + ide;
385 if((d->flags & IDEPRESENT) != 0){
386 d->stat = IDEDRDY|IDEDSC;
390 case 0x91: /* set translation mode */
391 d->lhead = (d->head & 0xf) + 1;
394 vl = d->size / (d->lhead * d->lsec);
395 d->lcyl = vl >= 65535 ? 65535 : vl;
397 d->stat = IDEDRDY|IDEDSC;
400 case 0xec: /* identify */
402 while(d->io.state != IIOIDLE)
404 p = d->io.rbuf + (d->io.rbufwp & sizeof(d->io.rbuf) - 1);
407 strcpy((char*)p+20, "13149562358579393248");
408 strcpy((char*)p+46, ".2.781 ");
409 sprint((char*)p+54, "%-40s", "jhidks s");
411 PUT16(p, 2, d->pcyl);
412 PUT16(p, 6, d->phead);
413 PUT16(p, 8, d->psec << 9);
415 PUT16(p, 12, d->psec);
419 PUT16(d, 108, d->lcyl);
420 PUT16(d, 110, d->lhead);
421 PUT16(d, 112, d->lsec);
422 PUT32(d, 114, d->lcyl * d->lhead * d->lsec);
424 PUT32(p, 120, d->size >= (u32int)-1 ? -1 : d->size);
427 d->stat = IDEDRDY|IDEDSC|IDEDRQ;
430 case 0xef: /* set feature */
432 case 1: case 0x81: /* enable/disable 8-bit transfers */
433 case 2: case 0x82: /* enable/disable cache */
435 case 0x66: d->flags |= IDEKEEPFEAT; break; /* retain settings */
436 case 0xcc: d->flags &= ~IDEKEEPFEAT; break; /* revert to default on reset */
438 vmerror("ide%d: unknown feature %#ux", d-ide, d->feat);
439 d->stat = IDEDRDY|IDEDSC|IDEERR;
443 d->stat = IDEDRDY|IDEDSC;
446 vmerror("ide%d: unknown command %#ux", d-ide, cmd);
447 d->stat = IDEDRDY|IDEDSC|IDEERR;
453 ideio(int isin, u16int port, u32int val, int sz, void *)
458 d = &ide[2 * ((port & 0x80) == 0)];
459 d += d->head >> 4 & 1;
460 e = (d - ide ^ 1) + ide;
461 if((port|0x80) != 0x1f0){
463 vmerror("ide: access to port %#x with incorrect size %d", port, sz);
466 if(isin && (d->flags & IDEPRESENT) == 0)
468 switch(isin << 16 | port | 0x80){
470 if((d->flags & IDEPIOWRITE) == 0)
473 PUT16(d->io.wbuf, d->io.wbufwp & sizeof(d->io.wbuf) - 1, (u16int)val);
475 if((d->io.wbufwp & 511) == 0)
479 ideio(0, port, val >> 16, 2, nil);
481 case 0x001f1: d->feat = e->feat = val; return 0;
482 case 0x001f2: d->cnt = e->cnt = val; return 0;
483 case 0x001f3: d->sec = e->sec = val; return 0;
484 case 0x001f4: d->cyl = d->cyl & 0xff00 | val; e->cyl = e->cyl & 0xff00 | val; return 0;
485 case 0x001f5: d->cyl = d->cyl & 0xff | val << 8; e->cyl = e->cyl & 0xff | val << 8; return 0;
486 case 0x001f6: d->head = e->head = val | 0xa0; return 0;
487 case 0x001f7: idecmd(d, val); return 0;
489 d->ctrl = e->ctrl = val;
490 if((val & IDESRST) != 0){
499 if(d->io.rbufrp != d->io.rbufwp){
500 rc = GET16(d->io.rbuf, d->io.rbufrp & sizeof(d->io.rbuf)-1);
502 if((d->io.rbufrp & 511) == 0)
508 rc |= ideio(1, port, 0, 2, nil) << 16;
510 case 0x101f1: return d->err;
511 case 0x101f2: return d->cnt;
512 case 0x101f3: return d->sec;
513 case 0x101f4: return (u8int)d->cyl;
514 case 0x101f5: return d->cyl >> 8;
515 case 0x101f6: return d->head;
519 if((d->ctrl & IDESRST) != 0)
522 /* stupid hack to work around different expectations of how DRQ behaves on error */
523 if((d->stat & IDEERR) != 0)
526 default: return iowhine(isin, port, val, sz, "ide");
531 idegeom(vlong vsz, int *cp, int *hp, int *sp)
536 if(vsz >= 63*255*1023){
544 for(s = 63; s >= 1; s--)
545 for(h = 1; h <= 16; h++){
547 if(c >= 1023) c = 1023;
556 return max == 0 ? -1 : 0;
567 werrstr("too many ide disks");
571 d->io.Rendez.l = &d->io;
572 fd = open(fn, ORDWR);
575 d->size = seek(fd, 0, 2) >> 9;
576 if(idegeom(d->size, &d->pcyl, &d->phead, &d->psec) < 0){
577 werrstr("disk file too small");
581 cmos[0x12] |= 0xf << (1-idediskno) * 4;
582 cmos[0x19 + idediskno] = 47;
584 p = ideint13 + idediskno * 12;
585 PUT16(p, 0, 0x80 | idediskno);
586 PUT32(p, 2, d->pcyl);
587 PUT16(p, 6, d->psec);
588 PUT16(p, 8, d->phead);
590 d->flags |= IDEPRESENT;
592 idereset(&ide[idediskno]);
594 proccreate(ideioproc, d, 8192);