snj doesn't like my accent, so use proper English month names.
[netbsd-mini2440.git] / dist / pdisk / ATA_media.c
blobdbb3b30ea72563d8b8568b71115ba98563568533
1 /*
2 * ATA_media.c -
4 * Written by Eryk Vershen
5 */
7 /*
8 * Copyright 1997,1998 by Apple Computer, Inc.
9 * All Rights Reserved
11 * Permission to use, copy, modify, and distribute this software and
12 * its documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appears in all copies and
14 * that both the copyright notice and this permission notice appear in
15 * supporting documentation.
17 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE.
21 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
24 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
25 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29 // for printf()
30 #include <stdio.h>
31 // for malloc() & free()
32 #include <stdlib.h>
33 #include <ATA.h>
34 // for SCSI command structures
35 #include "MacSCSICommand.h"
36 #include "ATA_media.h"
37 #include "util.h"
41 * Defines
43 #define RESULT_OFFSET(type) \
44 ((sizeof(type) == 1) ? 3 : ((sizeof(type) == 2) ? 1 : 0))
45 #define TBTrapTableAddress(trapNum) (((trapNum & 0x03FF) << 2) + 0xE00)
46 #define SWAP_SHORTS(x) ((((x) & 0xFFFF) << 16) | (((x) >> 16) & 0xFFFF))
47 #define LBA_CAPABLE 0x0200
51 * Types
53 typedef struct ATA_info *ATA_INFO;
55 struct ATA_info {
56 long lba;
57 long heads;
58 long sectors;
61 typedef struct ATA_media *ATA_MEDIA;
63 struct ATA_media {
64 struct media m;
65 long id;
66 struct ATA_info info;
69 struct ATA_manager {
70 long exists;
71 long kind;
72 struct {
73 char major;
74 char minor;
75 } version;
76 short busCount;
77 long *bus_list;
80 typedef struct ATA_media_iterator *ATA_MEDIA_ITERATOR;
82 struct ATA_media_iterator {
83 struct media_iterator m;
84 long bus_index;
85 long bus;
86 long id;
89 struct ATA_identify_drive_info { /* word */
90 unsigned short config_bits; /* 0 */
91 unsigned short num_cylinders; /* 1 */
92 unsigned short reserved2; /* 2 */
93 unsigned short num_heads; /* 3 */
94 unsigned short bytes_per_track; /* 4 */
95 unsigned short bytes_per_sector; /* 5 */
96 unsigned short sectors_per_track; /* 6 */
97 unsigned short vendor7[3]; /* 7-9 */
98 char serial_number[20]; /* 10-19 */
99 unsigned short buffer_type; /* 20 */
100 unsigned short buffer_size; /* 21 */
101 unsigned short num_of_ecc_bytes; /* 22 */
102 char firmware_rev[8]; /* 23-26 */
103 char model_number[40]; /* 27-46 */
104 unsigned short word47; /* 47 */
105 unsigned short double_word_io; /* 48 */
106 unsigned short capabilities; /* 49 */
107 unsigned short reserved50; /* 50 */
108 unsigned short pio_timing; /* 51 */
109 unsigned short dma_timing; /* 52 */
110 unsigned short current_is_valid; /* 53 */
111 unsigned short cur_cylinders; /* 54 */
112 unsigned short cur_heads; /* 55 */
113 unsigned short cur_sec_per_track; /* 56 */
114 unsigned long total_sectors; /* 57-58 */
115 unsigned short multiple_sectors; /* 59 */
116 unsigned long lba_sectors; /* 60-61 */
117 unsigned short singleword_dma; /* 62 */
118 unsigned short multiword_dma; /* 63 */
119 unsigned short reserved64[64]; /* 64-127 */
120 unsigned short vendor128[32]; /* 128-159 */
121 unsigned short reserved160[96]; /* 160-255 */
124 struct ATAPI_identify_drive_info { /* word */
125 unsigned short config_bits; /* 0 */
126 unsigned short retired1[9]; /* 1-9 */
127 char serial_number[20]; /* 10-19 */
128 unsigned short retired20[3]; /* 20-22 */
129 char firmware_rev[8]; /* 23-26 */
130 char model_number[40]; /* 27-46 */
131 unsigned short retired47[2]; /* 47-48 */
132 unsigned short capabilities; /* 49 */
133 unsigned short reserved50; /* 50 */
134 unsigned short pio_timing; /* 51 */
135 unsigned short dma_timing; /* 52 */
136 unsigned short current_is_valid; /* 53 */
137 unsigned short retired54[8]; /* 54-61 */
138 unsigned short singleword_dma; /* 62 */
139 unsigned short multiword_dma; /* 63 */
140 unsigned short pio_transfer; /* 64 */
141 unsigned short min_cycle_time; /* 65 */
142 unsigned short rec_cycle_time; /* 66 */
143 unsigned short min_wo_flow; /* 67 */
144 unsigned short min_with_flow; /* 68 */
145 unsigned short reserved69[2]; /* 69-70 */
146 unsigned short release_over; /* 71 */
147 unsigned short release_service; /* 72 */
148 unsigned short major_rev; /* 73 */
149 unsigned short minor_rev; /* 74 */
150 unsigned short reserved75[53]; /* 75-127 */
151 unsigned short vendor128[32]; /* 128-159 */
152 unsigned short reserved160[96]; /* 160-255 */
155 /* Identifies the bus protocol type. */
156 enum {
157 kDevUnknown = 0,
158 kDevATA = 1,
159 kDevATAPI = 2,
160 kDevPCMCIA = 3
165 * Global Constants
167 enum {
168 kNoDevice = 0x00FF,
169 kATAtimeout = 3000,
170 kATAcmdATAPIPacket = 0x00A0 /* ATAPI packet command */
175 * Global Variables
177 static long ata_inited = 0;
178 static struct ATA_manager ata_mgr;
181 * Forward declarations
183 int ATAManagerPresent(void);
184 int ATAHardwarePresent(void);
185 pascal SInt16 ataManager(ataPB *pb);
186 void ata_init(void);
187 ATA_MEDIA new_ata_media(void);
188 long read_ata_media(MEDIA m, long long offset, unsigned long count, void *address);
189 long write_ata_media(MEDIA m, long long offset, unsigned long count, void *address);
190 long close_ata_media(MEDIA m);
191 long os_reload_ata_media(MEDIA m);
192 long compute_id(long bus, long device);
193 pascal SInt16 ataManager(ataPB *pb);
194 int ATA_ReadBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address);
195 int ATA_WriteBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address);
196 long get_info(long id, struct ATA_identify_drive_info *ip);
197 long get_pi_info(long id, struct ATAPI_identify_drive_info *ip);
198 long is_atapi(long id);
199 long read_atapi_media(MEDIA m, long long offset, unsigned long count, void *address);
200 long write_atapi_media(MEDIA m, long long offset, unsigned long count, void *address);
201 int ATAPI_ReadBlock(UInt32 deviceID, UInt32 block_size, UInt32 block, UInt8 *address);
202 int ATAPI_TestUnitReady(UInt32 deviceID);
203 int ATAPI_ReadCapacity(UInt32 deviceID, unsigned long *block_size, unsigned long *blocks);
204 ATA_MEDIA_ITERATOR new_ata_iterator(void);
205 void reset_ata_iterator(MEDIA_ITERATOR m);
206 char *step_ata_iterator(MEDIA_ITERATOR m);
207 void delete_ata_iterator(MEDIA_ITERATOR m);
208 int ata_bus_present(int num);
212 * Routines
214 #if GENERATINGPOWERPC
215 pascal SInt16
216 ataManager(ataPB *pb)
218 #ifdef applec
219 #if sizeof(SInt16) > 4
220 #error "Result types larger than 4 bytes are not supported."
221 #endif
222 #endif
223 long private_result;
225 private_result = CallUniversalProc(
226 *(UniversalProcPtr*)TBTrapTableAddress(0xAAF1),
227 kPascalStackBased
228 | RESULT_SIZE(SIZE_CODE(sizeof(SInt16)))
229 | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(pb))),
230 pb);
231 return *(((SInt16*)&private_result) + RESULT_OFFSET(SInt16));
233 #endif
237 ATAHardwarePresent(void)
239 UInt16 configFlags;
241 // Hardware configuration flags
242 configFlags = LMGetHWCfgFlags();
244 return ((configFlags & 0x0080) != 0);
249 ATAManagerPresent(void)
251 if (ATAHardwarePresent()) {
252 return (TrapAvailable(kATATrap));
253 } else {
254 return 0;
258 void
259 ata_init(void)
261 ataMgrInquiry pb;
262 OSErr status;
263 int i;
264 int j;
266 if (ata_inited != 0) {
267 return;
269 ata_inited = 1;
271 if (ATAManagerPresent() == 0) {
272 ata_mgr.exists = 0;
273 return;
276 ata_mgr.exists = 1;
277 ata_mgr.kind = allocate_media_kind();
279 clear_memory((void *)&pb, sizeof(pb));
281 pb.ataPBFunctionCode = kATAMgrManagerInquiry;
282 pb.ataPBVers = kATAPBVers1;
284 status = ataManager((ataPB*) &pb );
286 if (status != noErr) {
287 ata_mgr.exists = 0;
288 return;
290 ata_mgr.version.major = pb.ataMgrVersion.majorRev;
291 ata_mgr.version.minor = pb.ataMgrVersion.minorAndBugRev >> 4;
292 ata_mgr.busCount = pb.ataBusCnt;
294 ata_mgr.bus_list = (long *) calloc(ata_mgr.busCount, sizeof(long));
295 if (ata_mgr.bus_list == 0) {
296 ata_mgr.busCount = 0;
297 } else {
298 for (i = 0, j = 0; j < ata_mgr.busCount; i++) {
299 if (ata_bus_present(i)) {
300 ata_mgr.bus_list[j] = i;
301 j++;
309 ata_bus_present(int num)
311 ataBusInquiry pb;
312 OSErr status;
314 clear_memory((void *)&pb, sizeof(pb));
316 pb.ataPBFunctionCode = kATAMgrBusInquiry;
317 pb.ataPBVers = kATAPBVers1;
318 pb.ataPBDeviceID = num;
320 status = ataManager((ataPB*) &pb );
322 if (status == noErr) {
323 return 1;
324 } else {
325 //printf("status = %d\n", status);
326 return 0;
331 ATA_MEDIA
332 new_ata_media(void)
334 return (ATA_MEDIA) new_media(sizeof(struct ATA_media));
338 #pragma mark -
341 long
342 compute_id(long bus, long device)
344 long id;
345 int i;
347 id = -1;
348 for (i = 0; i < ata_mgr.busCount; i++) {
349 if (bus == ata_mgr.bus_list[i]) {
350 break;
353 if (i >= ata_mgr.busCount) {
354 /* bad bus id */
355 } else if (ata_mgr.version.major < 3) {
356 if (device != 0) {
357 /* bad device id */
358 } else {
359 id = bus & 0xFF;
361 } else {
362 if (device < 0 || device > 1) {
363 /* bad device id */
364 } else {
365 id = ((device & 0xFF) << 8) | (bus & 0xFF);
368 return id;
372 static long
373 get_info(long id, struct ATA_identify_drive_info *ip)
375 ataIdentify pb;
376 ataDevConfiguration pb2;
377 OSErr status;
378 long rtn_value;
379 long atapi;
381 if (sizeof(struct ATA_identify_drive_info) < 512) {
382 return 0;
384 clear_memory((void *)ip, sizeof(struct ATA_identify_drive_info));
386 clear_memory((void *)&pb, sizeof(pb));
387 pb.ataPBFunctionCode = kATAMgrDriveIdentify;
388 pb.ataPBVers = kATAPBVers1;
389 pb.ataPBDeviceID = id;
390 pb.ataPBFlags = mATAFlagIORead | mATAFlagByteSwap;
391 pb.ataPBTimeOut = kATAtimeout;
392 pb.ataPBBuffer = (void*) ip;
394 status = ataManager((ataPB*) &pb );
396 if (status != noErr) {
397 //printf("get info status = %d\n", status);
398 rtn_value = 0;
399 } else {
400 ip->total_sectors = SWAP_SHORTS(ip->total_sectors);
401 ip->lba_sectors = SWAP_SHORTS(ip->lba_sectors);
402 rtn_value = 1;
404 return rtn_value;
408 static long
409 is_atapi(long id)
411 ataDevConfiguration pb;
412 OSErr status;
413 long atapi;
415 atapi = 0;
416 if (ata_mgr.version.major >= 2) {
417 clear_memory((void *)&pb, sizeof(pb));
418 pb.ataPBFunctionCode = kATAMgrGetDrvConfiguration;
419 pb.ataPBVers = kATAPBVers2;
420 pb.ataPBDeviceID = id;
421 pb.ataPBTimeOut = kATAtimeout;
423 status = ataManager((ataPB*) &pb );
424 if (status != noErr) {
425 //printf("is atatpi status = %d\n", status);
426 } else if (pb.ataDeviceType == kDevATAPI) {
427 atapi = 1;
428 /* the drive can be asleep or something in which case this doesn't work */
429 /* how do we do reads */
432 return atapi;
436 MEDIA
437 open_ata_as_media(long bus, long device)
439 ATA_MEDIA a;
440 long id;
441 struct ATA_identify_drive_info info;
442 unsigned char *buf;
443 unsigned long total;
445 if (ata_inited == 0) {
446 ata_init();
449 if (ata_mgr.exists == 0) {
450 //printf("ATA manager does not exist\n");
451 return 0;
454 id = compute_id(bus, device);
456 if (id < 0) {
457 return 0;
459 } else if (is_atapi(id)) {
460 a = (ATA_MEDIA) open_atapi_as_media(bus, device);
462 } else {
463 a = 0;
464 if (get_info(id, &info) != 0) {
465 a = new_ata_media();
466 if (a != 0) {
467 a->m.kind = ata_mgr.kind;
468 if ((info.capabilities & LBA_CAPABLE) != 0) {
469 total = info.lba_sectors;
470 a->info.lba = 1;
471 a->info.heads = 0;
472 a->info.sectors = 0;
473 } else {
474 /* Only CHS - Cylinder Head Sector addressing */
475 total = info.total_sectors;
476 a->info.lba = 0;
477 a->info.heads = info.cur_heads;
478 a->info.sectors = info.cur_sec_per_track;
480 { /* XXX this should be a loop in a subroutine */
481 buf = malloc(2048);
482 if (ATA_ReadBlock(id, &a->info, 512, 0, buf)) {
483 a->m.grain = 512;
484 } else if (ATA_ReadBlock(id, &a->info, 1024, 0, buf)) {
485 a->m.grain = 1024;
486 } else if (ATA_ReadBlock(id, &a->info, 2048, 0, buf)) {
487 a->m.grain = 2048;
488 } else {
489 a->m.grain = 512; /* XXX should really return failure here */
491 free(buf);
493 if (total == 0) {
494 a->m.size_in_bytes = ((long long)1000) * a->m.grain; /* XXX not right */
495 } else {
496 a->m.size_in_bytes = ((long long)total) * a->m.grain;
498 a->m.do_read = read_ata_media;
499 a->m.do_write = write_ata_media;
500 a->m.do_close = close_ata_media;
501 a->m.do_os_reload = os_reload_ata_media;
502 a->id = id;
504 } else {
505 printf("ATA - couldn't get info\n");
508 return (MEDIA) a;
512 long
513 read_ata_media(MEDIA m, long long offset, unsigned long count, void *address)
515 ATA_MEDIA a;
516 ataIOPB pb;
517 OSErr status;
518 long rtn_value;
519 long block;
520 long block_count;
521 long block_size;
522 unsigned char *buffer;
523 int i;
525 a = (ATA_MEDIA) m;
526 rtn_value = 0;
527 if (a == 0) {
528 /* no media */
529 } else if (a->m.kind != ata_mgr.kind) {
530 /* wrong kind - XXX need to error here - this is an internal problem */
531 } else if (count <= 0 || count % a->m.grain != 0) {
532 /* can't handle size */
533 } else if (offset < 0 || offset % a->m.grain != 0) {
534 /* can't handle offset */
535 } else if (offset + count > a->m.size_in_bytes) {
536 /* check for offset (and offset+count) too large */
537 } else {
538 /* do a read on the physical device */
539 block_size = a->m.grain;
540 block = offset / block_size;
541 block_count = count / block_size;
542 buffer = address;
543 rtn_value = 1;
544 for (i = 0; i < block_count; i++) {
545 if (ATA_ReadBlock(a->id, &a->info, block_size, block, buffer) == 0) {
546 rtn_value = 0;
547 break;
549 buffer += block_size;
550 block += 1;
553 return rtn_value;
557 long
558 write_ata_media(MEDIA m, long long offset, unsigned long count, void *address)
560 ATA_MEDIA a;
561 long rtn_value;
562 long block;
563 long block_count;
564 long block_size;
565 unsigned char *buffer;
566 int i;
568 a = (ATA_MEDIA) m;
569 rtn_value = 0;
570 if (a == 0) {
571 /* no media */
572 } else if (a->m.kind != ata_mgr.kind) {
573 /* XXX need to error here - this is an internal problem */
574 } else if (count <= 0 || count % a->m.grain != 0) {
575 /* can't handle size */
576 } else if (offset < 0 || offset % a->m.grain != 0) {
577 /* can't handle offset */
578 } else if (offset + count > a->m.size_in_bytes) {
579 /* check for offset (and offset+count) too large */
580 } else {
581 /* do a write on the physical device */
582 block_size = a->m.grain;
583 block = offset / block_size;
584 block_count = count / block_size;
585 buffer = address;
586 rtn_value = 1;
587 for (i = 0; i < block_count; i++) {
588 if (ATA_WriteBlock(a->id, &a->info, block_size, block, buffer) == 0) {
589 rtn_value = 0;
590 break;
592 buffer += block_size;
593 block += 1;
596 return rtn_value;
600 long
601 close_ata_media(MEDIA m)
603 ATA_MEDIA a;
605 a = (ATA_MEDIA) m;
606 if (a == 0) {
607 return 0;
608 } else if (a->m.kind != ata_mgr.kind) {
609 /* XXX need to error here - this is an internal problem */
610 return 0;
612 /* XXX nothing to do - I think? */
613 return 1;
617 long
618 os_reload_ata_media(MEDIA m)
620 printf("Reboot your system so the partition table will be reread.\n");
621 return 1;
626 ATA_ReadBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address)
628 ataIOPB pb;
629 OSErr status;
630 long slave;
631 long lba, cyl, head, sector;
633 clear_memory((void *)&pb, sizeof(pb));
634 pb.ataPBFunctionCode = kATAMgrExecIO;
635 pb.ataPBVers = kATAPBVers1;
636 pb.ataPBDeviceID = deviceID;
637 pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead ;
638 pb.ataPBTimeOut = kATAtimeout;
640 pb.ataPBLogicalBlockSize = block_size;
641 pb.ataPBBuffer = address;
642 pb.ataPBByteCount = block_size;
643 if (info->lba) {
644 lba = 0x40;
645 sector = block & 0xFF;
646 head = (block >> 24) & 0xF;
647 cyl = (block >> 8) & 0xFFFF;
648 } else {
649 lba = 0x00;
650 sector = (block % info->sectors) + 1;
651 cyl = block / info->sectors;
652 head = cyl % info->heads;
653 cyl = cyl / info->heads;
656 pb.ataPBTaskFile.ataTFCount = 1;
657 pb.ataPBTaskFile.ataTFSector = sector;
658 pb.ataPBTaskFile.ataTFCylinder = cyl;
659 if (deviceID & 0x0FF00) {
660 slave = 0x10;
661 } else {
662 slave = 0x0;
664 /* std | L/C | Drive | head */
665 pb.ataPBTaskFile.ataTFSDH = 0xA0 | lba | slave | head;
666 pb.ataPBTaskFile.ataTFCommand = kATAcmdRead;
668 status = ataManager((ataPB*) &pb );
669 if (status != noErr) {
670 /* failure */
671 //printf(" ATA read status = %d\n", status);
672 return 0;
673 } else {
674 return 1;
680 ATA_WriteBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address)
682 ataIOPB pb;
683 OSErr status;
684 long slave;
685 long lba, cyl, head, sector;
687 clear_memory((void *)&pb, sizeof(pb));
688 pb.ataPBFunctionCode = kATAMgrExecIO;
689 pb.ataPBVers = kATAPBVers1;
690 pb.ataPBDeviceID = deviceID;
691 pb.ataPBFlags = mATAFlagTFRead | mATAFlagIOWrite ;
692 pb.ataPBTimeOut = kATAtimeout;
694 pb.ataPBLogicalBlockSize = block_size;
695 pb.ataPBBuffer = address;
696 pb.ataPBByteCount = block_size;
697 if (info->lba) {
698 lba = 0x40;
699 sector = block & 0xFF;
700 head = (block >> 24) & 0xF;
701 cyl = (block >> 8) & 0xFFFF;
702 } else {
703 lba = 0x00;
704 sector = (block % info->sectors) + 1;
705 cyl = block / info->sectors;
706 head = cyl % info->heads;
707 cyl = cyl / info->heads;
709 pb.ataPBTaskFile.ataTFCount = 1;
710 pb.ataPBTaskFile.ataTFSector = sector;
711 pb.ataPBTaskFile.ataTFCylinder = cyl;
712 if (deviceID & 0x0FF00) {
713 slave = 0x10;
714 } else {
715 slave = 0x0;
717 /* std | L/C | Drive | head */
718 pb.ataPBTaskFile.ataTFSDH = 0xA0 | lba | slave | head;
719 pb.ataPBTaskFile.ataTFCommand = kATAcmdWrite;
721 status = ataManager((ataPB*) &pb );
722 if (status != noErr) {
723 /* failure */
724 return 0;
725 } else {
726 return 1;
731 #pragma mark -
735 * ATAPI stuff
737 static long
738 get_pi_info(long id, struct ATAPI_identify_drive_info *ip)
740 ataIdentify pb;
741 OSErr status;
742 long rtn_value;
744 if (sizeof(struct ATAPI_identify_drive_info) < 512) {
745 return 0;
747 clear_memory((void *)ip, sizeof(struct ATAPI_identify_drive_info));
749 clear_memory((void *)&pb, sizeof(pb));
750 pb.ataPBFunctionCode = kATAMgrDriveIdentify;
751 pb.ataPBVers = kATAPBVers1;
752 pb.ataPBDeviceID = id;
753 pb.ataPBFlags = mATAFlagIORead | mATAFlagByteSwap | mATAFlagProtocol1;
754 pb.ataPBTimeOut = kATAtimeout;
755 pb.ataPBBuffer = (void*) ip;
757 status = ataManager((ataPB*) &pb );
759 if (status != noErr) {
760 //printf("get pi info status = %d\n", status);
761 rtn_value = 0;
762 } else {
763 rtn_value = 1;
765 return rtn_value;
769 MEDIA
770 open_atapi_as_media(long bus, long device)
772 ATA_MEDIA a;
773 long id;
774 struct ATAPI_identify_drive_info info;
775 unsigned char *buf;
776 unsigned long block_size;
777 unsigned long blocks;
779 if (ata_inited == 0) {
780 ata_init();
783 if (ata_mgr.exists == 0) {
784 return 0;
787 id = compute_id(bus, device);
789 if (!is_atapi(id)) {
790 a = 0;
792 } else {
793 a = 0;
794 if (get_pi_info(id, &info) != 0
795 && (info.capabilities & LBA_CAPABLE) != 0) {
796 if (ATAPI_TestUnitReady(id) != 0) {
797 a = new_ata_media();
798 if (a != 0) {
799 a->m.kind = ata_mgr.kind;
800 if (ATAPI_ReadCapacity(id, &block_size, &blocks) == 0) {
801 block_size = 2048;
802 blocks = 1000;
804 a->m.grain = block_size;
805 a->m.size_in_bytes = ((long long)blocks) * a->m.grain;
806 a->m.do_read = read_atapi_media;
807 a->m.do_write = write_atapi_media;
808 a->m.do_close = close_ata_media;
809 a->m.do_os_reload = os_reload_ata_media;
810 a->id = id;
812 } else {
813 printf("ATAPI - unit not ready\n");
815 } else {
816 printf("ATAPI - couldn't get info or not LBA capable\n");
819 return (MEDIA) a;
823 long
824 read_atapi_media(MEDIA m, long long offset, unsigned long count, void *address)
826 ATA_MEDIA a;
827 ataIOPB pb;
828 OSErr status;
829 long rtn_value;
830 long block;
831 long block_count;
832 long block_size;
833 unsigned char *buffer;
834 int i;
836 a = (ATA_MEDIA) m;
837 rtn_value = 0;
838 if (a == 0) {
839 /* no media */
840 } else if (a->m.kind != ata_mgr.kind) {
841 /* wrong kind - XXX need to error here - this is an internal problem */
842 } else if (count <= 0 || count % a->m.grain != 0) {
843 /* can't handle size */
844 } else if (offset < 0 || offset % a->m.grain != 0) {
845 /* can't handle offset */
846 } else if (offset + count > a->m.size_in_bytes) {
847 /* check for offset (and offset+count) too large */
848 } else {
849 /* XXX do a read on the physical device */
850 block_size = a->m.grain;
851 block = offset / block_size;
852 block_count = count / block_size;
853 buffer = address;
854 rtn_value = 1;
855 for (i = 0; i < block_count; i++) {
856 if (ATAPI_ReadBlock(a->id, block_size, block, buffer) == 0) {
857 rtn_value = 0;
858 break;
860 buffer += block_size;
861 block += 1;
864 return rtn_value;
868 long
869 write_atapi_media(MEDIA m, long long offset, unsigned long count, void *address)
871 return 0;
876 ATAPI_ReadBlock(UInt32 deviceID, UInt32 block_size, UInt32 block, UInt8 *address)
878 ataIOPB pb;
879 OSErr status;
880 long slave;
881 ATAPICmdPacket cmdPacket;
882 SCSI_10_Byte_Command *gRead;
883 long count;
885 clear_memory((void *)&pb, sizeof(pb));
886 pb.ataPBFunctionCode = kATAMgrExecIO;
887 pb.ataPBVers = kATAPBVers1;
888 pb.ataPBDeviceID = deviceID;
889 pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1;
890 pb.ataPBTimeOut = kATAtimeout;
892 pb.ataPBBuffer = address;
893 pb.ataPBByteCount = block_size;
894 pb.ataPBTaskFile.ataTFCylinder = block_size;
895 if (deviceID & 0x0FF00) {
896 slave = 0x10;
897 } else {
898 slave = 0x0;
900 /* std | L/C | Drive | head */
901 pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave;
902 pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket;
903 pb.ataPBPacketPtr = &cmdPacket;
905 cmdPacket.atapiPacketSize = 16;
906 clear_memory((void *)&cmdPacket.atapiCommandByte, 16);
907 gRead = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0];
909 gRead->opcode = kScsiCmdRead10;
911 gRead->lbn4 = (block >> 24) & 0xFF;
912 gRead->lbn3 = (block >> 16) & 0xFF;
913 gRead->lbn2 = (block >> 8) & 0xFF;
914 gRead->lbn1 = block & 0xFF;
916 count = 1;
917 gRead->len2 = (count >> 8) & 0xFF;
918 gRead->len1 = count & 0xFF;
921 status = ataManager((ataPB*) &pb );
922 if (status != noErr) {
923 /* failure */
924 //printf("ATAPI read status = %d\n", status);
925 return 0;
926 } else {
927 return 1;
933 ATAPI_TestUnitReady(UInt32 deviceID)
935 ataIOPB pb;
936 OSErr status;
937 long slave;
938 ATAPICmdPacket cmdPacket;
939 SCSI_10_Byte_Command *gTestUnit;
941 clear_memory((void *)&pb, sizeof(pb));
942 pb.ataPBFunctionCode = kATAMgrExecIO;
943 pb.ataPBVers = kATAPBVers1;
944 pb.ataPBDeviceID = deviceID;
945 pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1;
946 pb.ataPBTimeOut = kATAtimeout;
948 if (deviceID & 0x0FF00) {
949 slave = 0x10;
950 } else {
951 slave = 0x0;
953 /* std | L/C | Drive | head */
954 pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave;
955 pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket;
956 pb.ataPBPacketPtr = &cmdPacket;
958 cmdPacket.atapiPacketSize = 16;
959 clear_memory((void *)&cmdPacket.atapiCommandByte, 16);
960 gTestUnit = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0];
962 gTestUnit->opcode = kScsiCmdTestUnitReady;
965 status = ataManager((ataPB*) &pb );
966 if (status != noErr) {
967 /* failure */
968 //printf("ATAPI test unit ready status = %d\n", status);
969 return 0;
970 } else {
971 return 1;
977 ATAPI_ReadCapacity(UInt32 deviceID, unsigned long *block_size, unsigned long *blocks)
979 ataIOPB pb;
980 OSErr status;
981 long slave;
982 ATAPICmdPacket cmdPacket;
983 SCSI_10_Byte_Command *gReadCap;
984 struct read_cap_data {
985 long addr;
986 long size;
987 } rcd;
989 clear_memory((void *)&pb, sizeof(pb));
990 pb.ataPBFunctionCode = kATAMgrExecIO;
991 pb.ataPBVers = kATAPBVers1;
992 pb.ataPBDeviceID = deviceID;
993 pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1;
994 pb.ataPBTimeOut = kATAtimeout;
996 pb.ataPBBuffer = (unsigned char *)&rcd;
997 pb.ataPBByteCount = 8;
998 pb.ataPBTaskFile.ataTFCylinder = 8;
999 if (deviceID & 0x0FF00) {
1000 slave = 0x10;
1001 } else {
1002 slave = 0x0;
1004 /* std | L/C | Drive | head */
1005 pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave;
1006 pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket;
1007 pb.ataPBPacketPtr = &cmdPacket;
1009 cmdPacket.atapiPacketSize = 16;
1010 clear_memory((void *)&cmdPacket.atapiCommandByte, 16);
1011 gReadCap = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0];
1013 gReadCap->opcode = kScsiCmdReadCapacity;
1016 status = ataManager((ataPB*) &pb );
1017 if (status != noErr) {
1018 /* failure */
1019 //printf("ATAPI read capacity status = %d\n", status);
1020 return 0;
1021 } else {
1022 *blocks = rcd.addr;
1023 *block_size = rcd.size;
1024 return 1;
1029 MEDIA
1030 ATA_FindDevice(long dRefNum)
1032 ataDrvrRegister pb;
1033 OSErr status;
1035 if (ATAManagerPresent()) {
1036 clear_memory((void *)&pb, sizeof(pb));
1038 pb.ataPBFunctionCode = kATAMgrFindDriverRefnum;
1039 pb.ataPBVers = kATAPBVers1;
1040 pb.ataPBDeviceID = 0xFFFF;
1041 pb.ataPBTimeOut = kATAtimeout;
1043 pb.ataDeviceNextID = 1;
1044 do {
1045 status = ataManager((ataPB*) &pb);
1047 if (status != noErr) {
1048 break;
1049 } else if (pb.ataDrvrRefNum == dRefNum
1050 && pb.ataPBDeviceID != kNoDevice) {
1051 return open_ata_as_media(pb.ataPBDeviceID & 0xFF,
1052 (pb.ataPBDeviceID >> 8) & 0xFF);
1053 } else {
1054 pb.ataPBDeviceID = pb.ataDeviceNextID;
1056 } while (pb.ataPBDeviceID != kNoDevice);
1058 return 0;
1062 #pragma mark -
1065 ATA_MEDIA_ITERATOR
1066 new_ata_iterator(void)
1068 return (ATA_MEDIA_ITERATOR) new_media_iterator(sizeof(struct ATA_media_iterator));
1072 MEDIA_ITERATOR
1073 create_ata_iterator(void)
1075 ATA_MEDIA_ITERATOR a;
1077 if (ata_inited == 0) {
1078 ata_init();
1081 if (ata_mgr.exists == 0) {
1082 return 0;
1085 a = new_ata_iterator();
1086 if (a != 0) {
1087 a->m.kind = ata_mgr.kind;
1088 a->m.state = kInit;
1089 a->m.do_reset = reset_ata_iterator;
1090 a->m.do_step = step_ata_iterator;
1091 a->m.do_delete = delete_ata_iterator;
1092 a->bus_index = 0;
1093 a->bus = 0;
1094 a->id = 0;
1097 return (MEDIA_ITERATOR) a;
1101 void
1102 reset_ata_iterator(MEDIA_ITERATOR m)
1104 ATA_MEDIA_ITERATOR a;
1106 a = (ATA_MEDIA_ITERATOR) m;
1107 if (a == 0) {
1108 /* no media */
1109 } else if (a->m.kind != ata_mgr.kind) {
1110 /* wrong kind - XXX need to error here - this is an internal problem */
1111 } else if (a->m.state != kInit) {
1112 a->m.state = kReset;
1117 char *
1118 step_ata_iterator(MEDIA_ITERATOR m)
1120 ATA_MEDIA_ITERATOR a;
1121 char *result;
1123 a = (ATA_MEDIA_ITERATOR) m;
1124 if (a == 0) {
1125 /* no media */
1126 } else if (a->m.kind != ata_mgr.kind) {
1127 /* wrong kind - XXX need to error here - this is an internal problem */
1128 } else {
1129 switch (a->m.state) {
1130 case kInit:
1131 /* find # of buses (done in ata_init) */
1132 a->m.state = kReset;
1133 /* fall through to reset */
1134 case kReset:
1135 a->bus_index = 0 /* low bus id */;
1136 a->bus = ata_mgr.bus_list[a->bus_index];
1137 a->id = 0 /* low device id */;
1138 a->m.state = kIterating;
1139 /* fall through to iterate */
1140 case kIterating:
1141 while (1) {
1142 if (a->bus_index >= ata_mgr.busCount/* max bus id */) {
1143 break;
1145 if (a->id > 1 /*max id for bus */) {
1146 a->bus_index += 1;
1147 a->bus = ata_mgr.bus_list[a->bus_index];
1148 a->id = 0 /* low device id */;
1149 continue; /* try again */
1151 if (a->bus > 9) {
1152 // insure that name creation works
1153 break;
1155 /* generate result */
1156 result = (char *) malloc(20);
1157 if (result != NULL) {
1158 snprintf(result, 20, "/dev/ata%c.%c",
1159 '0'+a->bus, '0'+a->id);
1162 a->id += 1; /* next id */
1163 return result;
1165 a->m.state = kEnd;
1166 /* fall through to end */
1167 case kEnd:
1168 default:
1169 break;
1172 return 0 /* no entry */;
1176 void
1177 delete_ata_iterator(MEDIA_ITERATOR m)
1179 return;
1183 #pragma mark -
1186 #ifdef notdef
1187 MEDIA
1188 open_linux_ata_as_media(long index)
1190 long bus;
1191 long id;
1192 long i;
1194 i = index / 2;
1195 if (i >= ata_mgr.busCount) {
1196 // set bogus id
1197 bus = 0;
1198 id = 2;
1199 } else {
1200 bus = ata_mgr.bus_list[index / 2];
1201 id = index % 2;
1204 return open_ata_as_media(bus, id);
1207 #else
1209 MEDIA
1210 open_linux_ata_as_media(long index)
1212 long bus;
1213 long id;
1215 bus = index / 2;
1216 id = index % 2;
1218 return open_ata_as_media(bus, id);
1220 #endif
1223 char *
1224 linux_ata_name(long bus, long id)
1226 char *result;
1228 if (bus >= 13) {
1229 // a bus >= 13 would be a bogus character
1230 return NULL;
1232 result = (char *) malloc(20);
1233 if (result != NULL) {
1234 /* name is hda, hdb, hdc, hdd, ...
1235 * in order (0,0) (0,1) (1,0) (1,1) ...
1237 snprintf(result, 20, "/dev/hd%c", 'a' + (bus*2 + id));
1239 return result;