📄 devsd.c
字号:
return r; } i -= Qpart; if(unit->part == nil || i >= unit->npart){ qunlock(&unit->ctl); decref(&sdev->r); break; } pp = &unit->part[i]; if(!pp->valid){ qunlock(&unit->ctl); decref(&sdev->r); return 0; } l = (pp->end - pp->start) * unit->secsize; mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart), unit->vers+pp->vers, QTFILE); if(emptystr(pp->perm.user)) kstrdup(&pp->perm.user, eve); devdir(c, q, pp->perm.name, l, pp->perm.user, pp->perm.perm, dp); qunlock(&unit->ctl); decref(&sdev->r); return 1; case Qraw: case Qctl: case Qpart: if((sdev = sdgetdev(DEV(c->qid))) == nil){ devdir(c, q, "unavailable", 0, eve, 0, dp); return 1; } unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->ctl); r = sd2gen(c, TYPE(c->qid), dp); qunlock(&unit->ctl); decref(&sdev->r); return r; case Qtopctl: return sd1gen(c, TYPE(c->qid), dp); default: break; } return -1;}static Chan*sdattach(char* spec){ Chan *c; char *p; SDev *sdev; int idno, subno; if(*spec == '\0'){ c = devattach(sddevtab.dc, spec); mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR); return c; } if(spec[0] != 's' || spec[1] != 'd') error(Ebadspec); idno = spec[2]; subno = strtol(&spec[3], &p, 0); if(p == &spec[3]) error(Ebadspec); if((sdev=sdgetdev(idno)) == nil) error(Enonexist); if(sdgetunit(sdev, subno) == nil){ decref(&sdev->r); error(Enonexist); } c = devattach(sddevtab.dc, spec); mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR); c->dev = (sdev->idno << UnitLOG) + subno; decref(&sdev->r); return c;}static Walkqid*sdwalk(Chan* c, Chan* nc, char** name, int nname){ return devwalk(c, nc, name, nname, nil, 0, sdgen);}static intsdstat(Chan* c, uchar* db, int n){ return devstat(c, db, n, nil, 0, sdgen);}static Chan*sdopen(Chan* c, int omode){ SDpart *pp; SDunit *unit; SDev *sdev; uchar tp; c = devopen(c, omode, 0, 0, sdgen); if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart) return c; sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; switch(TYPE(c->qid)){ case Qctl: c->qid.vers = unit->vers; break; case Qraw: c->qid.vers = unit->vers; if(tas(&unit->rawinuse) != 0){ c->flag &= ~COPEN; decref(&sdev->r); error(Einuse); } unit->state = Rawcmd; break; case Qpart: qlock(&unit->ctl); if(waserror()){ qunlock(&unit->ctl); c->flag &= ~COPEN; decref(&sdev->r); nexterror(); } pp = &unit->part[PART(c->qid)]; c->qid.vers = unit->vers+pp->vers; qunlock(&unit->ctl); poperror(); break; } decref(&sdev->r); return c;}static voidsdclose(Chan* c){ SDunit *unit; SDev *sdev; if(c->qid.type & QTDIR) return; if(!(c->flag & COPEN)) return; switch(TYPE(c->qid)){ default: break; case Qraw: sdev = sdgetdev(DEV(c->qid)); if(sdev){ unit = sdev->unit[UNIT(c->qid)]; unit->rawinuse = 0; decref(&sdev->r); } break; }}static longsdbio(Chan* c, int write, char* a, long len, uvlong off){ int nchange; long l; uchar *b; SDpart *pp; SDunit *unit; SDev *sdev; ulong max, nb, offset; uvlong bno; sdev = sdgetdev(DEV(c->qid)); if(sdev == nil){ decref(&sdev->r); error(Enonexist); } unit = sdev->unit[UNIT(c->qid)]; if(unit == nil) error(Enonexist); nchange = 0; qlock(&unit->ctl); while(waserror()){ /* notification of media change; go around again */ if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){ sdinitpart(unit); continue; } /* other errors; give up */ qunlock(&unit->ctl); decref(&sdev->r); nexterror(); } pp = &unit->part[PART(c->qid)]; if(unit->vers+pp->vers != c->qid.vers) error(Echange); /* * Check the request is within bounds. * Removeable drives are locked throughout the I/O * in case the media changes unexpectedly. * Non-removeable drives are not locked during the I/O * to allow the hardware to optimise if it can; this is * a little fast and loose. * It's assumed that non-removeable media parameters * (sectors, secsize) can't change once the drive has * been brought online. */ bno = (off/unit->secsize) + pp->start; nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno; max = SDmaxio/unit->secsize; if(nb > max) nb = max; if(bno+nb > pp->end) nb = pp->end - bno; if(bno >= pp->end || nb == 0){ if(write) error(Eio); qunlock(&unit->ctl); decref(&sdev->r); poperror(); return 0; } if(!(unit->inquiry[1] & 0x80)){ qunlock(&unit->ctl); poperror(); } b = sdmalloc(nb*unit->secsize); if(b == nil) error(Enomem); if(waserror()){ sdfree(b); if(!(unit->inquiry[1] & 0x80)) decref(&sdev->r); /* gadverdamme! */ nexterror(); } offset = off%unit->secsize; if(offset+len > nb*unit->secsize) len = nb*unit->secsize - offset; if(write){ if(offset || (len%unit->secsize)){ l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno); if(l < 0) error(Eio); if(l < (nb*unit->secsize)){ nb = l/unit->secsize; l = nb*unit->secsize - offset; if(len > l) len = l; } } memmove(b+offset, a, len); l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno); if(l < 0) error(Eio); if(l < offset) len = 0; else if(len > l - offset) len = l - offset; } else{ l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno); if(l < 0) error(Eio); if(l < offset) len = 0; else if(len > l - offset) len = l - offset; memmove(a, b+offset, len); } sdfree(b); poperror(); if(unit->inquiry[1] & 0x80){ qunlock(&unit->ctl); poperror(); } decref(&sdev->r); return len;}static longsdrio(SDreq* r, void* a, long n){ void *data; if(n >= SDmaxio || n < 0) error(Etoobig); data = nil; if(n){ if((data = sdmalloc(n)) == nil) error(Enomem); if(r->write) memmove(data, a, n); } r->data = data; r->dlen = n; if(waserror()){ sdfree(data); r->data = nil; nexterror(); } if(r->unit->dev->ifc->rio(r) != SDok) error(Eio); if(!r->write && r->rlen > 0) memmove(a, data, r->rlen); sdfree(data); r->data = nil; poperror(); return r->rlen;}/* * SCSI simulation for non-SCSI devices */intsdsetsense(SDreq *r, int status, int key, int asc, int ascq){ int len; SDunit *unit; unit = r->unit; unit->sense[2] = key; unit->sense[12] = asc; unit->sense[13] = ascq; r->status = status; if(status == SDcheck && !(r->flags & SDnosense)){ /* request sense case from sdfakescsi */ len = sizeof unit->sense; if(len > sizeof r->sense-1) len = sizeof r->sense-1; memmove(r->sense, unit->sense, len); unit->sense[2] = 0; unit->sense[12] = 0; unit->sense[13] = 0; r->flags |= SDvalidsense; return SDok; } return status;}intsdmodesense(SDreq *r, uchar *cmd, void *info, int ilen){ int len; uchar *data; /* * Fake a vendor-specific request with page code 0, * return the drive info. */ if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F) return sdsetsense(r, SDcheck, 0x05, 0x24, 0); len = (cmd[7]<<8)|cmd[8]; if(len == 0) return SDok; if(len < 8+ilen) return sdsetsense(r, SDcheck, 0x05, 0x1A, 0); if(r->data == nil || r->dlen < len) return sdsetsense(r, SDcheck, 0x05, 0x20, 1); data = r->data; memset(data, 0, 8); data[0] = ilen>>8; data[1] = ilen; if(ilen) memmove(data+8, info, ilen); r->rlen = 8+ilen; return sdsetsense(r, SDok, 0, 0, 0);}intsdfakescsi(SDreq *r, void *info, int ilen){ uchar *cmd, *p; uvlong len; SDunit *unit; cmd = r->cmd; r->rlen = 0; unit = r->unit; /* * Rewrite read(6)/write(6) into read(10)/write(10). */ switch(cmd[0]){ case 0x08: /* read */ case 0x0A: /* write */ cmd[9] = 0; cmd[8] = cmd[4]; cmd[7] = 0; cmd[6] = 0; cmd[5] = cmd[3]; cmd[4] = cmd[2]; cmd[3] = cmd[1] & 0x0F; cmd[2] = 0; cmd[1] &= 0xE0; cmd[0] |= 0x20; break; } /* * Map SCSI commands into ATA commands for discs. * Fail any command with a LUN except INQUIRY which * will return 'logical unit not supported'. */ if((cmd[1]>>5) && cmd[0] != 0x12) return sdsetsense(r, SDcheck, 0x05, 0x25, 0); switch(cmd[0]){ default: return sdsetsense(r, SDcheck, 0x05, 0x20, 0); case 0x00: /* test unit ready */ return sdsetsense(r, SDok, 0, 0, 0); case 0x03: /* request sense */ if(cmd[4] < sizeof unit->sense) len = cmd[4]; else len = sizeof unit->sense; if(r->data && r->dlen >= len){ memmove(r->data, unit->sense, len); r->rlen = len; } return sdsetsense(r, SDok, 0, 0, 0); case 0x12: /* inquiry */ if(cmd[4] < sizeof unit->inquiry) len = cmd[4]; else len = sizeof unit->inquiry; if(r->data && r->dlen >= len){ memmove(r->data, unit->inquiry, len); r->rlen = len; } return sdsetsense(r, SDok, 0, 0, 0); case 0x1B: /* start/stop unit */ /* * nop for now, can use power management later. */ return sdsetsense(r, SDok, 0, 0, 0); case 0x25: /* read capacity */ if((cmd[1] & 0x01) || cmd[2] || cmd[3]) return sdsetsense(r, SDcheck, 0x05, 0x24, 0); if(r->data == nil || r->dlen < 8) return sdsetsense(r, SDcheck, 0x05, 0x20, 1); /* * Read capacity returns the LBA of the last sector. */ len = unit->sectors - 1; p = r->data; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; len = 512; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; r->rlen = p - (uchar*)r->data; return sdsetsense(r, SDok, 0, 0, 0); case 0x9E: /* long read capacity */ if((cmd[1] & 0x01) || cmd[2] || cmd[3]) return sdsetsense(r, SDcheck, 0x05, 0x24, 0); if(r->data == nil || r->dlen < 8) return sdsetsense(r, SDcheck, 0x05, 0x20, 1); /* * Read capcity returns the LBA of the last sector. */ len = unit->sectors - 1; p = r->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 = 512; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; r->rlen = p - (uchar*)r->data; return sdsetsense(r, SDok, 0, 0, 0); case 0x5A: /* mode sense */ return sdmodesense(r, cmd, info, ilen); case 0x28: /* read */ case 0x2A: /* write */ case 0x88: /* read16 */ case 0x8a: /* write16 */ return SDnostatus; }}static longsdread(Chan *c, void *a, long n, vlong off){ char *p, *e, *buf; SDpart *pp; SDunit *unit; SDev *sdev; ulong offset; int i, l, m, status; offset = off; switch(TYPE(c->qid)){ default: error(Eperm); case Qtopctl: m = 64*1024; /* room for register dumps */ p = buf = malloc(m); assert(p); e = p + m; qlock(&devslock); for(i = 0; i < nelem(devs); i++){ sdev = devs[i]; if(sdev && sdev->ifc->rtopctl) p = sdev->ifc->rtopctl(sdev, p, e); } qunlock(&devslock); n = readstr(off, a, n, buf); free(buf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -