1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15:
16:
17: 18: 19: 20: 21:
22:
23: #include "sdisk.h"
24: #include "ata.h"
25:
26: 27: 28:
29: LOCAL void ataDriveInit(DrvTab *drv)
30: {
31: ER er;
32:
33:
34: ataWaitReady(drv);
35:
36:
37: if (drv->MultiCnt >= 2) {
38:
39: er = ataCmd(drv, ATA_SETMULTI, 0, 0, NULL);
40: if (er < E_OK) drv->MultiCnt = 0;
41: }
42:
43:
44: drv->Reset = FALSE;
45: }
46:
47: 48: 49: 50: 51:
52: LOCAL INT ataRWblks(DrvTab *drv, W blk, W cnt, void *buf, W cmd)
53: {
54: ER er;
55: W nblks, nsec, maxlen;
56:
57: #define WRKBUFSZ (64 * 1024)
58:
59:
60:
61: ataSelDrv(drv);
62:
63:
64: if (drv->Reset) ataDriveInit(drv);
65:
66: maxlen = MAX_IOSEC * ATA_SECSZ;
67:
68:
69: maxlen /= drv->SecSize;
70: er = E_OK;
71:
72: for (nblks = 0; cnt > 0; cnt -= nsec) {
73:
74: if ((nsec = cnt) > maxlen) nsec = maxlen;
75:
76: er = ataCmd(drv, cmd, blk, nsec, buf);
77: if (er < E_OK) break;
78:
79: nblks += nsec;
80: blk += nsec;
81: if (buf != NULL) buf += nsec * drv->SecSize;
82: }
83: return (er < E_OK) ? er : nblks;
84: }
85:
86: 87: 88:
89: EXPORT INT ataReadWrite(DrvTab *drv, W blk, W cnt, void *mptr, BOOL write)
90: {
91:
92:
93:
94: return ataRWblks(drv, blk, cnt, mptr, (write) ? ATA_WRITE : ATA_READ);
95: }
96:
97: 98: 99: 100: 101: 102:
103: EXPORT ER ataFormat(DrvTab *drv, DiskFormat *fmt, W dcnt)
104: {
105: ER er;
106: W blk, cnt, nfm;
107:
108: nfm = *fmt;
109: if (nfm != DiskFmt_STD) return E_PAR;
110:
111:
112: blk = drv->s.SUnit[drv->CurSUnit].StartBlock;
113: cnt = drv->s.SUnit[drv->CurSUnit].EndBlock - blk;
114: if (cnt <= 0) return E_PAR;
115:
116:
117: if (drv->CurSUnit == 0) drv->nSUnit = 0;
118:
119:
120: er = ataRWblks(drv, blk, cnt, NULL, ATA_WRITE);
121: return (er >= E_OK) ? E_OK : er;
122: }
123:
124: 125: 126: 127: 128:
129: EXPORT W ataSetXCHS(DrvTab *drv)
130: {
131: W xt, xc, xh, xs;
132:
133:
134: xc = drv->nCyl;
135: xh = drv->nHead;
136: xs = drv->nSec;
137: xt = xc * xh * xs;
138:
139:
140: while (xc > 1024) {xc >>= 1; xh <<= 1;}
141:
142: if (xs > 63) xs = 63;
143: if (xh > 255) xh = 255;
144: if (xt != 0) xc = xt / xh / xs;
145: if (xc > 1024) xc = 1024;
146: if (xc > 0) xc--;
147:
148:
149: drv->nXSec = xs;
150: drv->nXHead = xh;
151: drv->nXCyl = xc;
152: return xc * xh * xs;
153: }
154:
155: 156: 157:
158: EXPORT ER ataIdentify(DrvTab *drv, BOOL check)
159: {
160: ER er;
161: W cyl, head, sec, tsec, n, i;
162: BOOL uselba;
163: UH buf[ATA_SECSZ / sizeof(UH)];
164:
165:
166: for (n = 0; (er = ataSetDrive(drv, -1)) != E_OK; n++) {
167: 168:
169: if (drv->Spec.pccard) break;
170:
171:
172: if (n != 0) goto E_EXIT;
173: ataReset(drv);
174: }
175:
176:
177: if ((er = ataWaitReady(drv)) != E_OK) goto E_EXIT;
178:
179:
180: ataSelDrv(drv);
181:
182:
183: for (;;) {
184: er = ataCmd(drv, ATA_IDENTIFY, 0, 1, (void*)buf);
185: if (er >= E_OK) break;
186: goto E_EXIT;
187: }
188:
189:
190: buf[2] = buf[49];
191: buf[4] = buf[80];
192: buf[5] = CnvLeH(buf[53]) & 0x00FF;
193: buf[7] = buf[54];
194: buf[8] = buf[55];
195: buf[9] = buf[56];
196: buf[20] = buf[60];
197: buf[21] = buf[61];
198: buf[22] = 0;
199: buf[127] = 0;
200: buf[5] = CnvLeH(buf[5]);
201:
202: tsec = 0;
203: drv->DiskFmt = DiskFmt_STD;
204: drv->SecSize = ATA_SECSZ;
205: drv->SecBias = 0;
206:
207:
208: n = CnvLeH(buf[47]) & 0xFF;
209: for (i = 32; i > n; i >>= 1);
210: drv->MultiCnt = (i > 1) ? i : 0;
211: drv->DiskFmt = DiskFmt_STD;
212:
213:
214: drv->MediaOK = TRUE;
215: ataDriveInit(drv);
216:
217: if (check) { 218:
219: if (!drv->MediaOK ||
220: drv->Wprotect != drv->Spec.readonly ||
221: MEMCMP((void*)drv->Ident, (void*)&buf[0], IDENT_DTSZ) != 0) {
222: er = ERR_NOTSAME;
223: goto E_EXIT;
224: }
225: return E_OK;
226: }
227:
228:
229: MEMCPY((void*)drv->Ident, (void*)&buf[0], IDENT_DTSZ);
230:
231:
232: if (!drv->Spec.wlock) drv->Spec.readonly = drv->Wprotect;
233:
234: sec = head = cyl = 0;
235:
236: if (!drv->MediaOK) {
237: tsec = 0 ;
238: uselba = FALSE;
239:
240: } else {
241:
242: cyl = CnvLeH(buf[1]);
243: head = CnvLeH(buf[3]);
244: sec = CnvLeH(buf[6]);
245: tsec = cyl * head * sec;
246:
247: n = CnvLeH(buf[80]);
248: if ((n & ~0x7FFE) == 0 && n >= (1 << 3)) {
249: uselba = TRUE;
250: } else {
251: uselba = (CnvLeH(buf[49]) & 0x200) ? TRUE : FALSE;
252: }
253:
254: if (uselba) {
255: 256:
257: n = CnvLeW(*((UW*)&buf[60]));
258: if (tsec == n || tsec ==
259: (((n >> 16) & 0xFFFF)|((n & 0xFFFF) << 16))) {
260: ;
261: } else if (n < tsec) {
262: uselba = FALSE;
263:
264: } else if (tsec > 1032192) {
265: tsec = n;
266: cyl = n / head / sec;
267: if (cyl > 32767) cyl = 32767;
268:
269: } else if (tsec == 0 && n > 16514064) {
270: tsec = n;
271:
272: cyl = 16383; head = 15; sec = 63;
273: }
274: }
275:
276:
277: if (!uselba && (CnvLeH(buf[53]) & 0x1) != 0) {
278: cyl = CnvLeH(buf[54]);
279: head = CnvLeH(buf[55]);
280: sec = CnvLeH(buf[56]);
281: tsec = cyl * head * sec;
282: }
283: }
284:
285: drv->UseLBA = uselba;
286:
287:
288: drv->nSec = sec;
289: drv->nHead = head;
290: drv->nCyl = cyl;
291:
292:
293: drv->s.SUnit[0].SystemId = DSID_NONE;
294: drv->s.SUnit[0].StartBlock = 0;
295: drv->s.SUnit[0].EndBlock = tsec;
296: drv->s.SUnit[0].OpenCnt = 0;
297:
298:
299: tsec = ataSetXCHS(drv);
300: drv->SetXCHS = FALSE;
301:
302: if (drv->MediaOK) {
303: if (drv->s.SUnit[0].EndBlock <= 0 || tsec <= 0) {
304: er = ERR_NOBLK;
305: goto E_EXIT;
306: }
307: }
308: return E_OK;
309:
310: E_EXIT:
311:
312: ataSetDrive(drv, 0);
313: return er;
314: }
315:
316: 317: 318:
319: EXPORT ER ataSetupPart(DrvTab *drv)
320: {
321: ER er;
322: W i, n, k;
323: UW sblk, eblk;
324: UB buf[ATA_SECSZ];
325: PartTab *part;
326: W xCyl, xSec, xHead;
327:
328:
329:
330:
331:
332: xSec = xHead = 0;
333:
334:
335: if ((er = (*drv->ReadWrite)(drv, 0, 1, (void*)buf, FALSE))
336: < E_OK) return er;
337:
338:
339: if (*((UH*)&buf[OFS_SIGN]) != VALID_SIGN) {
340:
341:
342: MEMSET((void*)buf, 0, SIZE_PARTTAB);
343:
344: } else {
345:
346: MEMMOVE((void*)buf, (void*)&buf[OFS_PART], SIZE_PARTTAB);
347: }
348:
349: part = (PartTab*)buf;
350:
351: 352:
353:
354: for (i = n = 0; i < N_PART; i++) {
355: sblk = part[i].StartBlock;
356: sblk = CnvLeW(sblk);
357: eblk = part[i].BlockCnt;
358: eblk = sblk + CnvLeW(eblk);
359:
360: if (part[i].SysInd == DSID_NONE) {
361: INVALID_PART:
362:
363: if (n < MAX_PART) {
364: drv->s.SUnit[++n].SystemId = DSID_NONE;
365: drv->s.SUnit[n].StartBlock = 0;
366: drv->s.SUnit[n].EndBlock = 0;
367: drv->s.SUnit[n].OpenCnt = 0;
368: }
369: continue;
370: }
371:
372:
373: if (sblk >= eblk || eblk > drv->s.SUnit[0].EndBlock) {
374: goto INVALID_PART;
375: }
376:
377:
378: for (k = n; k > 0; k--) {
379: if (sblk < drv->s.SUnit[k].EndBlock &&
380: eblk > drv->s.SUnit[k].StartBlock) break;
381: }
382: if (k > 0) {
383: goto INVALID_PART;
384: }
385:
386: if (n < MAX_PART) {
387: drv->s.SUnit[++n].SystemId = part[i].SysInd;
388: drv->s.SUnit[n].StartBlock = sblk;
389: drv->s.SUnit[n].EndBlock = eblk;
390: drv->s.SUnit[n].OpenCnt = 0;
391:
392: 393:
394: if (xSec == 0) {
395: xSec = part[i].EndSec & 0x3F;
396: xHead = (UH)part[i].EndHead + 1;
397: xCyl = (UH)part[i].EndCyl + 1 +
398: (((UH)part[i].EndSec & 0xC0) << 2);
399: if ((k = xSec * xHead) != 0) {
400: k = ((eblk % k) != 0) ? 0 : eblk / k;
401: }
402: if (xCyl != 1024 && xCyl != k && xCyl != k - 1)
403: xSec = -1;
404: } else if (xSec > 0) {
405: if (xSec != (part[i].EndSec & 0x3F) ||
406: xHead != ((UH)part[i].EndHead + 1))
407: xSec = -1;
408: }
409: }
410: }
411:
412: drv->nSUnit = n;
413:
414:
415: if (!drv->SetXCHS) {
416: if (xSec > 0) {
417: drv->nXSec = xSec;
418: drv->nXHead = xHead;
419: drv->nXCyl = (drv->nCyl * drv->nHead * drv->nSec) /
420: xHead / xSec - 1;
421: if (drv->nXCyl >= 1024) drv->nXCyl = 1023;
422: }
423: drv->SetXCHS = TRUE;
424: }
425: return E_OK;
426: }
427:
428: 429: 430:
431: EXPORT ER ataDiskInit(DrvTab *drv)
432: {
433: ER er;
434:
435:
436: drv->nSUnit = 0;
437: drv->CurSUnit = 0;
438:
439:
440: drv->SuptMBR = FALSE;
441:
442: if (drv->Aborted) {
443: 444:
445: er = ERR_ABORT;
446:
447: } else if (!drv->MediaOK) {
448: er = ERR_NOMEDIA;
449:
450: } else if (drv->SecSize != ATA_SECSZ) {
451: er = ERR_BLKSZ;
452:
453: } else {
454:
455: er = ataSetupPart(drv);
456: if (er == E_OK) drv->SuptMBR = TRUE;
457: }
458: if (er < E_OK) goto E_EXIT;
459:
460: return E_OK;
461:
462: E_EXIT:
463: return er;
464: }
465:
466: 467: 468:
469: LOCAL void ataOpenClose(DrvTab *drv, W cmd)
470: {
471: switch(cmd) {
472: case DC_OPEN:
473:
474: break;
475:
476: case DC_CLOSE:
477: case DC_CLOSEALL:
478: ataSelDrv(drv);
479: }
480: }
481:
482: 483: 484:
485: EXPORT ER ataMisc(DrvTab *drv, W cmd)
486: {
487: switch(cmd) {
488: case DC_TSKINIT:
489: case DC_TSKTMO:
490: case DC_DRVCHG:
491: break;
492:
493: case DC_OPEN:
494: case DC_CLOSE:
495: case DC_CLOSEALL:
496: ataOpenClose(drv, cmd);
497: break;
498: }
499:
500: drv->ReqTmout = TMO_FEVR;
501: return E_OK;
502: }