/* needs drive->mmctype to be already set */ static int alltrackinfo(Drive *drive, int first, int last) { int i; int32_t nwa; int64_t cap; char *osfx; Mmcaux *aux; Track *track; for(i = first; i <= last; i++) if (mmctrackinfo(drive, i, i - first) < 0) { last = i - 1; if (last < 1) last = 1; break; } track = &drive->track[last - first]; drive->end = track->end; if (drive->mmctype == Mmcbd) { /* allow for lower apparent capacity due to reserved spares */ cap = (int64_t)track->end * track->bs; osfx = drive->laysfx; if (cap >= (int64_t)101*GB) drive->laysfx = "-ql"; /* 128GB nominal */ else if (cap >= (int64_t)51*GB) drive->laysfx = "-tl"; /* 100GB nominal */ else if (cap >= (int64_t)26*GB) drive->laysfx = "-dl"; /* 50GB nominal */ else drive->laysfx = ""; /* 25GB nominal */ if (vflag) fprint(2, "capacity %,lu sectors (%,lld bytes); bd%s\n", track->end, cap, drive->laysfx); if (osfx == nil || strcmp(osfx, drive->laysfx) != 0) drive->relearn = 1; } if (drive->mmctype == Mmcnone) return last; /* no disc */ nwa = computenwa(drive, first, last); aux = drive->aux; if (vflag) fprint(2, "nwa from drive %,ld; computed nwa %,ld\n", aux->mmcnwa, nwa); if (aux->mmcnwa == -1 && nwa == 0) return last; /* probably a blank disc */ if (aux->mmcnwa == -1) fprint(2, "%s: disc is full\n", argv0); /* reconcile differing nwas */ if (aux->mmcnwa != nwa) { fprint(2, "%s: nwa from drive %,ld != computed nwa %,ld\n", argv0, aux->mmcnwa, nwa); fprint(2, "\tbe careful! assuming computed nwa\n"); /* the invisible track may still start at the old nwa. */ // aux->mmcnwa = nwa; } return last; }
/* this gets called a lot from main.c's 9P routines */ static int mmcgettoc(Drive *drive) { int i, n, first, last; uchar resp[1024]; Mmcaux *aux; /* * if someone has swapped the cd, * mmcreadtoc will get ``medium changed'' and the * scsi routines will set nchange and changetime in the * scsi device. */ mmcreadtoc(drive, 0, 0, resp, sizeof(resp)); if(drive->Scsi.changetime == 0) { /* no media present */ drive->mmctype = Mmcnone; drive->ntrack = 0; return 0; } /* * if the disc doesn't appear to be have been changed, and there * is a disc in this drive, there's nothing to do (the common case). */ if(drive->nchange == drive->Scsi.nchange && drive->changetime != 0) return 0; /* * the disc in the drive may have just been changed, * so rescan it and relearn all about it. */ drive->ntrack = 0; drive->nameok = 0; drive->nchange = drive->Scsi.nchange; drive->changetime = drive->Scsi.changetime; drive->writeok = drive->erasable = drive->recordable = drive->blank = 0; drive->erasableset = drive->recordableset = drive->blankset = 0; aux = drive->aux; aux->mmcnwa = 0; aux->nropen = aux->nwopen = 0; aux->ntotby = aux->ntotbk = 0; for(i=0; i<nelem(drive->track); i++){ memset(&drive->track[i].mbeg, 0, sizeof(Msf)); memset(&drive->track[i].mend, 0, sizeof(Msf)); } /* * TODO: set read ahead, MMC-6 §6.37, seems to control caching. */ /* * find number of tracks */ if((n = mmcreadtoc(drive, Msfbit, 0, resp, sizeof(resp))) < 4) { /* * on a blank disc in a cd-rw, use readdiscinfo * to find the track info. */ if(getdiscinfo(drive, resp, sizeof(resp)) < 7) return -1; assert((resp[2] & 0340) == 0); /* data type 0 */ if(resp[4] != 1) print("multi-session disc %d\n", resp[4]); first = resp[3]; last = resp[6]; if(vflag) print("blank disc %d %d\n", first, last); /* the assumption of blankness may be unwarranted */ drive->writeok = drive->blank = drive->blankset = 1; } else { first = resp[2]; last = resp[3]; if(n >= 4+8*(last-first+2)) { /* resp[4 + i*8 + 2] is track # */ /* <=: track[last-first+1] = end */ for(i=0; i<=last-first+1; i++) drive->track[i].mbeg = rdmsf(resp+4+i*8+5); for(i=0; i<last-first+1; i++) drive->track[i].mend = drive->track[i+1].mbeg; } } drive->mmctype = Mmcnone; drive->dvdtype = nil; getdvdstruct(drive); getbdstruct(drive); if (drive->mmctype == Mmcnone) drive->mmctype = Mmccd; /* by default */ if (drive->recordable || drive->erasable) drive->writeok = 1; if (vflag) { fprint(2, "writeok %d", drive->writeok); /* drive->blank is never used and hard to figure out */ // if (drive->blankset) // fprint(2, " blank %d", drive->blank); if (drive->recordableset) fprint(2, " recordable %d", drive->recordable); if (drive->erasableset) fprint(2, " erasable %d", drive->erasable); fprint(2, "\n"); print("first %d last %d\n", first, last); } if(first == 0 && last == 0) first = 1; if(first <= 0 || first >= Maxtrack) { werrstr("first table %d not in range", first); return -1; } if(last <= 0 || last >= Maxtrack) { werrstr("last table %d not in range", last); return -1; } if(drive->cap & Cwrite) /* CDR drives are easy */ for(i = first; i <= last; i++) mmctrackinfo(drive, i, i - first); else /* * otherwise we need to infer endings from the * beginnings of other tracks. */ mmcinfertracks(drive, first, last); drive->firsttrack = first; drive->ntrack = last+1-first; return 0; }