VirtualBox

source: kStuff/hacks/xtide/atalib.c

Last change on this file was 76, checked in by bird, 9 years ago

xtide-utils: ataid fixes. new delay method.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 28.2 KB
Line 
1/* $Id: atalib.c 76 2015-12-28 01:37:00Z bird $ */
2/** @file
3 * Does a little write test.
4 */
5
6/*
7 * Copyright (c) 2015 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with This program. If not, see <http://www.gnu.org/licenses/>
21 *
22 */
23
24
25/*********************************************************************************************************************************
26* Header Files *
27*********************************************************************************************************************************/
28#include <stdarg.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdint.h>
33#include <io.h>
34#include <conio.h>
35#include "atalib.h"
36
37#define STR_TUPLE(a_szStr) a_szStr, sizeof(a_szStr) - 1
38
39
40/*********************************************************************************************************************************
41* Global Variables *
42*********************************************************************************************************************************/
43uint16_t g_uBasePort;
44uint16_t g_uCtrlPort;
45uint8_t g_cPortShift;
46uint8_t g_bDevice;
47uint8_t g_fUseLbaMode = 1;
48uint8_t g_f8BitData;
49uint8_t g_fSupportsSetFeature8BitData;
50uint8_t g_fSupportsSetFeatureWriteCache;
51uint8_t g_fSupportsSetFeatureXferMode;
52int8_t g_fSupportsReadBuffer = -1;
53int8_t g_fSupportsWriteBuffer = -1;
54
55uint16_t g_cHeads;
56uint8_t g_cSectorsPerTrack;
57uint16_t g_cCylinders;
58uint16_t g_cSectorsPerCylinder;
59
60/** The result of the identify command. */
61uint16_t g_awIdentify[256];
62
63
64uint16_t AtaReadPitCounter0(void);
65#pragma aux AtaReadPitCounter0 = \
66 "pushf" \
67 "cli" \
68 "mov al, 4" /* chan0, latch access[, mode 2, 16-bit] */ \
69 "out 43h, al" \
70 "in al, 40h" \
71 "mov ah, al" \
72 "in al, 40h" \
73 "xchg ah, al" \
74 "popf" \
75 value [ax] \
76 modify exact [ax];
77
78uint8_t AtaReadPitCounter0Lsb(void);
79#pragma aux AtaReadPitCounter0Lsb = \
80 "in al, 40h" \
81 value [al] \
82 modify exact [al];
83
84
85void AtaDelayMicroSecs(uint8_t cMicroSecs)
86{
87 /*
88 * ASSUME PIT chan 0 is not in mode 3 and running at 18Hz (reload 64K).
89 *
90 * ASSUME we won't be spending too many microsecs here, so we won't do
91 * an extremely accurate job converting PIT ticks to microseconds. Given
92 * the frequency of 1193182 HZ, that is a period of 838ns, we count each
93 * PIT tick as a microsecond but adding a leap period every 8 rounds
94 * (should've been 6, but 8 is cheaper to calculate).
95 */
96 uint16_t uPrev = AtaReadPitCounter0();
97 uint16_t const cTicksNeeded = cMicroSecs + (cMicroSecs >> 3);
98 uint32_t cTicksElapsed = 0;
99 while (cTicksElapsed < cTicksNeeded)
100 {
101 uint16_t uNow = AtaReadPitCounter0();
102 cTicksElapsed += uPrev - uNow;
103 uPrev = uNow;
104 }
105}
106
107
108#if 0 /* currently implemented as inline assembly */
109void AtaDelayPitTicks(uint8_t cTicks)
110{
111 /*
112 * ASSUME PIT channel 0 is in mode 2.
113 * ASSUME PIT channel 0 is in LSB read mode.
114 * ASSUME PIT channel 0 is reloading a multiple of 256.
115 * ASSUME PIT channel 0 is not currently latched.
116 * ASSUME PIT channel 0 is in binary mode (not BCD).
117 */
118 uint8_t uPrev = AtaReadPitCounter0Lsb();
119 for (;;)
120 {
121 uint8_t uNow = AtaReadPitCounter0Lsb();
122 uint8_t cElapsed = uPrev - uNow;
123 if (cElapsed >= cTicks)
124 break;
125 cElapsed -= cTicks;
126 uPrev = uNow;
127 }
128}
129#endif
130
131
132
133size_t AtaPrintStatus(FILE *pOut, uint8_t bSts)
134{
135 size_t cch = fprintf(pOut, "%#x", bSts);
136 if (bSts & ATA_STS_BUSY) cch += fprintf(pOut, " busy");
137 if (bSts & ATA_STS_DRDY) cch += fprintf(pOut, " drdy");
138 if (bSts & ATA_STS_DF ) cch += fprintf(pOut, " df");
139 if (bSts & ATA_STS_DSC ) cch += fprintf(pOut, " dsc");
140 if (bSts & ATA_STS_DRQ ) cch += fprintf(pOut, " drq");
141 if (bSts & ATA_STS_CORR) cch += fprintf(pOut, " corr");
142 if (bSts & ATA_STS_IDX ) cch += fprintf(pOut, " idx");
143 if (bSts & ATA_STS_ERR ) cch += fprintf(pOut, " err");
144 return cch;
145}
146
147size_t AtaPrintError(FILE *pOut, uint8_t bErr)
148{
149 size_t cch = fprintf(pOut, "%#x", bErr);
150 if (bErr & ATA_ERR_RSVR ) cch += fprintf(pOut, " rsrv");
151 if (bErr & ATA_ERR_UNC ) cch += fprintf(pOut, " unc");
152 if (bErr & ATA_ERR_MC ) cch += fprintf(pOut, " mc");
153 if (bErr & ATA_ERR_IDNF ) cch += fprintf(pOut, " idnf");
154 if (bErr & ATA_ERR_MCR ) cch += fprintf(pOut, " mcr");
155 if (bErr & ATA_ERR_ABRT ) cch += fprintf(pOut, " abrt");
156 if (bErr & ATA_ERR_TKNONF) cch += fprintf(pOut, " tknonf");
157 if (bErr & ATA_ERR_AMNF ) cch += fprintf(pOut, " amnf");
158 return cch;
159}
160
161static int AtaError(uint8_t bSts, const char *pszFormat, ...)
162{
163 va_list va;
164
165 fprintf(stderr, "error: ");
166 va_start(va, pszFormat);
167 vfprintf(stderr, pszFormat, va);
168 va_end(va);
169
170 fprintf(stderr, "\n status=");
171 AtaPrintStatus(stderr, bSts);
172 fprintf(stderr, "\n error= ");
173 AtaPrintError(stderr, inp(ATA_REG_ERROR(g_uBasePort)));
174 fprintf(stderr, "\n");
175
176 return -1;
177}
178
179uint8_t AtaWaitBusy(void)
180{
181 uint32_t cLoops = 0;
182 uint8_t bStatus;
183 do
184 {
185 if ((++cLoops & 0xfffff) == 0)
186 fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
187 bStatus = inp(ATA_REG_STATUS(g_uBasePort));
188 } while ((bStatus & (ATA_STS_BUSY | ATA_STS_ERR)) == ATA_STS_BUSY);
189 return bStatus;
190}
191
192uint8_t AtaWaitBusyDeviceReady(void)
193{
194 uint32_t cLoops = 0;
195 uint8_t bStatus;
196 do
197 {
198 if ((++cLoops & 0xfffff) == 0)
199 fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
200 bStatus = inp(ATA_REG_STATUS(g_uBasePort));
201 } while ( (bStatus & (ATA_STS_BUSY | ATA_STS_DRDY)) != ATA_STS_DRDY
202 && !(bStatus & ATA_STS_ERR) );
203 return bStatus;
204}
205
206uint8_t AtaWaitBusyForData(void)
207{
208 uint32_t cLoops = 0;
209 uint8_t bStatus;
210 do
211 {
212 if ((++cLoops & 0xfffff) == 0)
213 fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
214 bStatus = inp(ATA_REG_STATUS(g_uBasePort));
215 } while ( (bStatus & (ATA_STS_BUSY | ATA_STS_DRQ)) != ATA_STS_DRQ
216 && !(bStatus & ATA_STS_ERR) );
217 return bStatus;
218}
219
220uint8_t AtaSubmitCommandAndWait(uint8_t bCommand)
221{
222
223 outp(ATA_REG_COMMAND(g_uBasePort), bCommand);
224 ATA_DELAY_400NS();
225 return AtaWaitBusy();
226}
227
228uint8_t AtaSubmitCommandAndWaitForData(uint8_t bCommand)
229{
230
231 outp(ATA_REG_COMMAND(g_uBasePort), bCommand);
232 ATA_DELAY_400NS();
233 return AtaWaitBusyForData();
234}
235
236uint8_t AtaSelectDevice(uint8_t bDevice)
237{
238 outp(ATA_REG_DEVICE_SELECT(g_uBasePort), g_bDevice);
239 ATA_DELAY_400NS();
240 return AtaWaitBusyDeviceReady();
241}
242
243void AtaSetSectorAddress(uint32_t iSector, uint8_t bDevice)
244{
245 if (g_fUseLbaMode)
246 {
247 outp(ATA_REG_LBA_0_7(g_uBasePort), iSector & 0xff);
248 outp(ATA_REG_LBA_8_15(g_uBasePort), (iSector >> 8) & 0xff);
249 outp(ATA_REG_LBA_16_23(g_uBasePort), (iSector >> 16) & 0xff);
250 outp(ATA_REG_LBA_24_27_MODE(g_uBasePort), ((iSector >> 24) & 0x0f) | ATA_LBA_MODE | bDevice);
251 }
252 else
253 {
254 uint16_t iCyl = iSector / g_cSectorsPerCylinder;
255 uint16_t iRem = iSector % g_cSectorsPerCylinder;
256 uint8_t iHd = iRem / g_cSectorsPerTrack;
257 uint8_t iSec = iRem % g_cSectorsPerTrack;
258
259 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), iSec);
260 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), iCyl & 0xff);
261 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), iCyl >> 8);
262 outp(ATA_REG_HEAD(g_uBasePort), iHd | bDevice);
263 }
264}
265
266void AtaReadData(void *pvBuf, size_t cb, uint8_t f8BitData)
267{
268 uint16_t uDataPort = ATA_REG_DATA(g_uBasePort);
269 uint16_t *pu16 = (uint16_t *)pvBuf;
270 cb >>= 1;
271
272 if (f8BitData == 1)
273 {
274 while (cb-- > 0)
275 {
276 uint8_t b1 = inp(uDataPort);
277 uint8_t b2 = inp(uDataPort);
278 *pu16++ = b1 | ((uint16_t)b2 << 8);
279 }
280 }
281 else
282 {
283 while (cb-- > 0)
284 *pu16++ = inpw(uDataPort);
285 }
286}
287
288void AtaWriteData(void const *pvBuf, size_t cb, uint8_t f8BitData)
289{
290 uint16_t register uDataPort = ATA_REG_DATA(g_uBasePort);
291 uint16_t const *pu16 = (uint16_t const *)pvBuf;
292
293 cb >>= 1;
294 if (f8BitData == 1)
295 {
296 while (cb-- > 0)
297 {
298 uint16_t register u16 = *pu16++;
299 outp(uDataPort, (uint8_t)u16);
300 outp(uDataPort, (uint8_t)(u16 >> 8));
301 }
302 }
303 else
304 while (cb-- > 0)
305 outpw(uDataPort, *pu16++);
306}
307
308int AtaReadSector(uint32_t iSector, void *pvBuf)
309{
310 uint8_t bSts = AtaWaitBusy();
311 if (bSts & ATA_STS_ERR)
312 return AtaError(bSts, "Prepping for reading sector %lu", iSector);
313
314 bSts = AtaSelectDevice(g_bDevice);
315 if (bSts & ATA_STS_ERR)
316 return AtaError(bSts, "Selecting device for reading sector %lu", iSector);
317
318 outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
319 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
320 AtaSetSectorAddress(iSector, g_bDevice);
321
322 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_SECTORS);
323 if (bSts & ATA_STS_ERR)
324 return AtaError(bSts, "Reading sector %lu", iSector);
325
326 if (!(bSts & ATA_STS_DRQ))
327 return AtaError(bSts, "DRQ not set after reading sector %lu", iSector);
328
329 AtaReadData(pvBuf, 512, g_f8BitData);
330 bSts = inp(ATA_REG_STATUS(g_uBasePort));
331 if (bSts & ATA_STS_DRQ)
332 return AtaError(bSts, "DRQ is still set after reading sector %lu", iSector);
333 if (bSts & ATA_STS_ERR)
334 return AtaError(bSts, "ERR is set after reading sector %lu (#2)", iSector);
335 return 0;
336}
337
338int AtaWriteSector(uint32_t iSector, void const *pvBuf)
339{
340 uint8_t bSts = AtaWaitBusy();
341 if (bSts & ATA_STS_ERR)
342 return AtaError(bSts, "Prepping for writing sector %lu", iSector);
343
344 bSts = AtaSelectDevice(g_bDevice);
345 if (bSts & ATA_STS_ERR)
346 return AtaError(bSts, "Selecting device for writing sector %lu", iSector);
347
348 outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
349 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
350 AtaSetSectorAddress(iSector, g_bDevice);
351
352 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_SECTORS);
353 if (bSts & ATA_STS_ERR)
354 return AtaError(bSts, "writing sector (#1) %lu", iSector);
355 if (!(bSts & ATA_STS_DRQ))
356 return AtaError(bSts, "DRQ not set after writing sector (#1) %lu", iSector);
357
358 AtaWriteData(pvBuf, 512, g_f8BitData);
359 ATA_DELAY_400NS();
360 bSts = AtaWaitBusy();
361 if (bSts & ATA_STS_ERR)
362 return AtaError(bSts, "writing sector (#2) %lu", iSector);
363 if (bSts & ATA_STS_DRQ)
364 return AtaError(bSts, "DRQ is set after writing sector (#2) %lu", iSector);
365
366 return 0;
367}
368
369
370/**
371 * @param pvBuf Pointer to a 512-byte buffer.
372 */
373int AtaReadBuffer(void *pvBuf, uint8_t fExtraChecks)
374{
375 uint8_t bSts;
376
377 if (!g_fSupportsReadBuffer)
378 return -2;
379
380 bSts = AtaWaitBusy();
381 if (bSts & ATA_STS_ERR)
382 return AtaError(bSts, "Prepping for reading buffer");
383
384 bSts = AtaSelectDevice(g_bDevice);
385 if (bSts & ATA_STS_ERR)
386 return AtaError(bSts, "Selecting device for reading buffer");
387
388 outp(ATA_REG_FEATURES(g_uBasePort), 0);
389 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1); /* ignored */
390 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), 0);
391 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), 0);
392 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), 0);
393
394 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_BUFFER);
395 if (bSts & ATA_STS_ERR)
396 return AtaError(bSts, "Reading buffer");
397
398 if (!(bSts & ATA_STS_DRQ))
399 return AtaError(bSts, "DRQ not set after reading buffer");
400
401 if (!fExtraChecks)
402 AtaReadData(pvBuf, 512, g_f8BitData);
403 else
404 AtaReadData(pvBuf, 512, g_f8BitData);
405 bSts = inp(ATA_REG_STATUS(g_uBasePort));
406 if (bSts & ATA_STS_DRQ)
407 return AtaError(bSts, "DRQ is still set after reading buffer");
408 if (bSts & ATA_STS_ERR)
409 return AtaError(bSts, "ERR is set after reading buffer");
410 return 0;
411}
412
413int AtaWriteBuffer(void const *pvBuf, uint8_t fExtraChecks)
414{
415 uint8_t bSts;
416
417 if (!g_fSupportsWriteBuffer)
418 return -2;
419
420 bSts = AtaWaitBusy();
421 if (bSts & ATA_STS_ERR)
422 return AtaError(bSts, "Prepping for writing buffer");
423
424 bSts = AtaSelectDevice(g_bDevice);
425 if (bSts & ATA_STS_ERR)
426 return AtaError(bSts, "Selecting device for writing buffer");
427
428 outp(ATA_REG_FEATURES(g_uBasePort), 0);
429 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1); /* ignored */
430 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), 0);
431 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), 0);
432 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), 0);
433
434 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_BUFFER);
435 if (bSts & ATA_STS_ERR)
436 return AtaError(bSts, "writing buffer (#1)");
437 if (!(bSts & ATA_STS_DRQ))
438 return AtaError(bSts, "DRQ not set after writing buffer (#1)");
439
440 if (!fExtraChecks)
441 AtaWriteData(pvBuf, 512, g_f8BitData);
442 else
443 AtaWriteData(pvBuf, 512, g_f8BitData);
444 ATA_DELAY_400NS();
445 bSts = AtaWaitBusy();
446 if (bSts & ATA_STS_ERR)
447 return AtaError(bSts, "writing buffer (#2)");
448 if (bSts & ATA_STS_DRQ)
449 return AtaError(bSts, "DRQ is set after writing buffer (#2)");
450
451 return 0;
452}
453
454int AtaIdentifyDevice(uint8_t bDevice, void *pvBuf)
455{
456 uint8_t bSts = AtaWaitBusy();
457 if (bSts & ATA_STS_ERR)
458 return AtaError(bSts, "Prepping for device %#x identification", bDevice);
459
460 bSts = AtaSelectDevice(g_bDevice);
461 if (bSts & ATA_STS_ERR)
462 return AtaError(bSts, "Selecting device %#x for identification", bDevice);
463
464 outp(ATA_REG_FEATURES(g_uBasePort), 0);
465 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 0);
466 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), 0);
467 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), 0);
468 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), 0);
469 //outp(ATA_REG_HEAD(g_uBasePort), g_bDevice);
470
471 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_IDENTIFY_DEVICE);
472 if (bSts & ATA_STS_ERR)
473 return AtaError(bSts, "Device %#x identification", bDevice);
474 if (!(bSts & ATA_STS_DRQ))
475 return AtaError(bSts, "DRQ not set after device %#x identification", bDevice);
476
477 AtaReadData(pvBuf, 512, g_f8BitData);
478 return 0;
479}
480
481int AtaSetFeature(uint8_t bDevice, uint8_t bFeature, uint8_t bValue)
482{
483 uint8_t bSts = AtaWaitBusy();
484 if (bSts & ATA_STS_ERR)
485 return AtaError(bSts, "Prepping for setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
486
487 bSts = AtaSelectDevice(g_bDevice);
488 if (bSts & ATA_STS_ERR)
489 return AtaError(bSts, "Selecting device %#x for setting feature %#x (%#x)", bDevice, bFeature, bValue);
490
491 outp(ATA_REG_FEATURES(g_uBasePort), bFeature);
492 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 0);
493 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), bValue);
494 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), 0);
495 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), 0);
496 //outp(ATA_REG_HEAD(g_uBasePort), g_bDevice);
497
498 bSts = AtaSubmitCommandAndWait(ATA_CMD_SET_FEATURES);
499 if (bSts & ATA_STS_ERR)
500 return AtaError(bSts, "Setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
501 if (bSts & ATA_STS_DRQ)
502 return AtaError(bSts, "DRQ is set after setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
503 return 0;
504}
505
506int AtaInitDeviceParams(uint8_t bDevice, uint8_t cSectorsPerTrack, uint8_t cHeads)
507{
508 uint8_t bSts = AtaWaitBusy();
509 if (bSts & ATA_STS_ERR)
510 return AtaError(bSts, "Prepping for device %#x parameter initialization", bDevice);
511
512 bSts = AtaSelectDevice(g_bDevice);
513 if (bSts & ATA_STS_ERR)
514 return AtaError(bSts, "Selecting device for device %#x parameter initialization", bDevice);
515
516 outp(ATA_REG_FEATURES(g_uBasePort), 0);
517 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), cSectorsPerTrack);
518 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), 0);
519 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), 0);
520 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), 0);
521 outp(ATA_REG_HEAD(g_uBasePort), g_bDevice | cHeads);
522
523 bSts = AtaSubmitCommandAndWait(ATA_CMD_INIT_DEVICE_PARAMS);
524 if (bSts & ATA_STS_ERR)
525 return AtaError(bSts, "Device %#x parameter initialization", bDevice);
526 if (bSts & ATA_STS_DRQ)
527 return AtaError(bSts, "DRQ is set after device %#x parameter initialization", bDevice);
528 return 0;
529}
530
531int AtaReset(void)
532{
533 uint8_t bSts;
534
535 /* Set the reset flat. */
536 outp(ATA_REG_CONTROL(g_uBasePort), ATA_CTL_SRST | ATA_CTL_IEN);
537/** @todo This still needs work - it doesn't work when ERR is set. */
538
539 /* Wait for the busy flag response. */
540 ATA_DELAY_5US();
541 while (!(bSts = inp(ATA_REG_STATUS(g_uBasePort))) & ATA_STS_BUSY)
542 ATA_DELAY_400NS();
543
544 /* Clear the reset flag, keeping ints disabled. */
545 outp(ATA_REG_CONTROL(g_uBasePort), ATA_CTL_IEN);
546 ATA_DELAY_400NS();
547
548 /* Wait for the controller to become non-busy. */
549 bSts = AtaWaitBusy();
550 if (bSts & ATA_STS_ERR)
551 return AtaError(bSts, "Software reset failed");
552 return 0;
553}
554
555int AtaReInit(void)
556{
557 int rc;
558
559 /* Reset the controller + devices. */
560 if (AtaReset() != 0)
561 return -1;
562
563 if (g_fSupportsSetFeature8BitData)
564 {
565 if (g_f8BitData == 1 || g_f8BitData == 3)
566 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
567 else if (g_f8BitData == 0)
568 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_8BIT_DATA, 0);
569 else
570 rc = 0;
571 if (rc != 0)
572 return rc;
573 }
574
575 /* Try disable write cache. */
576 if (g_fSupportsSetFeatureWriteCache)
577 {
578 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
579 if (rc != 0)
580 return rc;
581 }
582
583 /* Select PIO mode without IORDY. */
584 if (g_fSupportsSetFeatureXferMode)
585 {
586 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
587 if (rc != 0)
588 return rc;
589 }
590
591 return 0;
592}
593
594int AtaInit(uint16_t uBasePort, uint16_t uCtrlPort, uint8_t cPortShift, uint8_t bDevice, uint8_t f8BitData, uint8_t fReset)
595{
596 int rc;
597 uint8_t bSts, bStsAlt;
598
599 g_uBasePort = uBasePort;
600 g_uCtrlPort = uCtrlPort;
601 g_cPortShift = cPortShift;
602 g_bDevice = bDevice;
603 g_f8BitData = f8BitData;
604 g_fSupportsSetFeature8BitData = 1;
605 g_fSupportsSetFeatureWriteCache = 1;
606 g_fSupportsSetFeatureXferMode = 1;
607
608 /* Check whether the two status registers match up. If they don't we
609 probably don't have a controller at this address. */
610 inp(ATA_REG_STATUS(g_uBasePort));
611 bSts = inp(ATA_REG_STATUS(g_uBasePort));
612 bStsAlt = inp(ATA_REG_ALT_STATUS(g_uCtrlPort));
613 if (bSts != bStsAlt || bSts == 0xff)
614 {
615 fprintf(stderr, "Status register differs or is 0xff\n");
616 fprintf(stderr, " port %#05x status=", ATA_REG_STATUS(g_uBasePort));
617 AtaPrintStatus(stderr, bSts);
618 fprintf(stderr, "\n");
619 fprintf(stderr, " port %#05x alt status=", ATA_REG_ALT_STATUS(g_uCtrlPort));
620 AtaPrintStatus(stderr, bStsAlt);
621 fprintf(stderr, "\n");
622 return -1;
623 }
624 printf("Pre init status=");
625 AtaPrintStatus(stdout, bSts);
626 printf("\n");
627
628 for (;;)
629 {
630 /* Reset the controller + devices. */
631 if (fReset)
632 if (AtaReset() != 0)
633 return -1;
634 fReset = 1;
635
636 /* Enable 8-bit data transfers (just to be on the safe side). */
637 if (g_fSupportsSetFeature8BitData)
638 {
639 if (g_f8BitData == 1 || g_f8BitData == 3)
640 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
641 else if (g_f8BitData == 0)
642 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_8BIT_DATA, 0);
643 else
644 rc = 0;
645 if (rc != 0)
646 {
647 fprintf(stderr,
648 f8BitData
649 ? "warning: ATA_FEATURE_EN_8BIT_DATA failed, assuming not supported. Retrying in 16-bit mode."
650 : "warning: ATA_FEATURE_DI_8BIT_DATA failed, assuming not supported. Retrying.");
651 g_fSupportsSetFeature8BitData = 0;
652 g_f8BitData = 0;
653 continue;
654 }
655 }
656
657 /* Try disable write cache. */
658 if (g_fSupportsSetFeatureWriteCache)
659 {
660 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
661 if (rc != 0)
662 {
663 fprintf(stderr, "warning: ATA_FEATURE_DI_WRITE_CACHE failed, assuming not supported. Retrying.");
664 g_fSupportsSetFeatureWriteCache = 0;
665 continue;
666 }
667 }
668
669 /* Select PIO mode without IORDY. */
670 if (g_fSupportsSetFeatureXferMode)
671 {
672 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
673 if (rc != 0)
674 {
675 fprintf(stderr, "warning: ATA_FEATURE_SET_XFERMODE = DEFAULT_NO_IORDY failed, assuming not supported. Retrying.");
676 g_fSupportsSetFeatureXferMode = 0;
677 continue;
678 }
679 }
680
681 /* Identify the device. */
682 memset(g_awIdentify, 0, sizeof(g_awIdentify));
683 if (AtaIdentifyDevice(g_bDevice, g_awIdentify) != 0)
684 return -1;
685
686 /** @todo this is rather simple... */
687 g_cCylinders = g_awIdentify[1];
688 g_cHeads = g_awIdentify[3];
689 g_cSectorsPerTrack = g_awIdentify[6];
690 g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
691 printf("Device %#x at %#x/%#x: %u cylinders, %u heads, %u sectors, %s data\n",
692 g_bDevice, g_uBasePort, g_uCtrlPort, g_cCylinders, g_cHeads, g_cSectorsPerTrack,
693 g_f8BitData == 1 ? "8-bit" : g_f8BitData == 3 ? "8/16-bit" : g_f8BitData == 0 ? "16-bit(!)" : "16-bit");
694
695 /* Figure 5-9 in SanDisk Manual Rev 12.0: */
696 if ( g_awIdentify[82] != 0 && g_awIdentify[82] != UINT16_C(0xffff)
697 && g_awIdentify[83] != 0 && g_awIdentify[83] != UINT16_C(0xffff)
698 && g_awIdentify[84] != 0 && g_awIdentify[84] != UINT16_C(0xffff)
699 && (g_awIdentify[83] & UINT16_C(0xc000)) == UINT16_C(0x4000)
700 && (g_awIdentify[84] & UINT16_C(0xc000)) == UINT16_C(0x4000) )
701 {
702 g_fSupportsWriteBuffer = (g_awIdentify[82] & UINT16_C(0x1000)) != 0;
703 g_fSupportsReadBuffer = (g_awIdentify[82] & UINT16_C(0x2000)) != 0;
704 }
705 printf(" %s WRITE_BUFFER, %s READ_BUFFER\n",
706 g_fSupportsWriteBuffer == 1 ? "have" : g_fSupportsWriteBuffer == 0 ? "no" : "uncertain",
707 g_fSupportsReadBuffer == 1 ? "have" : g_fSupportsReadBuffer == 0 ? "no" : "uncertain");
708 break;
709 }
710
711 return 0;
712}
713
714int AtaArgMatchWithValue(const char *pszArg, const char *pszMatch, size_t cchMatch,
715 int cArgs, char **papszArgs, int *piArg, const char **ppszValue)
716{
717 if (strncmp(pszArg, pszMatch, cchMatch) == 0)
718 {
719 pszArg += cchMatch;
720 if (!*pszArg)
721 {
722 if (*piArg < cArgs)
723 {
724 *ppszValue = papszArgs[*piArg];
725 *piArg += 1;
726 }
727 else
728 {
729 fprintf(stderr, "syntax error: Option '%s' is missing argument value\n", pszMatch);
730 *ppszValue = NULL;
731 }
732 return 1;
733 }
734
735 if (*pszArg == ':' || *pszArg == '=')
736 {
737 if (!*pszArg)
738 fprintf(stderr, "syntax error: Option '%s' is missing argument value\n", pszMatch);
739 *ppszValue = pszArg;
740 return 1;
741 }
742 }
743
744 return 0;
745}
746
747int AtaInitFromArgv(int iArg, int cArgs, char **papszArgs)
748{
749 uint8_t bDevice = ATA_DEV_MASTER;
750 uint8_t fReset = 0;
751#if 0
752 uint16_t uBasePort = 0x1f0; /* Primary ATA host controller. */
753 uint16_t uCtrlPort = 0x3f0; /* The control block of the primary ATA host controller. */
754 uint8_t cShiftPort = 0;
755 uint8_t f8BitData = 0;
756#else
757 uint16_t uBasePort = 0x300; /* Lo-tech CF-lite. */
758 uint16_t uCtrlPort = 0x310; /* Lo-tech CF-lite. */
759 uint8_t cShiftPort = 1; /* Special Lo-tech CF-lite hack. */
760 uint8_t f8BitData = 1;
761#endif
762
763 while (iArg < cArgs)
764 {
765 const char *pszArg = papszArgs[iArg++];
766 const char *pszValue;
767 int iWhich = 0;
768 if ( (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("--base-port"), cArgs, papszArgs, &iArg, &pszValue))
769 || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("-b"), cArgs, papszArgs, &iArg, &pszValue))
770 || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("--ctrl-port"), cArgs, papszArgs, &iArg, &pszValue) * 2)
771 || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("-c"), cArgs, papszArgs, &iArg, &pszValue) * 2) )
772 {
773 unsigned long uTmp = strtoul(pszValue, NULL, 16);
774 if (uTmp < 16 || uTmp >= 1024)
775 {
776 fprintf(stderr, "error: Invalid port number %#lx for %s (valid range 0x010..0x3ff)\n", uTmp, pszArg);
777 return -1;
778 }
779 if (iWhich == 1)
780 uBasePort = (uint16_t)uTmp;
781 else
782 uCtrlPort = (uint16_t)uTmp;
783 }
784 else if ( AtaArgMatchWithValue(pszArg, STR_TUPLE("--port-shift"), cArgs, papszArgs, &iArg, &pszValue)
785 || AtaArgMatchWithValue(pszArg, STR_TUPLE("-s"), cArgs, papszArgs, &iArg, &pszValue) )
786 {
787 unsigned long uTmp = strtoul(pszValue, NULL, 0);
788 if (uTmp >= 4)
789 {
790 fprintf(stderr, "error: Invalid port shift number %#lx (valid range 0..3)\n", uTmp);
791 return -1;
792 }
793 cShiftPort = (uint8_t)uTmp;
794 }
795 else if ( AtaArgMatchWithValue(pszArg, STR_TUPLE("--device"), cArgs, papszArgs, &iArg, &pszValue)
796 || AtaArgMatchWithValue(pszArg, STR_TUPLE("-d"), cArgs, papszArgs, &iArg, &pszValue) )
797 {
798 unsigned long uTmp = strtoul(pszValue, NULL, 16);
799 if ( uTmp != ATA_DEV_MASTER
800 && uTmp != ATA_DEV_SLAVE)
801 {
802 fprintf(stderr, "error: Invalid device number %#lx; only %#x (master) or %#x (slave) are allowed.\n",
803 uTmp, ATA_DEV_MASTER, ATA_DEV_SLAVE);
804 return -1;
805 }
806 bDevice = (uint8_t)uTmp;
807 }
808 else if ( strcmp(pszArg, "--8-bit-data") == 0
809 || strcmp(pszArg, "-8") == 0)
810 f8BitData = 1;
811 else if ( strcmp(pszArg, "--8-bit-data-plus") == 0
812 || strcmp(pszArg, "-8+") == 0)
813 f8BitData = 3;
814 else if ( strcmp(pszArg, "--16-bit-data") == 0
815 || strcmp(pszArg, "-16") == 0)
816 f8BitData = 0;
817 else if (strcmp(pszArg, "--16-bit-data-no-change") == 0)
818 f8BitData = UINT8_MAX;
819 else if (strcmp(pszArg, "--reset") == 0)
820 fReset = 1;
821 else if (strcmp(pszArg, "--no-reset") == 0)
822 fReset = 0;
823 else if ( strcmp(pszArg, "--ide") == 0
824 || strcmp(pszArg, "--ide-primary") == 0)
825 {
826 /* Normal IDE, primary. */
827 uBasePort = 0x1f0;
828 uCtrlPort = 0x3f0;
829 cShiftPort = 0;
830 f8BitData = UINT8_MAX;
831 }
832 else if (strcmp(pszArg, "--ide-secondary") == 0)
833 {
834 /* Normal IDE, secondary. */
835 uBasePort = 0x170;
836 uCtrlPort = 0x370;
837 cShiftPort = 0;
838 f8BitData = UINT8_MAX;
839 }
840 else if (strcmp(pszArg, "--xt-cf") == 0)
841 {
842 /* Lo-tech CF-lite. */
843 uBasePort = 0x300;
844 uCtrlPort = 0x310;
845 cShiftPort = 1;
846 f8BitData = 1;
847 }
848 }
849
850 return AtaInit(uBasePort, uCtrlPort, cShiftPort, bDevice, f8BitData, fReset);
851}
852
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette