Changeset 73 for hacks/xtide/atalib.c
- Timestamp:
- Dec 20, 2015, 10:17:34 PM (10 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
hacks/xtide/atalib.c
r72 r73 33 33 #include <io.h> 34 34 #include <conio.h> 35 36 /********************************************************************************************************************************* 37 * Structures and Typedefs * 38 *********************************************************************************************************************************/ 39 typedef struct REGS16 40 { 41 uint16_t ax; /**< 0 */ 42 uint16_t cx; /**< 2 */ 43 uint16_t dx; /**< 4 */ 44 uint16_t si; /**< 6 */ 45 uint16_t di; /**< 8 */ 46 uint16_t es; /**< 10 */ 47 uint16_t efl; /**< 12 */ 48 uint16_t ds; /**< 14 */ 49 uint16_t bx; /**< 16 */ 50 } REGS16; 51 52 #define X86_EFL_CF 1 53 54 /* The necessary I/O ports, indexed by "bus". */ 55 #define ATA_PORT_SHIFT 1 /* For XT-CF trick */ 56 #define ATA_REG_DATA(x) (x) 57 #define ATA_REG_FEATURES(x) ((x) + (1 << ATA_PORT_SHIFT)) 58 #define ATA_REG_SECTOR_COUNT(x) ((x) + (2 << ATA_PORT_SHIFT)) 59 60 #define ATA_REG_SECTOR_NUMBER(x) ((x) + (3 << ATA_PORT_SHIFT)) 61 #define ATA_REG_CYLINDER_LOW(x) ((x) + (4 << ATA_PORT_SHIFT)) 62 #define ATA_REG_CYLINDER_HIGH(x) ((x) + (5 << ATA_PORT_SHIFT)) 63 #define ATA_REG_HEAD(x) ((x) + (6 << ATA_PORT_SHIFT)) 64 65 #define ATA_REG_LBA_0_7(x) ((x) + (3 << ATA_PORT_SHIFT)) 66 #define ATA_REG_LBA_8_15(x) ((x) + (4 << ATA_PORT_SHIFT)) 67 #define ATA_REG_LBA_16_23(x) ((x) + (5 << ATA_PORT_SHIFT)) 68 #define ATA_REG_LBA_24_27_MODE(x) ((x) + (6 << ATA_PORT_SHIFT)) 69 #define ATA_LBA_MODE UINT8_C(0x40) /**< Selects LBA mode in ATA_REG_LBA_24_27_MODE. */ 70 71 #define ATA_REG_DEVICE_SELECT(x) ((x) + (6 << ATA_PORT_SHIFT)) 72 #define ATA_REG_COMMAND(x) ((x) + (7 << ATA_PORT_SHIFT)) 73 74 75 #define ATA_REG_STATUS(x) ATA_REG_COMMAND(x) 76 #define ATA_REG_ALT_STATUS(x) ATA_REG_CONTROL(x) 77 #define ATA_STS_BUSY UINT8_C(0x80) 78 #define ATA_STS_DRDY UINT8_C(0x40) 79 #define ATA_STS_DF UINT8_C(0x20) 80 #define ATA_STS_DSC UINT8_C(0x10) 81 #define ATA_STS_DRQ UINT8_C(0x08) 82 #define ATA_STS_CORR UINT8_C(0x04) 83 #define ATA_STS_IDX UINT8_C(0x02) 84 #define ATA_STS_ERR UINT8_C(0x01) 85 86 #define ATA_REG_ERROR(x) ATA_REG_FEATURES(x) 87 #define ATA_ERR_RSVR UINT8_C(0x80) 88 #define ATA_ERR_UNC UINT8_C(0x40) 89 #define ATA_ERR_MC UINT8_C(0x20) 90 #define ATA_ERR_IDNF UINT8_C(0x10) 91 #define ATA_ERR_MCR UINT8_C(0x08) 92 #define ATA_ERR_ABRT UINT8_C(0x04) 93 #define ATA_ERR_TKNONF UINT8_C(0x02) 94 #define ATA_ERR_AMNF UINT8_C(0x01) 95 96 #define ATA_REG_CONTROL(x) ((x) + (14 << ATA_PORT_SHIFT)) 97 #define ATA_CTL_IEN UINT8_C(0x02) /**< Interrupt enable. */ 98 #define ATA_CTL_SRST UINT8_C(0x04) /**< software reset */ 99 100 #define ATA_CMD_NOP UINT8_C(0x00) 101 #define ATA_CMD_READ_SECTORS UINT8_C(0x20) 102 #define ATA_CMD_READ_SECTORS_NR UINT8_C(0x21) 103 #define ATA_CMD_READ_LONG UINT8_C(0x22) 104 #define ATA_CMD_READ_LONG_NR UINT8_C(0x23) 105 #define ATA_CMD_WRITE_SECTORS UINT8_C(0x30) 106 #define ATA_CMD_WRITE_SECTORS_NR UINT8_C(0x31) 107 #define ATA_CMD_WRITE_LONG UINT8_C(0x32) 108 #define ATA_CMD_WRITE_LONG_NR UINT8_C(0x33) 109 #define ATA_CMD_INIT_DEVICE_PARAMS UINT8_C(0x91) 110 #define ATA_CMD_SET_FEATURES UINT8_C(0xef) 111 #define ATA_CMD_IDENTIFY_DEVICE UINT8_C(0xec) 112 113 114 #define ATA_DEV_MASTER UINT8_C(0x00) /**< Master device selection bit value. */ 115 #define ATA_DEV_SLAVE UINT8_C(0x10) /**< Slave device selection bit value. */ 116 117 #define ATA_FEATURE_EN_8BIT_DATA UINT8_C(0x01) 118 #define ATA_FEATURE_DI_8BIT_DATA UINT8_C(0x81) 119 #define ATA_FEATURE_EN_WRITE_CACHE UINT8_C(0x02) 120 #define ATA_FEATURE_DI_WRITE_CACHE UINT8_C(0x82) 121 #define ATA_FEATURE_SET_XFERMODE UINT8_C(0x03) 122 #define ATA_FV_XFERMODE_PIO_MODE_DEFAULT UINT8_C(0x00) 123 #define ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY UINT8_C(0x01) 124 #define ATA_FV_XFERMODE_PIO_MODE_XXX_FLAG UINT8_C(0x08) 125 #define ATA_FV_XFERMODE_SWDMA_MODE_XXX_FLAG UINT8_C(0x10) 126 #define ATA_FV_XFERMODE_MWDMA_MODE_XXX_FLAG UINT8_C(0x20) 127 128 /** Delay a bit by reading PIC mask. Should take 4-5 bus cycles, 129 * and thus be more than the required 400ns delay on old computers. */ 130 #define ATA_DELAY_400NS() do { inp(0x21); } while (0) 131 35 #include "atalib.h" 36 37 #define STR_TUPLE(a_szStr) a_szStr, sizeof(a_szStr) - 1 132 38 133 39 … … 135 41 * Global Variables * 136 42 *********************************************************************************************************************************/ 137 uint16_t g_uBasePort = 0x300; 138 uint16_t g_uPortShift = 1; 43 uint16_t g_uBasePort; 44 uint16_t g_uCtrlPort; 45 uint16_t g_uPortShift; 46 uint8_t g_bDevice; 139 47 uint8_t g_fUseLbaMode = 1; 140 uint8_t g_f8BitData = 1; 141 uint8_t g_bDevice = ATA_DEV_MASTER; 142 uint8_t g_bDrv = 0x80; 143 48 uint8_t g_f8BitData; 49 uint8_t g_fSupportsSetFeature8BitData; 50 uint8_t g_fSupportsSetFeatureWriteCache; 51 uint8_t g_fSupportsSetFeatureXferMode; 52 int8_t g_fSupportsReadBuffer = -1; 53 int8_t g_fSupportsWriteBuffer = -1; 144 54 145 55 uint16_t g_cHeads; … … 307 217 } 308 218 309 ////static uint8_t AtaWaitForDataRequest(size_t cbLeft)310 ////{311 //// uint16_t uAltStsPort = ATA_REG_ALT_STATUS(g_uBasePort);312 //// uint8_t bStsFirst = inp(uAltStsPort);313 //// uint8_t bSts = bStsFirst;314 //// uint32_t cLoops = 0;315 //// do316 //// {317 //// if (++cLoops & 0xffff)318 //// {319 ////static unsigned x = 0;320 ////if (x < 16)321 ////{322 //// printf("AtaWaitForDataRequest: bFirst=%#x bLast=%#x cbLeft=%#x\n", bStsFirst, bSts, cbLeft);323 //// x++;324 ////}325 //// break;326 //// }327 //// bSts = inp(uAltStsPort);328 //// } while (!(bSts & (ATA_STS_DRQ | ATA_STS_ERR)));329 //// return bSts;330 ////}331 332 void xchg(uint8_t volatile *pb);333 #pragma aux xchg = \334 "xchg [si], cx" \335 "xchg [si], cx" \336 "xchg [si], cx" \337 "xchg [si], cx" \338 parm [si] \339 modify exact [cx];340 341 219 void AtaWriteData(void const *pvBuf, size_t cb, uint8_t f8BitData) 342 220 { 343 // uint16_t uAltStsPort = ATA_REG_ALT_STATUS(g_uBasePort);344 221 uint16_t register uDataPort = ATA_REG_DATA(g_uBasePort); 345 222 uint16_t const *pu16 = (uint16_t const *)pvBuf; 223 224 cb >>= 1; 346 225 if (f8BitData) 347 226 { 348 #if 0349 uint8_t const * volatile pbSrc = (uint8_t const *)pvBuf;350 uint8_t volatile ab[64];351 uint8_t volatile *pb = &ab[0];352 while (((uintptr_t)pb & 0x1f) != 0x1f)353 pb++;354 //uint8_t bSts1, bSts2;355 inp(0x21);356 xchg(pb);357 358 while (cb-- > 0)359 {360 uint8_t b = *pbSrc++;361 xchg(pb);362 outp(uDataPort, b);363 xchg(pb);364 b = *pbSrc++;365 xchg(pb);366 //inp(0x21);367 outp(uDataPort, b);368 xchg(pb);369 //inp(0x21);370 //if (cb < 30)371 //{372 // if ((cb & 3) == 3)373 // printf("bSts1=%#x bSts2=%#x ", bSts1, bSts2);374 // else375 // printf("bSts1=%#x bSts2=%#x\n", bSts1, bSts2);376 //}377 }378 inp(0x21);379 #else380 uint16_t const *pu16 = (uint16_t const *)pvBuf;381 cb >>= 1;382 227 while (cb-- > 0) 383 228 { … … 386 231 outp(uDataPort, (uint8_t)(u16 >> 8)); 387 232 } 388 #endif389 233 } 390 234 else 391 {392 uint16_t const *pu16 = (uint16_t const *)pvBuf;393 cb >>= 1;394 235 while (cb-- > 0) 395 outp(uDataPort, *pu16++); 396 } 236 outpw(uDataPort, *pu16++); 397 237 } 398 238 … … 403 243 return AtaError(bSts, "Prepping for reading sector %lu", iSector); 404 244 405 printf("AtaReadSector #2\n");406 245 bSts = AtaSelectDevice(g_bDevice); 407 246 if (bSts & ATA_STS_ERR) 408 247 return AtaError(bSts, "Selecting device for reading sector %lu", iSector); 409 248 410 //printf("AtaReadSector #3\n");411 249 outp(ATA_REG_FEATURES(g_uBasePort), 0x0); 412 250 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1); 413 251 AtaSetSectorAddress(iSector, g_bDevice); 414 252 415 //printf("AtaReadSector #4\n");416 253 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_SECTORS); 417 254 if (bSts & ATA_STS_ERR) … … 421 258 return AtaError(bSts, "DRQ not set after reading sector %lu", iSector); 422 259 423 424 //printf("AtaReadSector #5\n");425 260 AtaReadData(pvBuf, 512, g_f8BitData); 426 //printf("AtaReadSector #6: bSts=%#x\n", inp(ATA_REG_ALT_STATUS(g_uBasePort)));427 261 bSts = inp(ATA_REG_STATUS(g_uBasePort)); 428 if ( (bSts & ATA_STS_DRQ))262 if (bSts & ATA_STS_DRQ) 429 263 return AtaError(bSts, "DRQ is still set after reading sector %lu", iSector); 430 if ( (bSts & ATA_STS_ERR))264 if (bSts & ATA_STS_ERR) 431 265 return AtaError(bSts, "ERR is set after reading sector %lu (#2)", iSector); 432 266 return 0; … … 435 269 int AtaWriteSector(uint32_t iSector, void const *pvBuf) 436 270 { 437 //int x = printf("AtaWriteSector #1\n");438 271 uint8_t bSts = AtaWaitBusy(); 439 272 if (bSts & ATA_STS_ERR) 440 273 return AtaError(bSts, "Prepping for writing sector %lu", iSector); 441 printf("AtaWriteSector #2\n");442 274 443 275 bSts = AtaSelectDevice(g_bDevice); … … 449 281 AtaSetSectorAddress(iSector, g_bDevice); 450 282 451 //printf("AtaWriteSector #3\n");452 283 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_SECTORS); 453 284 if (bSts & ATA_STS_ERR) … … 456 287 return AtaError(bSts, "DRQ not set after writing sector (#1) %lu", iSector); 457 288 458 //printf("AtaWriteSector #4\n");459 289 AtaWriteData(pvBuf, 512, g_f8BitData); 460 //printf("AtaWriteSector #5\n");461 290 ATA_DELAY_400NS(); 462 291 bSts = AtaWaitBusy(); 463 //printf("AtaWriteSector #6\n");464 292 if (bSts & ATA_STS_ERR) 465 293 return AtaError(bSts, "writing sector (#2) %lu", iSector); 466 294 if (bSts & ATA_STS_DRQ) 467 295 return AtaError(bSts, "DRQ is set after writing sector (#2) %lu", iSector); 296 297 return 0; 298 } 299 300 301 /** 302 * @param pvBuf Pointer to a 512-byte buffer. 303 */ 304 int AtaReadBuffer(void *pvBuf, uint8_t fExtraChecks) 305 { 306 uint8_t bSts; 307 308 if (!g_fSupportsReadBuffer) 309 return -2; 310 311 bSts = AtaWaitBusy(); 312 if (bSts & ATA_STS_ERR) 313 return AtaError(bSts, "Prepping for reading buffer"); 314 315 bSts = AtaSelectDevice(g_bDevice); 316 if (bSts & ATA_STS_ERR) 317 return AtaError(bSts, "Selecting device for reading buffer"); 318 319 outp(ATA_REG_FEATURES(g_uBasePort), 0); 320 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1); /* ignored */ 321 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), 0); 322 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), 0); 323 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), 0); 324 325 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_BUFFER); 326 if (bSts & ATA_STS_ERR) 327 return AtaError(bSts, "Reading buffer"); 328 329 if (!(bSts & ATA_STS_DRQ)) 330 return AtaError(bSts, "DRQ not set after reading buffer"); 331 332 if (!fExtraChecks) 333 AtaReadData(pvBuf, 512, g_f8BitData); 334 else 335 AtaReadData(pvBuf, 512, g_f8BitData); 336 bSts = inp(ATA_REG_STATUS(g_uBasePort)); 337 if (bSts & ATA_STS_DRQ) 338 return AtaError(bSts, "DRQ is still set after reading buffer"); 339 if (bSts & ATA_STS_ERR) 340 return AtaError(bSts, "ERR is set after reading buffer"); 341 return 0; 342 } 343 344 int AtaWriteBuffer(void const *pvBuf, uint8_t fExtraChecks) 345 { 346 uint8_t bSts; 347 348 if (!g_fSupportsWriteBuffer) 349 return -2; 350 351 bSts = AtaWaitBusy(); 352 if (bSts & ATA_STS_ERR) 353 return AtaError(bSts, "Prepping for writing buffer"); 354 355 bSts = AtaSelectDevice(g_bDevice); 356 if (bSts & ATA_STS_ERR) 357 return AtaError(bSts, "Selecting device for writing buffer"); 358 359 outp(ATA_REG_FEATURES(g_uBasePort), 0); 360 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1); /* ignored */ 361 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), 0); 362 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), 0); 363 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), 0); 364 365 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_SECTORS); 366 if (bSts & ATA_STS_ERR) 367 return AtaError(bSts, "writing buffer (#1)"); 368 if (!(bSts & ATA_STS_DRQ)) 369 return AtaError(bSts, "DRQ not set after writing buffer (#1)"); 370 371 if (!fExtraChecks) 372 AtaWriteData(pvBuf, 512, g_f8BitData); 373 else 374 AtaWriteData(pvBuf, 512, g_f8BitData); 375 ATA_DELAY_400NS(); 376 bSts = AtaWaitBusy(); 377 if (bSts & ATA_STS_ERR) 378 return AtaError(bSts, "writing buffer (#2)"); 379 if (bSts & ATA_STS_DRQ) 380 return AtaError(bSts, "DRQ is set after writing buffer (#2)"); 468 381 469 382 return 0; … … 571 484 } 572 485 573 574 int AtaInit(void) 575 { 576 uint8_t bSts = inp(ATA_REG_ALT_STATUS(g_uBasePort)); 577 printf("alt status="); 486 int AtaReInit(void) 487 { 488 int rc; 489 490 /* Reset the controller + devices. */ 491 if (AtaReset() != 0) 492 return -1; 493 494 if (g_fSupportsSetFeature8BitData) 495 { 496 if (g_f8BitData) 497 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0); 498 else 499 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_8BIT_DATA, 0); 500 if (rc != 0) 501 return rc; 502 } 503 504 /* Try disable write cache. */ 505 if (g_fSupportsSetFeatureWriteCache) 506 { 507 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0); 508 if (rc != 0) 509 return rc; 510 } 511 512 /* Select PIO mode without IORDY. */ 513 if (g_fSupportsSetFeatureXferMode) 514 { 515 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY); 516 if (rc != 0) 517 return rc; 518 } 519 520 return 0; 521 } 522 523 int AtaInit(uint16_t uBasePort, uint16_t uCtrlPort, uint8_t uPortShift, uint8_t bDevice, uint8_t f8BitData) 524 { 525 int rc; 526 uint8_t bSts, bStsAlt; 527 528 g_uBasePort = uBasePort; 529 g_uCtrlPort = uCtrlPort; 530 g_uPortShift = uPortShift; 531 g_bDevice = bDevice; 532 g_f8BitData = f8BitData; 533 g_fSupportsSetFeature8BitData = 1; 534 g_fSupportsSetFeatureWriteCache = 1; 535 g_fSupportsSetFeatureXferMode = 1; 536 537 /* Check whether the two status registers match up. If they don't we 538 probably don't have a controller at this address. */ 539 inp(ATA_REG_STATUS(g_uBasePort)); 540 bSts = inp(ATA_REG_STATUS(g_uBasePort)); 541 bStsAlt = inp(ATA_REG_ALT_STATUS(g_uBasePort)); 542 if (bSts != bStsAlt || bSts == 0xff) 543 { 544 fprintf(stderr, "Status register differs or is 0xff\n"); 545 fprintf(stderr, " status="); 546 AtaPrintStatus(stdout, bSts); 547 fprintf(stderr, "\n"); 548 fprintf(stderr, " alt status="); 549 AtaPrintStatus(stdout, bStsAlt); 550 fprintf(stderr, "\n"); 551 return -1; 552 } 553 printf("Pre init status="); 578 554 AtaPrintStatus(stdout, bSts); 579 555 printf("\n"); 580 556 581 bSts = inp(ATA_REG_STATUS(g_uBasePort)); 582 printf(" status="); 583 AtaPrintStatus(stdout, bSts); 584 printf("\n"); 585 586 if (AtaReset() != 0) 587 return -1; 588 589 /* Enable 8-bit data transfers (just to be on the safe side). */ 590 AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0); 591 592 /* Identify the device. */ 593 memset(g_awIdentify, 0, sizeof(g_awIdentify)); 594 if (AtaIdentifyDevice(g_bDevice, g_awIdentify) != 0) 595 return -1; 596 597 /** @todo this is rather simple... */ 598 g_cCylinders = g_awIdentify[1]; 599 g_cHeads = g_awIdentify[3]; 600 g_cSectorsPerTrack = g_awIdentify[6]; 601 g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack; 602 printf("Device %#x parameters: %u cylinders, %u heads, %u sectors\n", 603 g_bDevice, g_cCylinders, g_cHeads, g_cSectorsPerTrack); 604 605 /* Disable stuff and try select pio modes. */ 606 AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0); 607 AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY); 608 AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_XXX_FLAG | 0); 609 610 return 0; 611 } 612 613 614 615 616 /* 617 * INT13h access methods 618 * INT13h access methods 619 * INT13h access methods 620 */ 621 622 void BiosCall13(REGS16 *pRegs); 623 #pragma aux BiosCall13 = \ 624 "push ax" \ 625 "push cx" \ 626 "push dx" \ 627 "push bp" \ 628 "push si" \ 629 "push di" \ 630 "push es" \ 631 "push bx" \ 632 "push ds" \ 633 \ 634 "mov ax, [bx]" \ 635 "mov cx, [bx + 2]" \ 636 "mov dx, [bx + 4]" \ 637 "mov si, [bx + 6]" \ 638 "mov di, [bx + 8]" \ 639 "mov es, [bx + 10]" \ 640 "push word ptr [bx + 12]" \ 641 "popf" \ 642 "push word ptr [bx + 14]" \ 643 "push word ptr [bx + 16]" \ 644 "pop bx" \ 645 "pop ds" \ 646 \ 647 "int 13h"\ 648 \ 649 "push ds" \ 650 "push bx" \ 651 "mov bp, sp" \ 652 "mov ds, [bp + 4]" \ 653 "mov bx, [bp + 6]" \ 654 "mov [bx], ax" \ 655 "mov [bx + 2], cx" \ 656 "mov [bx + 4], dx" \ 657 "mov [bx + 6], si" \ 658 "mov [bx + 8], di" \ 659 "mov [bx + 10], es" \ 660 "pushf" \ 661 "pop ax" \ 662 "mov [bx + 12], ax" \ 663 "pop ax" \ 664 "mov [bx + 14], ax" \ 665 "pop ax" \ 666 "mov [bx + 16], ax" \ 667 \ 668 "pop ds" \ 669 "pop bx" \ 670 "pop es" \ 671 "pop di" \ 672 "pop si" \ 673 "pop bp" \ 674 "pop dx" \ 675 "pop cx" \ 676 "pop ax" \ 677 parm [bx]; 678 679 680 int Int13hInit(void) 681 { 682 REGS16 Regs; 683 memset(&Regs, 0, sizeof(Regs)); 684 Regs.ax = 0x0800; 685 Regs.dx = g_bDrv; 686 BiosCall13(&Regs); 687 /** @todo check for errors. */ 688 g_cHeads = (Regs.dx >> 8) + 1; 689 g_cSectorsPerTrack = Regs.cx & 0x3f; 690 g_cCylinders = (Regs.cx >> 8) | ((Regs.cx & 0xc0) << 2); 691 g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack; 692 693 printf("Drive %#x parameters: %u cylinders, %u heads, %u sectors\n", 694 g_bDrv, g_cCylinders, g_cHeads, g_cSectorsPerTrack); 695 if (!(Regs.efl & X86_EFL_CF)) 696 return 0; 697 fprintf(stderr, "Error getting disk params: %#x\n", Regs.ax); 698 return -1; 699 } 700 701 void SectorNoToInt13(uint32_t iSector, REGS16 *pRegs) 702 { 703 uint16_t iRem = iSector % g_cSectorsPerCylinder; 704 uint16_t iCyl = iSector / g_cSectorsPerCylinder; 705 pRegs->cx = iCyl << 8; 706 pRegs->cx |= (iCyl >> 2) & 0xc0; 707 pRegs->cx |= (iRem % g_cSectorsPerTrack) & 0x3f; 708 pRegs->dx &= UINT16_C(0x00ff); 709 pRegs->dx |= (iRem / g_cSectorsPerTrack) << 8; 710 } 711 712 int Int13hReadSector(uint32_t iSector, void *pvBuf) 713 { 714 REGS16 Regs; 715 memset(&Regs, 0, sizeof(Regs)); 716 Regs.ax = 0x0201; 717 Regs.dx = g_bDrv; 718 Regs.bx = (unsigned)(void __near *)pvBuf; 719 Regs.es = (__segment)pvBuf; 720 SectorNoToInt13(iSector, &Regs); 721 printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx); 722 BiosCall13(&Regs); 723 if (!(Regs.efl & X86_EFL_CF)) 724 return 0; 725 fprintf(stderr, "Error reading sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax); 726 return -1; 727 } 728 729 int Int13hWriteSector(uint32_t iSector, void const *pvBuf) 730 { 731 REGS16 Regs; 732 memset(&Regs, 0, sizeof(Regs)); 733 Regs.ax = 0x0301; 734 Regs.dx = g_bDrv; 735 Regs.bx = (unsigned)(void const __near *)pvBuf; 736 Regs.es = (__segment)pvBuf; 737 SectorNoToInt13(iSector, &Regs); 738 printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx); 739 BiosCall13(&Regs); 740 if (!(Regs.efl & X86_EFL_CF)) 741 return 0; 742 fprintf(stderr, "Error writing sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax); 743 return -1; 744 } 745 746 747 748 int GetDriveParams(void) 749 { 750 #ifdef USE_INT13H 751 return Int13hInit(); 557 for (;;) 558 { 559 /* Reset the controller + devices. */ 560 if (AtaReset() != 0) 561 return -1; 562 563 /* Enable 8-bit data transfers (just to be on the safe side). */ 564 if (g_fSupportsSetFeature8BitData) 565 { 566 if (g_f8BitData) 567 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0); 568 else 569 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_8BIT_DATA, 0); 570 if (rc != 0) 571 { 572 fprintf(stderr, 573 f8BitData 574 ? "warning: ATA_FEATURE_EN_8BIT_DATA failed, assuming not supported. Retrying in 16-bit mode." 575 : "warning: ATA_FEATURE_DI_8BIT_DATA failed, assuming not supported. Retrying."); 576 g_fSupportsSetFeature8BitData = 0; 577 g_f8BitData = 0; 578 continue; 579 } 580 } 581 582 /* Try disable write cache. */ 583 if (g_fSupportsSetFeatureWriteCache) 584 { 585 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0); 586 if (rc != 0) 587 { 588 fprintf(stderr, "warning: ATA_FEATURE_DI_WRITE_CACHE failed, assuming not supported. Retrying."); 589 g_fSupportsSetFeatureWriteCache = 0; 590 continue; 591 } 592 } 593 594 /* Select PIO mode without IORDY. */ 595 if (g_fSupportsSetFeatureXferMode) 596 { 597 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY); 598 if (rc != 0) 599 { 600 fprintf(stderr, "warning: ATA_FEATURE_SET_XFERMODE = DEFAULT_NO_IORDY failed, assuming not supported. Retrying."); 601 g_fSupportsSetFeatureXferMode = 0; 602 continue; 603 } 604 } 605 606 /* Identify the device. */ 607 memset(g_awIdentify, 0, sizeof(g_awIdentify)); 608 if (AtaIdentifyDevice(g_bDevice, g_awIdentify) != 0) 609 return -1; 610 611 /** @todo this is rather simple... */ 612 g_cCylinders = g_awIdentify[1]; 613 g_cHeads = g_awIdentify[3]; 614 g_cSectorsPerTrack = g_awIdentify[6]; 615 g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack; 616 printf("Device %#x at %#x/%#x: %u cylinders, %u heads, %u sectors, %s data\n", 617 g_bDevice, g_uBasePort, g_uCtrlPort, g_cCylinders, g_cHeads, g_cSectorsPerTrack, 618 g_f8BitData ? "8-bit" : "16-bit"); 619 620 /* Figure 5-9 in SanDisk Manual Rev 12.0: */ 621 if ( (g_awIdentify[83] & UINT16_C(0xc00)) == UINT16_C(0x4000) 622 && (g_awIdentify[84] & UINT16_C(0xc00)) == UINT16_C(0x4000)) 623 { 624 g_fSupportsWriteBuffer = (g_awIdentify[82] & UINT16_C(0x1000)) != 0; 625 g_fSupportsReadBuffer = (g_awIdentify[82] & UINT16_C(0x2000)) != 0; 626 } 627 printf(" %s WRITE_BUFFER, %s READ_BUFFER\n", 628 g_fSupportsWriteBuffer == 1 ? "have" : g_fSupportsWriteBuffer == 0 ? "no" : "uncertain", 629 g_fSupportsReadBuffer == 1 ? "have" : g_fSupportsReadBuffer == 0 ? "no" : "uncertain"); 630 } 631 632 return 0; 633 } 634 635 int AtaArgMatchWithValue(const char *pszArg, const char *pszMatch, size_t cchMatch, 636 int cArgs, char **papszArgs, int *piArg, const char **ppszValue) 637 { 638 if (strncmp(pszArg, pszMatch, cchMatch) == 0) 639 { 640 pszArg += cchMatch; 641 if (!*pszArg) 642 { 643 if (*piArg < cArgs) 644 { 645 *ppszValue = papszArgs[*piArg]; 646 *piArg += 1; 647 } 648 else 649 { 650 fprintf(stderr, "syntax error: Option '%s' is missing argument value\n", pszMatch); 651 *ppszValue = NULL; 652 } 653 return 1; 654 } 655 656 if (*pszArg == ':' || *pszArg == '=') 657 { 658 if (!*pszArg) 659 fprintf(stderr, "syntax error: Option '%s' is missing argument value\n", pszMatch); 660 *ppszValue = pszArg; 661 return 1; 662 } 663 } 664 665 return 0; 666 } 667 668 int AtaInitFromArgv(int iArg, int cArgs, char **papszArgs) 669 { 670 uint8_t bDevice = ATA_DEV_MASTER; 671 #if 0 672 uint16_t uBasePort = 0x1f0; /* Primary ATA host controller. */ 673 uint16_t uCtrlPort = 0x3f0; /* The control block of the primary ATA host controller. */ 674 uint8_t cShiftPort = 0; 675 uint8_t f8BitData = 0; 752 676 #else 753 return AtaInit(); 677 uint16_t uBasePort = 0x300; /* Lo-tech CF-lite. */ 678 uint16_t uCtrlPort = 0x310; /* Lo-tech CF-lite. */ 679 uint8_t cShiftPort = 1; /* Special Lo-tech CF-lite hack. */ 680 uint8_t f8BitData = 1; 754 681 #endif 755 } 756 757 int ReadSector(uint32_t iSector, void *pvBuf) 758 { 759 #ifdef USE_INT13H 760 return Int13hReadSector(iSector, pvBuf); 761 #else 762 return AtaReadSector(iSector, pvBuf); 763 #endif 764 } 765 766 int WriteSector(uint32_t iSector, void const *pvBuf) 767 { 768 #ifdef USE_INT13H 769 return Int13hWriteSector(iSector, pvBuf); 770 #else 771 return AtaWriteSector(iSector, pvBuf); 772 #endif 773 } 774 775 776 777 778 static int usage(void) 779 { 780 printf("usage: writetst [sector] [drv]\n"); 781 return 1; 782 } 783 784 785 int main(int argc, char **argv) 786 { 787 int rc = 1; 788 789 /* 790 * Parse parameters. 791 */ 792 uint32_t iSector = 3; 793 g_bDrv = 0x80; 794 g_bDevice = ATA_DEV_MASTER; 795 796 if (argc > 3) 797 { 798 fprintf(stderr, "too many parameters!\n"); 799 return usage(); 800 } 801 if (argc > 1) 802 { 803 iSector = strtoul(argv[1], NULL, 0); 804 if ( iSector == 0 805 || (iSector >= 32 && iSector < 65535) 806 || iSector > 0x800000 /*4G*/) 807 { 808 fprintf(stderr, "error: start sector is out of bounds: %s (%lu)\n", argv[1], iSector); 809 return usage(); 810 } 811 } 812 if (argc > 2) 813 { 814 unsigned long uTmp = strtoul(argv[2], NULL, 0); 815 if (uTmp < 0x80 || uTmp > 0x8f) 816 { 817 fprintf(stderr, "error: drive number is out of bounds: %s (%lu)\n", argv[1], uTmp); 818 return usage(); 819 } 820 g_bDrv = (uint8_t)uTmp; 821 g_bDevice = g_bDrv == 0x80 ? ATA_DEV_MASTER : ATA_DEV_SLAVE; /* simplified */ 822 } 823 824 /* 825 * Detect drive parameters. 826 */ 827 if (GetDriveParams() == 0) 828 { 829 static uint8_t s_abSaved[512]; 830 if (ReadSector(iSector, s_abSaved) == 0) 831 { 832 static uint8_t s_abWrite[512]; 833 unsigned i; 834 unsigned cTries; 835 //unsigned cMaxTries = 20; 836 unsigned cMaxTries = 1; 837 838 for (i = 0; i < 512; i++) 839 s_abWrite[i] = (uint8_t)i; 840 841 for (cTries = 0; cTries < cMaxTries && rc != 0; cTries++) 682 683 while (iArg < cArgs) 684 { 685 const char *pszArg = papszArgs[iArg++]; 686 const char *pszValue; 687 int iWhich = 0; 688 if ( (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("--base-port"), cArgs, papszArgs, &iArg, &pszValue)) 689 || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("-b"), cArgs, papszArgs, &iArg, &pszValue)) 690 || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("--ctrl-port"), cArgs, papszArgs, &iArg, &pszValue) * 2) 691 || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("-c"), cArgs, papszArgs, &iArg, &pszValue) * 2) ) 692 { 693 unsigned long uTmp = strtoul(pszValue, NULL, 16); 694 if (uTmp < 16 || uTmp >= 1024) 842 695 { 843 if (WriteSector(iSector, s_abWrite) == 0) 844 { 845 static uint8_t s_abReadBack[512]; 846 847 if (ReadSector(iSector, s_abReadBack) == 0) 848 { 849 for (i = 0; i < 512; i++) 850 s_abWrite[i] = (uint8_t)i; 851 852 if (memcmp(s_abReadBack, s_abWrite, sizeof(s_abReadBack)) == 0) 853 { 854 rc = 0; 855 printf("wrote sector and successfully read it back\n"); 856 } 857 else if (cTries >= cMaxTries - 1) 858 { 859 unsigned cErrors = 0; 860 fprintf(stderr, "read back doesn't match what was written:\n"); 861 for (i = 0; i < 512; i++) 862 if (s_abReadBack[i] != (uint8_t)i) 863 { 864 fprintf(stderr, " %03x: %02x->%02x", i, (uint8_t)i, s_abReadBack[i]); 865 if ((cErrors % 5) == 4) 866 fprintf(stderr, "\n"); 867 cErrors++; 868 if (cErrors > 5 * 10) 869 break; 870 } 871 if ((cErrors % 5) != 0) 872 fprintf(stderr, "\n"); 873 } 874 } 875 876 } 696 fprintf(stderr, "error: Invalid port number %#lx for %s (valid range 0x010..0x3ff)\n", uTmp, pszArg); 697 return -1; 877 698 } 878 879 /* restore */ 880 WriteSector(iSector, s_abSaved); 881 } 882 } 883 884 885 return rc; 886 } 887 699 if (iWhich == 1) 700 uBasePort = (uint16_t)uTmp; 701 else 702 uCtrlPort = (uint16_t)uTmp; 703 } 704 else if ( AtaArgMatchWithValue(pszArg, STR_TUPLE("--port-shift"), cArgs, papszArgs, &iArg, &pszValue) 705 || AtaArgMatchWithValue(pszArg, STR_TUPLE("-s"), cArgs, papszArgs, &iArg, &pszValue) ) 706 { 707 unsigned long uTmp = strtoul(pszValue, NULL, 0); 708 if (uTmp >= 4) 709 { 710 fprintf(stderr, "error: Invalid port shift number %#lx (valid range 0..3)\n", uTmp); 711 return -1; 712 } 713 cShiftPort = (uint8_t)uTmp; 714 } 715 else if ( AtaArgMatchWithValue(pszArg, STR_TUPLE("--device"), cArgs, papszArgs, &iArg, &pszValue) 716 || AtaArgMatchWithValue(pszArg, STR_TUPLE("-d"), cArgs, papszArgs, &iArg, &pszValue) ) 717 { 718 unsigned long uTmp = strtoul(pszValue, NULL, 16); 719 if ( uTmp != ATA_DEV_MASTER 720 && uTmp != ATA_DEV_SLAVE) 721 { 722 fprintf(stderr, "error: Invalid device number %#lx; only %#x (master) or %#x (slave) are allowed.\n", 723 uTmp, ATA_DEV_MASTER, ATA_DEV_SLAVE); 724 return -1; 725 } 726 bDevice = (uint8_t)uTmp; 727 } 728 else if ( strcmp(pszArg, "--8-bit-data") == 0 729 || strcmp(pszArg, "-8") == 0) 730 f8BitData = 1; 731 else if ( strcmp(pszArg, "--16-bit-data") == 0 732 || strcmp(pszArg, "-16") == 0) 733 f8BitData = 0; 734 } 735 736 return AtaInit(uBasePort, uCtrlPort, cShiftPort, bDevice, f8BitData); 737 } 738
Note:
See TracChangeset
for help on using the changeset viewer.