1 1.1 christos /* 2 1.1 christos * SCSI_media.c - 3 1.1 christos * 4 1.1 christos * Written by Eryk Vershen 5 1.1 christos */ 6 1.1 christos 7 1.1 christos /* 8 1.1 christos * Copyright 1997,1998 by Apple Computer, Inc. 9 1.1 christos * All Rights Reserved 10 1.1 christos * 11 1.1 christos * Permission to use, copy, modify, and distribute this software and 12 1.1 christos * its documentation for any purpose and without fee is hereby granted, 13 1.1 christos * provided that the above copyright notice appears in all copies and 14 1.1 christos * that both the copyright notice and this permission notice appear in 15 1.1 christos * supporting documentation. 16 1.1 christos * 17 1.1 christos * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 18 1.1 christos * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 1.1 christos * FOR A PARTICULAR PURPOSE. 20 1.1 christos * 21 1.1 christos * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 22 1.1 christos * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 23 1.1 christos * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 24 1.1 christos * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 25 1.1 christos * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 26 1.1 christos */ 27 1.1 christos 28 1.1 christos 29 1.1 christos // for printf() & sprintf() 30 1.1 christos #include <stdio.h> 31 1.1 christos // for malloc() & free() 32 1.1 christos #include <stdlib.h> 33 1.1 christos #include "DoSCSICommand.h" 34 1.1 christos #include "SCSI_media.h" 35 1.1 christos #include "util.h" 36 1.1 christos 37 1.1 christos 38 1.1 christos /* 39 1.1 christos * Defines 40 1.1 christos */ 41 1.2 christos #define DriverRefNumToSCSI(x) ((int16_t) (~(x) - 32)) 42 1.1 christos 43 1.1 christos 44 1.1 christos /* 45 1.1 christos * Types 46 1.1 christos */ 47 1.1 christos typedef struct SCSI_media *SCSI_MEDIA; 48 1.1 christos 49 1.1 christos struct SCSI_media { 50 1.1 christos struct media m; 51 1.1 christos long bus; 52 1.1 christos long id; 53 1.1 christos }; 54 1.1 christos 55 1.1 christos struct bus_entry { 56 1.1 christos long bus; 57 1.1 christos long sort_value; 58 1.1 christos long max_id; 59 1.1 christos long master_id; 60 1.1 christos }; 61 1.1 christos 62 1.1 christos struct SCSI_manager { 63 1.1 christos long exists; 64 1.1 christos long kind; 65 1.1 christos long bus_count; 66 1.1 christos struct bus_entry *bus_list; 67 1.1 christos }; 68 1.1 christos 69 1.1 christos typedef struct SCSI_media_iterator *SCSI_MEDIA_ITERATOR; 70 1.1 christos 71 1.1 christos struct SCSI_media_iterator { 72 1.1 christos struct media_iterator m; 73 1.1 christos long bus_index; 74 1.1 christos long bus; 75 1.1 christos long id; 76 1.1 christos }; 77 1.1 christos 78 1.1 christos struct linux_order_cache { 79 1.1 christos struct cache_item *first; 80 1.1 christos struct cache_item *last; 81 1.1 christos long next_disk; 82 1.1 christos long next_cdrom; 83 1.1 christos long loaded; 84 1.1 christos }; 85 1.1 christos 86 1.1 christos struct cache_item { 87 1.1 christos struct cache_item *next; 88 1.1 christos long bus; 89 1.1 christos long id; 90 1.1 christos long value; 91 1.1 christos long is_cdrom; 92 1.1 christos long unsure; 93 1.1 christos }; 94 1.1 christos 95 1.1 christos 96 1.1 christos /* 97 1.1 christos * Global Constants 98 1.1 christos */ 99 1.1 christos enum { 100 1.1 christos kNoDevice = 0x00FF 101 1.1 christos }; 102 1.1 christos 103 1.1 christos enum { 104 1.1 christos kRequiredSCSIinquiryLength = 36 105 1.1 christos }; 106 1.1 christos 107 1.1 christos 108 1.1 christos /* 109 1.1 christos * Global Variables 110 1.1 christos */ 111 1.1 christos static long scsi_inited = 0; 112 1.1 christos static struct SCSI_manager scsi_mgr; 113 1.1 christos static struct linux_order_cache linux_order; 114 1.1 christos 115 1.1 christos 116 1.1 christos /* 117 1.1 christos * Forward declarations 118 1.1 christos */ 119 1.1 christos int AsyncSCSIPresent(void); 120 1.1 christos void scsi_init(void); 121 1.1 christos SCSI_MEDIA new_scsi_media(void); 122 1.2 christos long read_scsi_media(MEDIA m, long long offset, uint32_t count, void *address); 123 1.2 christos long write_scsi_media(MEDIA m, long long offset, uint32_t count, void *address); 124 1.1 christos long close_scsi_media(MEDIA m); 125 1.1 christos long os_reload_scsi_media(MEDIA m); 126 1.1 christos long compute_id(long bus, long device); 127 1.1 christos int SCSI_ReadBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address); 128 1.1 christos int SCSI_WriteBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address); 129 1.1 christos int DoTestUnitReady(UInt8 targetID, int bus); 130 1.1 christos int DoReadCapacity(UInt32 id, UInt32 bus, UInt32 *blockCount, UInt32 *blockSize); 131 1.1 christos SCSI_MEDIA_ITERATOR new_scsi_iterator(void); 132 1.1 christos void reset_scsi_iterator(MEDIA_ITERATOR m); 133 1.1 christos char *step_scsi_iterator(MEDIA_ITERATOR m); 134 1.1 christos void delete_scsi_iterator(MEDIA_ITERATOR m); 135 1.1 christos void fill_bus_entry(struct bus_entry *entry, long bus); 136 1.1 christos /*long get_bus_sort_value(long bus);*/ 137 1.1 christos int bus_entry_compare(const void* a, const void* b); 138 1.1 christos int DoInquiry(UInt32 id, UInt32 bus, UInt32 *devType); 139 1.1 christos void probe_all(void); 140 1.1 christos void probe_scsi_device(long bus, long id, int unsure); 141 1.1 christos long lookup_scsi_device(long bus, long id, int *is_cdrom, int *unsure); 142 1.1 christos long lookup_scsi_index(long index, int is_cdrom, long *bus, long *id); 143 1.1 christos void add_to_cache(long bus, long id, int is_cdrom, int unsure); 144 1.1 christos void init_linux_cache(void); 145 1.1 christos void clear_linux_cache(void); 146 1.1 christos void mark_linux_cache_loaded(void); 147 1.1 christos int linux_cache_loaded(void); 148 1.1 christos 149 1.1 christos 150 1.1 christos /* 151 1.1 christos * Routines 152 1.1 christos */ 153 1.1 christos int 154 1.1 christos AsyncSCSIPresent(void) 155 1.1 christos { 156 1.1 christos return (TrapAvailable(_SCSIAtomic)); 157 1.1 christos } 158 1.1 christos 159 1.1 christos 160 1.1 christos void 161 1.1 christos scsi_init(void) 162 1.1 christos { 163 1.1 christos int i; 164 1.1 christos int old_scsi; 165 1.1 christos 166 1.1 christos if (scsi_inited != 0) { 167 1.1 christos return; 168 1.1 christos } 169 1.1 christos scsi_inited = 1; 170 1.1 christos 171 1.1 christos scsi_mgr.exists = 1; 172 1.1 christos scsi_mgr.kind = allocate_media_kind(); 173 1.1 christos 174 1.1 christos if (AsyncSCSIPresent()) { 175 1.1 christos AllocatePB(); 176 1.1 christos 177 1.1 christos scsi_mgr.bus_count = gSCSIHiBusID + 1; 178 1.1 christos old_scsi = 0; 179 1.1 christos } else { 180 1.1 christos scsi_mgr.bus_count = 1; 181 1.1 christos old_scsi = 1; 182 1.1 christos } 183 1.1 christos 184 1.1 christos scsi_mgr.bus_list = (struct bus_entry *) 185 1.1 christos calloc(scsi_mgr.bus_count, sizeof(struct bus_entry)); 186 1.1 christos 187 1.1 christos if (scsi_mgr.bus_list == 0) { 188 1.1 christos scsi_mgr.bus_count = 0; 189 1.1 christos } else { 190 1.1 christos for (i = 0; i < scsi_mgr.bus_count; i++) { 191 1.1 christos if (old_scsi) { 192 1.1 christos scsi_mgr.bus_list[i].bus = 0xFF; 193 1.1 christos } else { 194 1.1 christos scsi_mgr.bus_list[i].bus = i; 195 1.1 christos } 196 1.1 christos fill_bus_entry(&scsi_mgr.bus_list[i], i); 197 1.1 christos } 198 1.1 christos qsort((void *)scsi_mgr.bus_list, /* address of array */ 199 1.1 christos scsi_mgr.bus_count, /* number of elements */ 200 1.1 christos sizeof(struct bus_entry), /* size of element */ 201 1.1 christos bus_entry_compare); /* element comparison routine */ 202 1.1 christos } 203 1.1 christos 204 1.1 christos init_linux_cache(); 205 1.1 christos } 206 1.1 christos 207 1.1 christos void 208 1.1 christos fill_bus_entry(struct bus_entry *entry, long bus) 209 1.1 christos { 210 1.1 christos OSErr status; 211 1.1 christos SCSIBusInquiryPB pb; 212 1.1 christos long len; 213 1.1 christos long result; 214 1.1 christos long x, y; 215 1.1 christos 216 1.1 christos if (!AsyncSCSIPresent()) { 217 1.1 christos entry->sort_value = 0; 218 1.1 christos entry->max_id = 7; 219 1.1 christos entry->master_id = 7; 220 1.1 christos return; 221 1.1 christos } 222 1.1 christos len = sizeof(SCSIBusInquiryPB); 223 1.1 christos clear_memory((Ptr) &pb, len); 224 1.1 christos pb.scsiPBLength = len; 225 1.1 christos pb.scsiFunctionCode = SCSIBusInquiry; 226 1.1 christos pb.scsiDevice.bus = bus; 227 1.1 christos status = SCSIAction((SCSI_PB *) &pb); 228 1.1 christos if (status != noErr) { 229 1.1 christos result = 6; 230 1.1 christos } else { 231 1.1 christos switch (pb.scsiHBAslotType) { 232 1.1 christos case scsiMotherboardBus: x = 0; break; 233 1.1 christos case scsiPDSBus: x = 1; break; 234 1.1 christos case scsiNuBus: x = 2; break; 235 1.1 christos case scsiPCIBus: x = 3; break; 236 1.1 christos case scsiFireWireBridgeBus: x = 4; break; 237 1.1 christos case scsiPCMCIABus: x = 5; break; 238 1.1 christos default: x = 7 + pb.scsiHBAslotType; break; 239 1.1 christos }; 240 1.1 christos 241 1.1 christos switch (pb.scsiFeatureFlags & scsiBusInternalExternalMask) { 242 1.1 christos case scsiBusInternal: y = 0; break; 243 1.1 christos case scsiBusInternalExternal: y = 1; break; 244 1.1 christos case scsiBusExternal: y = 2; break; 245 1.1 christos default: 246 1.1 christos case scsiBusInternalExternalUnknown: y = 3; break; 247 1.1 christos }; 248 1.1 christos result = x * 4 + y; 249 1.1 christos } 250 1.1 christos entry->sort_value = result; 251 1.1 christos entry->max_id = pb.scsiMaxLUN; 252 1.1 christos entry->master_id = pb.scsiInitiatorID; 253 1.1 christos } 254 1.1 christos 255 1.1 christos 256 1.1 christos int 257 1.1 christos bus_entry_compare(const void* a, const void* b) 258 1.1 christos { 259 1.1 christos long result; 260 1.1 christos 261 1.1 christos const struct bus_entry *x = (const struct bus_entry *) a; 262 1.1 christos const struct bus_entry *y = (const struct bus_entry *) b; 263 1.1 christos 264 1.1 christos result = x->sort_value - y->sort_value; 265 1.1 christos if (result == 0) { 266 1.1 christos result = x->bus - y->bus; 267 1.1 christos } 268 1.1 christos return result; 269 1.1 christos } 270 1.1 christos 271 1.1 christos 272 1.1 christos SCSI_MEDIA 273 1.1 christos new_scsi_media(void) 274 1.1 christos { 275 1.1 christos return (SCSI_MEDIA) new_media(sizeof(struct SCSI_media)); 276 1.1 christos } 277 1.1 christos 278 1.1 christos 279 1.1 christos MEDIA 280 1.1 christos open_old_scsi_as_media(long device) 281 1.1 christos { 282 1.1 christos return open_scsi_as_media(kOriginalSCSIBusAdaptor, device); 283 1.1 christos } 284 1.1 christos 285 1.1 christos 286 1.1 christos MEDIA 287 1.1 christos open_scsi_as_media(long bus, long device) 288 1.1 christos { 289 1.1 christos SCSI_MEDIA a; 290 1.1 christos UInt32 blockCount; 291 1.1 christos UInt32 blockSize; 292 1.1 christos 293 1.1 christos if (scsi_inited == 0) { 294 1.1 christos scsi_init(); 295 1.1 christos } 296 1.1 christos 297 1.1 christos if (scsi_mgr.exists == 0) { 298 1.1 christos return 0; 299 1.1 christos } 300 1.1 christos 301 1.1 christos a = 0; 302 1.1 christos if (DoTestUnitReady(device, bus) > 0) { 303 1.1 christos if (DoReadCapacity(device, bus, &blockCount, &blockSize) != 0) { 304 1.1 christos a = new_scsi_media(); 305 1.1 christos if (a != 0) { 306 1.1 christos a->m.kind = scsi_mgr.kind; 307 1.1 christos a->m.grain = blockSize; 308 1.1 christos a->m.size_in_bytes = ((long long)blockCount) * blockSize; 309 1.1 christos a->m.do_read = read_scsi_media; 310 1.1 christos a->m.do_write = write_scsi_media; 311 1.1 christos a->m.do_close = close_scsi_media; 312 1.1 christos a->m.do_os_reload = os_reload_scsi_media; 313 1.1 christos a->bus = bus; 314 1.1 christos a->id = device; 315 1.1 christos } 316 1.1 christos } 317 1.1 christos } 318 1.1 christos return (MEDIA) a; 319 1.1 christos } 320 1.1 christos 321 1.1 christos 322 1.1 christos long 323 1.2 christos read_scsi_media(MEDIA m, long long offset, uint32_t count, void *address) 324 1.1 christos { 325 1.1 christos SCSI_MEDIA a; 326 1.1 christos long rtn_value; 327 1.1 christos long block; 328 1.1 christos long block_count; 329 1.1 christos long block_size; 330 1.2 christos uint8_t *buffer; 331 1.1 christos int i; 332 1.1 christos 333 1.1 christos block = (long) offset; 334 1.1 christos //printf("scsi %d count %d\n", block, count); 335 1.1 christos a = (SCSI_MEDIA) m; 336 1.1 christos rtn_value = 0; 337 1.1 christos if (a == 0) { 338 1.1 christos /* no media */ 339 1.1 christos } else if (a->m.kind != scsi_mgr.kind) { 340 1.1 christos /* wrong kind - XXX need to error here - this is an internal problem */ 341 1.1 christos } else if (count <= 0 || count % a->m.grain != 0) { 342 1.1 christos /* can't handle size */ 343 1.1 christos } else if (offset < 0 || offset % a->m.grain != 0) { 344 1.1 christos /* can't handle offset */ 345 1.1 christos } else if (offset + count > a->m.size_in_bytes) { 346 1.1 christos /* check for offset (and offset+count) too large */ 347 1.1 christos } else { 348 1.1 christos /* XXX do a read on the physical device */ 349 1.1 christos block_size = a->m.grain; 350 1.1 christos block = offset / block_size; 351 1.1 christos block_count = count / block_size; 352 1.1 christos buffer = address; 353 1.1 christos rtn_value = 1; 354 1.1 christos for (i = 0; i < block_count; i++) { 355 1.1 christos if (SCSI_ReadBlock(a->id, a->bus, block_size, block, buffer) == 0) { 356 1.1 christos rtn_value = 0; 357 1.1 christos break; 358 1.1 christos } 359 1.1 christos buffer += block_size; 360 1.1 christos block += 1; 361 1.1 christos } 362 1.1 christos } 363 1.1 christos return rtn_value; 364 1.1 christos } 365 1.1 christos 366 1.1 christos 367 1.1 christos long 368 1.2 christos write_scsi_media(MEDIA m, long long offset, uint32_t count, void *address) 369 1.1 christos { 370 1.1 christos SCSI_MEDIA a; 371 1.1 christos long rtn_value; 372 1.1 christos long block; 373 1.1 christos long block_count; 374 1.1 christos long block_size; 375 1.2 christos uint8_t *buffer; 376 1.1 christos int i; 377 1.1 christos 378 1.1 christos a = (SCSI_MEDIA) m; 379 1.1 christos rtn_value = 0; 380 1.1 christos if (a == 0) { 381 1.1 christos /* no media */ 382 1.1 christos } else if (a->m.kind != scsi_mgr.kind) { 383 1.1 christos /* XXX need to error here - this is an internal problem */ 384 1.1 christos } else if (count <= 0 || count % a->m.grain != 0) { 385 1.1 christos /* can't handle size */ 386 1.1 christos } else if (offset < 0 || offset % a->m.grain != 0) { 387 1.1 christos /* can't handle offset */ 388 1.1 christos } else if (offset + count > a->m.size_in_bytes) { 389 1.1 christos /* check for offset (and offset+count) too large */ 390 1.1 christos } else { 391 1.1 christos /* XXX do a write on the physical device */ 392 1.1 christos block_size = a->m.grain; 393 1.1 christos block = offset / block_size; 394 1.1 christos block_count = count / block_size; 395 1.1 christos buffer = address; 396 1.1 christos rtn_value = 1; 397 1.1 christos for (i = 0; i < block_count; i++) { 398 1.1 christos if (SCSI_WriteBlock(a->id, a->bus, block_size, block, buffer) == 0) { 399 1.1 christos rtn_value = 0; 400 1.1 christos break; 401 1.1 christos } 402 1.1 christos buffer += block_size; 403 1.1 christos block += 1; 404 1.1 christos } 405 1.1 christos } 406 1.1 christos return rtn_value; 407 1.1 christos } 408 1.1 christos 409 1.1 christos 410 1.1 christos long 411 1.1 christos close_scsi_media(MEDIA m) 412 1.1 christos { 413 1.1 christos SCSI_MEDIA a; 414 1.1 christos 415 1.1 christos a = (SCSI_MEDIA) m; 416 1.1 christos if (a == 0) { 417 1.1 christos return 0; 418 1.1 christos } else if (a->m.kind != scsi_mgr.kind) { 419 1.1 christos /* XXX need to error here - this is an internal problem */ 420 1.1 christos return 0; 421 1.1 christos } 422 1.1 christos /* XXX nothing to do - I think? */ 423 1.1 christos return 1; 424 1.1 christos } 425 1.1 christos 426 1.1 christos 427 1.1 christos long 428 1.1 christos os_reload_scsi_media(MEDIA m) 429 1.1 christos { 430 1.1 christos printf("Reboot your system so the partition table will be reread.\n"); 431 1.1 christos return 1; 432 1.1 christos } 433 1.1 christos 434 1.1 christos 435 1.1 christos #pragma mark - 436 1.1 christos 437 1.1 christos 438 1.1 christos int 439 1.1 christos DoTestUnitReady(UInt8 targetID, int bus) 440 1.1 christos { 441 1.1 christos OSErr status; 442 1.1 christos Str255 errorText; 443 1.1 christos char* msg; 444 1.1 christos static const SCSI_6_Byte_Command gTestUnitReadyCommand = { 445 1.1 christos kScsiCmdTestUnitReady, 0, 0, 0, 0, 0 446 1.1 christos }; 447 1.1 christos SCSI_Sense_Data senseData; 448 1.1 christos DeviceIdent scsiDevice; 449 1.1 christos int rtn_value; 450 1.1 christos 451 1.1 christos scsiDevice.diReserved = 0; 452 1.1 christos scsiDevice.bus = bus; 453 1.1 christos scsiDevice.targetID = targetID; 454 1.1 christos scsiDevice.LUN = 0; 455 1.1 christos 456 1.1 christos status = DoSCSICommand( 457 1.1 christos scsiDevice, 458 1.1 christos "\pTest Unit Ready", 459 1.1 christos (SCSI_CommandPtr) &gTestUnitReadyCommand, 460 1.1 christos NULL, 461 1.1 christos 0, 462 1.1 christos scsiDirectionNone, 463 1.1 christos NULL, 464 1.1 christos &senseData, 465 1.1 christos errorText 466 1.1 christos ); 467 1.1 christos if (status == scsiNonZeroStatus) { 468 1.1 christos rtn_value = -1; 469 1.1 christos } else if (status != noErr) { 470 1.1 christos rtn_value = 0; 471 1.1 christos } else { 472 1.1 christos rtn_value = 1; 473 1.1 christos } 474 1.1 christos return rtn_value; 475 1.1 christos } 476 1.1 christos 477 1.1 christos 478 1.1 christos int 479 1.1 christos SCSI_ReadBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address) 480 1.1 christos { 481 1.1 christos OSErr status; 482 1.1 christos Str255 errorText; 483 1.1 christos char* msg; 484 1.1 christos static SCSI_10_Byte_Command gReadCommand = { 485 1.1 christos kScsiCmdRead10, 0, 0, 0, 0, 0, 0, 0, 0, 0 486 1.1 christos }; 487 1.1 christos SCSI_Sense_Data senseData; 488 1.1 christos DeviceIdent scsiDevice; 489 1.1 christos int rtn_value; 490 1.1 christos long count; 491 1.1 christos 492 1.1 christos //printf("scsi read %d:%d block %d size %d\n", bus, id, block, block_size); 493 1.1 christos scsiDevice.diReserved = 0; 494 1.1 christos scsiDevice.bus = bus; 495 1.1 christos scsiDevice.targetID = id; 496 1.1 christos scsiDevice.LUN = 0; 497 1.1 christos 498 1.1 christos gReadCommand.lbn4 = (block >> 24) & 0xFF; 499 1.1 christos gReadCommand.lbn3 = (block >> 16) & 0xFF; 500 1.1 christos gReadCommand.lbn2 = (block >> 8) & 0xFF; 501 1.1 christos gReadCommand.lbn1 = block & 0xFF; 502 1.1 christos 503 1.1 christos count = 1; 504 1.1 christos gReadCommand.len2 = (count >> 8) & 0xFF; 505 1.1 christos gReadCommand.len1 = count & 0xFF; 506 1.1 christos 507 1.1 christos status = DoSCSICommand( 508 1.1 christos scsiDevice, 509 1.1 christos "\pRead", 510 1.1 christos (SCSI_CommandPtr) &gReadCommand, 511 1.1 christos (Ptr) address, 512 1.1 christos count * block_size, 513 1.1 christos scsiDirectionIn, 514 1.1 christos NULL, 515 1.1 christos &senseData, 516 1.1 christos errorText 517 1.1 christos ); 518 1.1 christos if (status == noErr) { 519 1.1 christos rtn_value = 1; 520 1.1 christos } else { 521 1.1 christos rtn_value = 0; 522 1.1 christos } 523 1.1 christos return rtn_value; 524 1.1 christos } 525 1.1 christos 526 1.1 christos 527 1.1 christos int 528 1.1 christos SCSI_WriteBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address) 529 1.1 christos { 530 1.1 christos OSErr status; 531 1.1 christos Str255 errorText; 532 1.1 christos char* msg; 533 1.1 christos static SCSI_10_Byte_Command gWriteCommand = { 534 1.1 christos kScsiCmdWrite10, 0, 0, 0, 0, 0, 0, 0, 0, 0 535 1.1 christos }; 536 1.1 christos SCSI_Sense_Data senseData; 537 1.1 christos DeviceIdent scsiDevice; 538 1.1 christos int rtn_value; 539 1.1 christos long count; 540 1.1 christos 541 1.1 christos scsiDevice.diReserved = 0; 542 1.1 christos scsiDevice.bus = bus; 543 1.1 christos scsiDevice.targetID = id; 544 1.1 christos scsiDevice.LUN = 0; 545 1.1 christos 546 1.1 christos gWriteCommand.lbn4 = (block >> 24) & 0xFF; 547 1.1 christos gWriteCommand.lbn3 = (block >> 16) & 0xFF; 548 1.1 christos gWriteCommand.lbn2 = (block >> 8) & 0xFF; 549 1.1 christos gWriteCommand.lbn1 = block & 0xFF; 550 1.1 christos 551 1.1 christos count = 1; 552 1.1 christos gWriteCommand.len2 = (count >> 8) & 0xFF; 553 1.1 christos gWriteCommand.len1 = count & 0xFF; 554 1.1 christos 555 1.1 christos status = DoSCSICommand( 556 1.1 christos scsiDevice, 557 1.1 christos "\pWrite", 558 1.1 christos (SCSI_CommandPtr) &gWriteCommand, 559 1.1 christos (Ptr) address, 560 1.1 christos count * block_size, 561 1.1 christos scsiDirectionOut, 562 1.1 christos NULL, 563 1.1 christos &senseData, 564 1.1 christos errorText 565 1.1 christos ); 566 1.1 christos if (status == noErr) { 567 1.1 christos rtn_value = 1; 568 1.1 christos } else { 569 1.1 christos rtn_value = 0; 570 1.1 christos } 571 1.1 christos return rtn_value; 572 1.1 christos } 573 1.1 christos 574 1.1 christos 575 1.1 christos int 576 1.1 christos DoReadCapacity(UInt32 id, UInt32 bus, UInt32 *blockCount, UInt32 *blockSize) 577 1.1 christos { 578 1.1 christos OSErr status; 579 1.1 christos Str255 errorText; 580 1.1 christos static const SCSI_10_Byte_Command gCapacityCommand = { 581 1.1 christos kScsiCmdReadCapacity, 0, 0, 0, 0, 0, 0, 0, 0, 0 582 1.1 christos }; 583 1.1 christos SCSI_Sense_Data senseData; 584 1.1 christos DeviceIdent scsiDevice; 585 1.1 christos SCSI_Capacity_Data capacityData; 586 1.1 christos UInt32 temp; 587 1.1 christos int rtn_value; 588 1.1 christos 589 1.1 christos scsiDevice.diReserved = 0; 590 1.1 christos scsiDevice.bus = bus; 591 1.1 christos scsiDevice.targetID = id; 592 1.1 christos scsiDevice.LUN = 0; 593 1.1 christos 594 1.1 christos CLEAR(capacityData); 595 1.1 christos 596 1.1 christos status = DoSCSICommand( 597 1.1 christos scsiDevice, 598 1.1 christos "\pRead Capacity", 599 1.1 christos (SCSI_CommandPtr) &gCapacityCommand, 600 1.1 christos (Ptr) &capacityData, 601 1.1 christos sizeof (SCSI_Capacity_Data), 602 1.1 christos scsiDirectionIn, 603 1.1 christos NULL, 604 1.1 christos &senseData, 605 1.1 christos errorText 606 1.1 christos ); 607 1.1 christos 608 1.1 christos if (status == noErr) { 609 1.1 christos temp = capacityData.lbn4; 610 1.1 christos temp = (temp << 8) | capacityData.lbn3; 611 1.1 christos temp = (temp << 8) | capacityData.lbn2; 612 1.1 christos temp = (temp << 8) | capacityData.lbn1; 613 1.1 christos *blockCount = temp; 614 1.1 christos 615 1.1 christos temp = capacityData.len4; 616 1.1 christos temp = (temp << 8) | capacityData.len3; 617 1.1 christos temp = (temp << 8) | capacityData.len2; 618 1.1 christos temp = (temp << 8) | capacityData.len1; 619 1.1 christos *blockSize = temp; 620 1.1 christos 621 1.1 christos rtn_value = 1; 622 1.1 christos } else { 623 1.1 christos rtn_value = 0; 624 1.1 christos } 625 1.1 christos return rtn_value; 626 1.1 christos } 627 1.1 christos 628 1.1 christos 629 1.1 christos int 630 1.1 christos DoInquiry(UInt32 id, UInt32 bus, UInt32 *devType) 631 1.1 christos { 632 1.1 christos OSErr status; 633 1.1 christos Str255 errorText; 634 1.1 christos static const SCSI_6_Byte_Command gInquiryCommand = { 635 1.1 christos kScsiCmdInquiry, 0, 0, 0, kRequiredSCSIinquiryLength, 0 636 1.1 christos }; 637 1.1 christos SCSI_Sense_Data senseData; 638 1.1 christos DeviceIdent scsiDevice; 639 1.1 christos SCSI_Inquiry_Data inquiryData; 640 1.1 christos UInt32 temp; 641 1.1 christos int rtn_value; 642 1.1 christos 643 1.1 christos scsiDevice.diReserved = 0; 644 1.1 christos scsiDevice.bus = bus; 645 1.1 christos scsiDevice.targetID = id; 646 1.1 christos scsiDevice.LUN = 0; 647 1.1 christos 648 1.1 christos CLEAR(inquiryData); 649 1.1 christos 650 1.1 christos status = DoSCSICommand( 651 1.1 christos scsiDevice, 652 1.1 christos "\pInquiry", 653 1.1 christos (SCSI_CommandPtr) &gInquiryCommand, 654 1.1 christos (Ptr) &inquiryData, 655 1.1 christos kRequiredSCSIinquiryLength, 656 1.1 christos scsiDirectionIn, 657 1.1 christos NULL, 658 1.1 christos &senseData, 659 1.1 christos errorText 660 1.1 christos ); 661 1.1 christos 662 1.1 christos if (status == noErr) { 663 1.1 christos *devType = inquiryData.devType & kScsiDevTypeMask; 664 1.1 christos rtn_value = 1; 665 1.1 christos } else { 666 1.1 christos rtn_value = 0; 667 1.1 christos } 668 1.1 christos return rtn_value; 669 1.1 christos } 670 1.1 christos 671 1.1 christos 672 1.1 christos MEDIA 673 1.1 christos SCSI_FindDevice(long dRefNum) 674 1.1 christos { 675 1.1 christos SCSIDriverPB pb; 676 1.1 christos OSErr status; 677 1.1 christos short targetID; 678 1.1 christos 679 1.1 christos status = nsvErr; 680 1.1 christos if (AsyncSCSIPresent()) { 681 1.1 christos clear_memory((Ptr) &pb, sizeof pb); 682 1.1 christos 683 1.1 christos pb.scsiPBLength = sizeof (SCSIDriverPB); 684 1.1 christos pb.scsiCompletion = NULL; 685 1.1 christos pb.scsiFlags = 0; 686 1.1 christos pb.scsiFunctionCode = SCSILookupRefNumXref; 687 1.1 christos pb.scsiDevice.bus = kNoDevice; /* was *((long *) &pb.scsiDevice) = 0xFFFFFFFFL; */ 688 1.1 christos 689 1.1 christos do { 690 1.1 christos status = SCSIAction((SCSI_PB *) &pb); 691 1.1 christos 692 1.1 christos if (status != noErr) { 693 1.1 christos break; 694 1.1 christos } else if (pb.scsiDriver == dRefNum 695 1.1 christos && pb.scsiDevice.bus != kNoDevice) { 696 1.1 christos return open_scsi_as_media(pb.scsiDevice.bus, pb.scsiDevice.targetID); 697 1.1 christos 698 1.1 christos } else { 699 1.1 christos pb.scsiDevice = pb.scsiNextDevice; 700 1.1 christos } 701 1.1 christos } 702 1.1 christos while (pb.scsiDevice.bus != kNoDevice); 703 1.1 christos } 704 1.1 christos if (status == nsvErr) { 705 1.1 christos /* 706 1.1 christos * The asynchronous SCSI Manager is missing or the 707 1.1 christos * driver didn't register with the SCSI Manager.*/ 708 1.1 christos targetID = DriverRefNumToSCSI(dRefNum); 709 1.1 christos if (targetID >= 0 && targetID <= 6) { 710 1.1 christos return open_old_scsi_as_media(targetID); 711 1.1 christos } 712 1.1 christos } 713 1.1 christos return 0; 714 1.1 christos } 715 1.1 christos 716 1.1 christos 717 1.1 christos #pragma mark - 718 1.1 christos 719 1.1 christos 720 1.1 christos SCSI_MEDIA_ITERATOR 721 1.1 christos new_scsi_iterator(void) 722 1.1 christos { 723 1.1 christos return (SCSI_MEDIA_ITERATOR) new_media_iterator(sizeof(struct SCSI_media_iterator)); 724 1.1 christos } 725 1.1 christos 726 1.1 christos 727 1.1 christos MEDIA_ITERATOR 728 1.1 christos create_scsi_iterator(void) 729 1.1 christos { 730 1.1 christos SCSI_MEDIA_ITERATOR a; 731 1.1 christos 732 1.1 christos if (scsi_inited == 0) { 733 1.1 christos scsi_init(); 734 1.1 christos } 735 1.1 christos 736 1.1 christos if (scsi_mgr.exists == 0) { 737 1.1 christos return 0; 738 1.1 christos } 739 1.1 christos 740 1.1 christos a = new_scsi_iterator(); 741 1.1 christos if (a != 0) { 742 1.1 christos a->m.kind = scsi_mgr.kind; 743 1.1 christos a->m.state = kInit; 744 1.1 christos a->m.do_reset = reset_scsi_iterator; 745 1.1 christos a->m.do_step = step_scsi_iterator; 746 1.1 christos a->m.do_delete = delete_scsi_iterator; 747 1.1 christos a->bus_index = 0; 748 1.1 christos a->bus = 0; 749 1.1 christos a->id = 0; 750 1.1 christos } 751 1.1 christos 752 1.1 christos return (MEDIA_ITERATOR) a; 753 1.1 christos } 754 1.1 christos 755 1.1 christos 756 1.1 christos void 757 1.1 christos reset_scsi_iterator(MEDIA_ITERATOR m) 758 1.1 christos { 759 1.1 christos SCSI_MEDIA_ITERATOR a; 760 1.1 christos 761 1.1 christos a = (SCSI_MEDIA_ITERATOR) m; 762 1.1 christos if (a == 0) { 763 1.1 christos /* no media */ 764 1.1 christos } else if (a->m.kind != scsi_mgr.kind) { 765 1.1 christos /* wrong kind - XXX need to error here - this is an internal problem */ 766 1.1 christos } else if (a->m.state != kInit) { 767 1.1 christos a->m.state = kReset; 768 1.1 christos } 769 1.1 christos } 770 1.1 christos 771 1.1 christos 772 1.1 christos char * 773 1.1 christos step_scsi_iterator(MEDIA_ITERATOR m) 774 1.1 christos { 775 1.1 christos SCSI_MEDIA_ITERATOR a; 776 1.1 christos char *result; 777 1.1 christos 778 1.1 christos a = (SCSI_MEDIA_ITERATOR) m; 779 1.1 christos if (a == 0) { 780 1.1 christos /* no media */ 781 1.1 christos } else if (a->m.kind != scsi_mgr.kind) { 782 1.1 christos /* wrong kind - XXX need to error here - this is an internal problem */ 783 1.1 christos } else { 784 1.1 christos switch (a->m.state) { 785 1.1 christos case kInit: 786 1.1 christos /* find # of buses - done in AllocatePB() out of scsi_init() */ 787 1.1 christos a->m.state = kReset; 788 1.1 christos /* fall through to reset */ 789 1.1 christos case kReset: 790 1.1 christos a->bus_index = 0 /* first bus id */; 791 1.1 christos a->bus = scsi_mgr.bus_list[a->bus_index].bus; 792 1.1 christos a->id = 0 /* first device id */; 793 1.1 christos a->m.state = kIterating; 794 1.1 christos clear_linux_cache(); 795 1.1 christos /* fall through to iterate */ 796 1.1 christos case kIterating: 797 1.1 christos while (1) { 798 1.1 christos if (a->bus_index >= scsi_mgr.bus_count /* max bus id */) { 799 1.1 christos break; 800 1.1 christos } 801 1.1 christos if (a->id == scsi_mgr.bus_list[a->bus_index].master_id) { 802 1.1 christos /* next id */ 803 1.1 christos a->id += 1; 804 1.1 christos } 805 1.1 christos if (a->id > scsi_mgr.bus_list[a->bus_index].max_id) { 806 1.1 christos a->bus_index += 1; 807 1.1 christos a->bus = scsi_mgr.bus_list[a->bus_index].bus; 808 1.1 christos a->id = 0 /* first device id */; 809 1.1 christos continue; /* try again */ 810 1.1 christos } 811 1.1 christos /* generate result */ 812 1.1 christos result = (char *) malloc(20); 813 1.1 christos if (result != NULL) { 814 1.1 christos if (a->bus == 0xFF) { 815 1.2 christos snprintf(result, 20, "/dev/scsi%c", '0'+a->id); 816 1.1 christos probe_scsi_device(a->bus, a->id, 1); 817 1.1 christos } else { 818 1.1 christos // insure bus number in range 819 1.1 christos if (a->bus > 9) { 820 1.1 christos free(result); 821 1.1 christos result = NULL; 822 1.1 christos break; 823 1.1 christos } 824 1.2 christos snprintf(result, 20, "/dev/scsi%c.%c", 825 1.2 christos '0'+a->bus, '0'+a->id); 826 1.1 christos /* only probe out of iterate; so always added in order. */ 827 1.1 christos probe_scsi_device(a->bus, a->id, 0); 828 1.1 christos } 829 1.1 christos } 830 1.1 christos 831 1.1 christos a->id += 1; /* next id */ 832 1.1 christos return result; 833 1.1 christos } 834 1.1 christos a->m.state = kEnd; 835 1.1 christos /* fall through to end */ 836 1.1 christos case kEnd: 837 1.1 christos mark_linux_cache_loaded(); 838 1.1 christos default: 839 1.1 christos break; 840 1.1 christos } 841 1.1 christos } 842 1.1 christos return 0 /* no entry */; 843 1.1 christos } 844 1.1 christos 845 1.1 christos 846 1.1 christos void 847 1.1 christos delete_scsi_iterator(MEDIA_ITERATOR m) 848 1.1 christos { 849 1.1 christos return; 850 1.1 christos } 851 1.1 christos 852 1.1 christos 853 1.1 christos #pragma mark - 854 1.1 christos 855 1.1 christos 856 1.1 christos MEDIA 857 1.1 christos open_linux_scsi_as_media(long index, int is_cdrom) 858 1.1 christos { 859 1.1 christos MEDIA m; 860 1.1 christos long bus; 861 1.1 christos long id; 862 1.1 christos 863 1.1 christos if (lookup_scsi_index(index, is_cdrom, &bus, &id) > 0) { 864 1.1 christos m = open_scsi_as_media(bus, id); 865 1.1 christos } else { 866 1.1 christos m = 0; 867 1.1 christos } 868 1.1 christos 869 1.1 christos return m; 870 1.1 christos } 871 1.1 christos 872 1.1 christos 873 1.1 christos char * 874 1.1 christos linux_old_scsi_name(long id) 875 1.1 christos { 876 1.1 christos linux_scsi_name(kOriginalSCSIBusAdaptor, id); 877 1.1 christos } 878 1.1 christos 879 1.1 christos 880 1.1 christos char * 881 1.1 christos linux_scsi_name(long bus, long id) 882 1.1 christos { 883 1.1 christos char *result = 0; 884 1.1 christos long value; 885 1.1 christos int is_cdrom; 886 1.1 christos int unsure; 887 1.1 christos char *suffix; 888 1.1 christos 889 1.1 christos /* name is sda, sdb, sdc, ... 890 1.1 christos * in order by buses and ids, but only count responding devices ... 891 1.1 christos */ 892 1.1 christos if ((value = lookup_scsi_device(bus, id, &is_cdrom, &unsure)) >= 0) { 893 1.1 christos result = (char *) malloc(20); 894 1.1 christos if (result != NULL) { 895 1.1 christos if (unsure) { 896 1.1 christos suffix = " ?"; 897 1.1 christos } else { 898 1.1 christos suffix = ""; 899 1.1 christos } 900 1.1 christos if (is_cdrom) { 901 1.1 christos if (value > 9) { 902 1.1 christos // too many CD's, give up 903 1.1 christos free(result); result = NULL; 904 1.1 christos } else { 905 1.2 christos snprintf(result, 20, "/dev/scd%c%s", '0' + value, suffix); 906 1.1 christos } 907 1.1 christos } else { 908 1.1 christos if (value < 26) { 909 1.2 christos snprintf(result, 20, "/dev/sd%c%s", 'a' + value, suffix); 910 1.1 christos } else { 911 1.2 christos snprintf(result, 20, "/dev/sd%c%c%s", 912 1.1 christos 'a' + value / 26, 'a' + value % 26, suffix); 913 1.1 christos } 914 1.1 christos } 915 1.1 christos } 916 1.1 christos } 917 1.1 christos return result; 918 1.1 christos } 919 1.1 christos 920 1.1 christos 921 1.1 christos void 922 1.1 christos probe_all(void) 923 1.1 christos { 924 1.1 christos MEDIA_ITERATOR iter; 925 1.1 christos char *name; 926 1.1 christos 927 1.1 christos iter = create_scsi_iterator(); 928 1.1 christos if (iter == 0) { 929 1.1 christos return; 930 1.1 christos } 931 1.1 christos 932 1.1 christos printf("finding devices "); 933 1.1 christos fflush(stdout); 934 1.1 christos while ((name = step_media_iterator(iter)) != 0) { 935 1.1 christos /* step does the probe for us */ 936 1.1 christos printf("."); 937 1.1 christos fflush(stdout); 938 1.1 christos free(name); 939 1.1 christos } 940 1.1 christos delete_media_iterator(iter); 941 1.1 christos printf("\n"); 942 1.1 christos fflush(stdout); 943 1.1 christos } 944 1.1 christos 945 1.1 christos 946 1.1 christos void 947 1.1 christos probe_scsi_device(long bus, long id, int unsure) 948 1.1 christos { 949 1.1 christos UInt32 devType; 950 1.1 christos 951 1.1 christos if (DoInquiry(id, bus, &devType)) { 952 1.1 christos if (devType == kScsiDevTypeDirect 953 1.1 christos || devType == kScsiDevTypeOptical) { 954 1.1 christos add_to_cache(bus, id, 0, unsure); 955 1.1 christos } else if (devType == kScsiDevTypeCDROM 956 1.1 christos || devType == kScsiDevTypeWorm) { 957 1.1 christos add_to_cache(bus, id, 1, unsure); 958 1.1 christos } 959 1.1 christos } 960 1.1 christos } 961 1.1 christos 962 1.1 christos 963 1.1 christos long 964 1.1 christos lookup_scsi_device(long bus, long id, int *is_cdrom, int *unsure) 965 1.1 christos { 966 1.1 christos /* walk down list looking for bus and id ? 967 1.1 christos * 968 1.1 christos * only probe out of iterate (so always add in order) 969 1.1 christos * reset list if we reset the iterate 970 1.1 christos */ 971 1.1 christos struct cache_item *item; 972 1.1 christos struct cache_item *next; 973 1.1 christos long result = -1; 974 1.1 christos int count = 0; 975 1.1 christos 976 1.1 christos if (scsi_inited == 0) { 977 1.1 christos scsi_init(); 978 1.1 christos } 979 1.1 christos 980 1.1 christos while (1) { 981 1.1 christos count++; 982 1.1 christos for (item = linux_order.first; item != NULL; item = item->next) { 983 1.1 christos if (item->bus == bus && item->id == id) { 984 1.1 christos result = item->value; 985 1.1 christos *is_cdrom = item->is_cdrom; 986 1.1 christos *unsure = item->unsure; 987 1.1 christos break; 988 1.1 christos } 989 1.1 christos } 990 1.1 christos if (count < 2 && result < 0) { 991 1.1 christos probe_all(); 992 1.1 christos } else { 993 1.1 christos break; 994 1.1 christos } 995 1.1 christos }; 996 1.1 christos 997 1.1 christos return result; 998 1.1 christos } 999 1.1 christos 1000 1.1 christos 1001 1.1 christos /* 1002 1.1 christos * This has the same structure as lookup_scsi_device() except we are 1003 1.1 christos * matching on the value & type rather than the bus & id. 1004 1.1 christos */ 1005 1.1 christos long 1006 1.1 christos lookup_scsi_index(long index, int is_cdrom, long *bus, long *id) 1007 1.1 christos { 1008 1.1 christos struct cache_item *item; 1009 1.1 christos struct cache_item *next; 1010 1.1 christos long result = 0; 1011 1.1 christos int count = 0; 1012 1.1 christos 1013 1.1 christos if (scsi_inited == 0) { 1014 1.1 christos scsi_init(); 1015 1.1 christos } 1016 1.1 christos 1017 1.1 christos while (1) { 1018 1.1 christos count++; 1019 1.1 christos for (item = linux_order.first; item != NULL; item = item->next) { 1020 1.1 christos if (item->value == index && item->is_cdrom == is_cdrom 1021 1.1 christos && item->unsure == 0) { 1022 1.1 christos result = 1; 1023 1.1 christos *bus = item->bus; 1024 1.1 christos *id = item->id; 1025 1.1 christos break; 1026 1.1 christos } 1027 1.1 christos } 1028 1.1 christos if (count < 2 && result == 0 && !linux_cache_loaded()) { 1029 1.1 christos probe_all(); 1030 1.1 christos } else { 1031 1.1 christos break; 1032 1.1 christos } 1033 1.1 christos }; 1034 1.1 christos 1035 1.1 christos return result; 1036 1.1 christos } 1037 1.1 christos 1038 1.1 christos 1039 1.1 christos void 1040 1.1 christos add_to_cache(long bus, long id, int is_cdrom, int unsure) 1041 1.1 christos { 1042 1.1 christos struct cache_item *item; 1043 1.1 christos 1044 1.1 christos item = malloc(sizeof(struct cache_item)); 1045 1.1 christos if (item == NULL) { 1046 1.1 christos return; 1047 1.1 christos } else { 1048 1.1 christos item->bus = bus; 1049 1.1 christos item->id = id; 1050 1.1 christos item->is_cdrom = is_cdrom; 1051 1.1 christos item->unsure = unsure; 1052 1.1 christos if (is_cdrom) { 1053 1.1 christos item->value = linux_order.next_cdrom; 1054 1.1 christos linux_order.next_cdrom++; 1055 1.1 christos } else { 1056 1.1 christos item->value = linux_order.next_disk; 1057 1.1 christos linux_order.next_disk++; 1058 1.1 christos } 1059 1.1 christos item->next = 0; 1060 1.1 christos } 1061 1.1 christos if (linux_order.first == NULL) { 1062 1.1 christos linux_order.first = item; 1063 1.1 christos linux_order.last = item; 1064 1.1 christos } else { 1065 1.1 christos linux_order.last->next = item; 1066 1.1 christos linux_order.last = item; 1067 1.1 christos } 1068 1.1 christos } 1069 1.1 christos 1070 1.1 christos 1071 1.1 christos void 1072 1.1 christos init_linux_cache(void) 1073 1.1 christos { 1074 1.1 christos linux_order.first = NULL; 1075 1.1 christos clear_linux_cache(); 1076 1.1 christos } 1077 1.1 christos 1078 1.1 christos 1079 1.1 christos void 1080 1.1 christos clear_linux_cache(void) 1081 1.1 christos { 1082 1.1 christos struct cache_item *item; 1083 1.1 christos struct cache_item *next; 1084 1.1 christos 1085 1.1 christos for (item = linux_order.first; item != NULL; item = next) { 1086 1.1 christos next = item->next; 1087 1.1 christos free(item); 1088 1.1 christos } 1089 1.1 christos /* back to starting value */ 1090 1.1 christos linux_order.first = NULL; 1091 1.1 christos linux_order.last = NULL; 1092 1.1 christos linux_order.next_disk = 0; 1093 1.1 christos linux_order.next_cdrom = 0; 1094 1.1 christos linux_order.loaded = 0; 1095 1.1 christos } 1096 1.1 christos 1097 1.1 christos 1098 1.1 christos void 1099 1.1 christos mark_linux_cache_loaded(void) 1100 1.1 christos { 1101 1.1 christos linux_order.loaded = 1; 1102 1.1 christos } 1103 1.1 christos 1104 1.1 christos 1105 1.1 christos int 1106 1.1 christos linux_cache_loaded(void) 1107 1.1 christos { 1108 1.1 christos return linux_order.loaded; 1109 1.1 christos } 1110