1 1.1 christos /* This file is part of the program psim. 2 1.1 christos 3 1.1 christos Copyright (C) 1996, Andrew Cagney <cagney (at) highland.com.au> 4 1.1 christos 5 1.1 christos This program is free software; you can redistribute it and/or modify 6 1.1 christos it under the terms of the GNU General Public License as published by 7 1.1.1.2 christos the Free Software Foundation; either version 3 of the License, or 8 1.1 christos (at your option) any later version. 9 1.1 christos 10 1.1 christos This program is distributed in the hope that it will be useful, 11 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 12 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 1.1 christos GNU General Public License for more details. 14 1.1 christos 15 1.1 christos You should have received a copy of the GNU General Public License 16 1.1.1.2 christos along with this program; if not, see <http://www.gnu.org/licenses/>. 17 1.1 christos 18 1.1 christos */ 19 1.1 christos 20 1.1 christos 21 1.1 christos #ifndef _HW_IDE_C_ 22 1.1 christos #define _HW_IDE_C_ 23 1.1 christos 24 1.1 christos #include "device_table.h" 25 1.1 christos 26 1.1 christos 27 1.1 christos 28 1.1 christos /* DEVICE 29 1.1 christos 30 1.1 christos 31 1.1 christos ide - Integrated Disk Electronics 32 1.1 christos 33 1.1 christos 34 1.1 christos DESCRIPTION 35 1.1 christos 36 1.1 christos 37 1.1 christos This device models the primary/secondary <<ide>> controller 38 1.1 christos described in the [CHRPIO] document. 39 1.1 christos 40 1.1.1.4 christos The controller has separate independent interrupt outputs for each 41 1.1 christos <<ide>> bus. 42 1.1 christos 43 1.1 christos 44 1.1 christos PROPERTIES 45 1.1 christos 46 1.1 christos 47 1.1 christos reg = ... (required) 48 1.1 christos 49 1.1 christos The <<reg>> property is described in the document [CHRPIO]. 50 1.1 christos 51 1.1 christos 52 1.1 christos ready-delay = <integer> (optional) 53 1.1 christos 54 1.1 christos If present, this specifies the time that the <<ide>> device takes 55 1.1 christos to complete an I/O operation. 56 1.1 christos 57 1.1 christos 58 1.1 christos disk@?/ide-byte-count = <integer> (optional) 59 1.1 christos 60 1.1 christos disk@?/ide-sector-count = <integer> (optional) 61 1.1 christos 62 1.1 christos disk@?/ide-head-count = <integer> (optional) 63 1.1 christos 64 1.1 christos The <<ide>> device checks each child (disk device) node to see if 65 1.1 christos it has the above properties. If present, these values will be used 66 1.1 christos to compute the <<LBA>> address in <<CHS>> addressing mode. 67 1.1 christos 68 1.1 christos 69 1.1 christos EXAMPLES 70 1.1 christos 71 1.1 christos 72 1.1 christos Enable tracing: 73 1.1 christos 74 1.1 christos | -t ide-device \ 75 1.1 christos 76 1.1 christos 77 1.1 christos Attach the <<ide>> device to the <<pci>> bus at slot one. Specify 78 1.1 christos legacy I/O addresses: 79 1.1 christos 80 1.1 christos | -o '/phb/ide@1/assigned-addresses \ 81 1.1 christos | ni0,0,10,1f0 8 \ 82 1.1 christos | ni0,0,14,3f8 8 \ 83 1.1 christos | ni0,0,18,170 8 \ 84 1.1 christos | ni0,0,1c,378 8 \ 85 1.1 christos | ni0,0,20,200 8' \ 86 1.1 christos | -o '/phb@0x80000000/ide@1/reg \ 87 1.1 christos | 1 0 \ 88 1.1 christos | i0,0,10,0 8 \ 89 1.1 christos | i0,0,18,0 8 \ 90 1.1 christos | i0,0,14,6 1 \ 91 1.1 christos | i0,0,1c,6 1 \ 92 1.1 christos | i0,0,20,0 8' \ 93 1.1 christos 94 1.1.1.4 christos Note: the fourth and fifth reg entries specify that the register is 95 1.1 christos at an offset into the address specified by the base register 96 1.1 christos (<<assigned-addresses>>); Apart from restrictions placed by the 97 1.1 christos <<pci>> specification, no restrictions are placed on the number of 98 1.1 christos base registers specified by the <<assigned-addresses>> property. 99 1.1 christos 100 1.1 christos Attach a <<disk>> to the primary and a <<cdrom>> to the secondary 101 1.1 christos <<ide>> controller. 102 1.1 christos 103 1.1 christos | -o '/phb@0x80000000/ide@1/disk@0/file "zero' \ 104 1.1 christos | -o '/phb@0x80000000/ide@1/cdrom@2/file "/dev/cdrom"' \ 105 1.1 christos 106 1.1 christos Connect the two interrupt outputs (a and b) to a <<glue>> device to 107 1.1 christos allow testing of the interrupt port. In a real simulation they 108 1.1 christos would be wired to the interrupt controller. 109 1.1 christos 110 1.1 christos | -o '/phb@0x80000000/glue@2/reg 2 0 ni0,0,0,0 8' \ 111 1.1 christos | -o '/phb@0x80000000/ide@1 > a 0 /phb@0x80000000/glue@2' \ 112 1.1 christos | -o '/phb@0x80000000/ide@1 > b 1 /phb@0x80000000/glue@2' 113 1.1 christos 114 1.1 christos 115 1.1 christos BUGS 116 1.1 christos 117 1.1 christos 118 1.1 christos While the DMA registers are present, DMA support has not yet been 119 1.1 christos implemented. 120 1.1 christos 121 1.1 christos The number of supported commands is very limited. 122 1.1 christos 123 1.1 christos The standards documents appear to be vague on how to specify the 124 1.1 christos <<unit-address>> of disk devices devices being attached to the 125 1.1 christos <<ide>> controller. I've chosen to use integers with devices zero 126 1.1 christos and one going to the primary controller while two and three are 127 1.1 christos connected to the secondary controller. 128 1.1 christos 129 1.1 christos 130 1.1 christos REFERENCES 131 1.1 christos 132 1.1 christos 133 1.1 christos [CHRPIO] PowerPC(tm) Microprocessor Common Hardware Reference 134 1.1 christos Platform: I/O Device Reference. http://chrp.apple.com/???. 135 1.1 christos 136 1.1 christos [SCHMIDT] The SCSI Bus and IDE Interface - Protocols, Applications 137 1.1 christos and Programming. Friedhelm Schmidt (translated by Michael 138 1.1 christos Schultz). ISBN 0-201-42284-0. Addison-Wesley Publishing Company. 139 1.1 christos 140 1.1 christos 141 1.1 christos */ 142 1.1 christos 143 1.1 christos 144 1.1 christos 145 1.1 christos typedef enum _io_direction { 146 1.1 christos is_read, 147 1.1 christos is_write, 148 1.1 christos } io_direction; 149 1.1 christos 150 1.1 christos 151 1.1 christos enum { 152 1.1 christos nr_ide_controllers = 2, 153 1.1 christos nr_ide_drives_per_controller = 2, 154 1.1 christos nr_fifo_entries = 8192, 155 1.1 christos }; 156 1.1 christos 157 1.1 christos enum { 158 1.1 christos /* command register block - read */ 159 1.1 christos ide_data_reg, 160 1.1 christos ide_error_reg, /*ide_feature_reg*/ 161 1.1 christos ide_sector_count_reg, 162 1.1 christos ide_sector_number_reg, 163 1.1 christos ide_cylinder_reg0, 164 1.1 christos ide_cylinder_reg1, 165 1.1 christos ide_drive_head_reg, 166 1.1 christos ide_status_reg, /*ide_command_reg*/ 167 1.1 christos /* command register block - write */ 168 1.1 christos ide_feature_reg, /*ide_error_reg*/ 169 1.1 christos ide_command_reg, /*ide_status_reg*/ 170 1.1 christos /* control register block - read */ 171 1.1 christos ide_alternate_status_reg, /*ide_control_reg*/ 172 1.1 christos ide_control_reg, /*ide_alternate_status_reg*/ 173 1.1 christos /* dma register block */ 174 1.1 christos ide_dma_command_reg, 175 1.1 christos ide_dma_unused_1_reg, 176 1.1 christos ide_dma_status_reg, 177 1.1 christos ide_dma_unused_3_reg, 178 1.1 christos ide_dma_prd_table_address_reg0, 179 1.1 christos ide_dma_prd_table_address_reg1, 180 1.1 christos ide_dma_prd_table_address_reg2, 181 1.1 christos ide_dma_prd_table_address_reg3, 182 1.1 christos nr_ide_registers, 183 1.1 christos }; 184 1.1 christos 185 1.1 christos 186 1.1 christos typedef enum _ide_states { 187 1.1 christos idle_state, 188 1.1 christos busy_loaded_state, 189 1.1 christos busy_drained_state, 190 1.1 christos busy_dma_state, 191 1.1 christos busy_command_state, 192 1.1 christos loading_state, 193 1.1 christos draining_state, 194 1.1 christos } ide_states; 195 1.1 christos 196 1.1 christos static const char * 197 1.1 christos ide_state_name(ide_states state) 198 1.1 christos { 199 1.1 christos switch (state) { 200 1.1 christos case idle_state: return "idle"; 201 1.1 christos case busy_loaded_state: return "busy_loaded_state"; 202 1.1 christos case busy_drained_state: return "busy_drained_state"; 203 1.1 christos case busy_dma_state: return "busy_dma_state"; 204 1.1 christos case busy_command_state: return "busy_command_state"; 205 1.1 christos case loading_state: return "loading_state"; 206 1.1 christos case draining_state: return "draining_state"; 207 1.1 christos default: return "illegal-state"; 208 1.1 christos } 209 1.1 christos } 210 1.1 christos 211 1.1 christos typedef struct _ide_geometry { 212 1.1 christos int head; 213 1.1 christos int sector; 214 1.1 christos int byte; 215 1.1 christos } ide_geometry; 216 1.1 christos 217 1.1 christos typedef struct _ide_drive { 218 1.1 christos int nr; 219 1.1 christos device *device; 220 1.1 christos ide_geometry geometry; 221 1.1 christos ide_geometry default_geometry; 222 1.1 christos } ide_drive; 223 1.1 christos 224 1.1 christos typedef struct _ide_controller { 225 1.1 christos int nr; 226 1.1 christos ide_states state; 227 1.1.1.3 christos uint8_t reg[nr_ide_registers]; 228 1.1.1.3 christos uint8_t fifo[nr_fifo_entries]; 229 1.1 christos int fifo_pos; 230 1.1 christos int fifo_size; 231 1.1 christos ide_drive *current_drive; 232 1.1 christos int current_byte; 233 1.1 christos int current_transfer; 234 1.1 christos ide_drive drive[nr_ide_drives_per_controller]; 235 1.1 christos device *me; 236 1.1 christos event_entry_tag event_tag; 237 1.1 christos int is_interrupting; 238 1.1.1.3 christos int64_t ready_delay; 239 1.1 christos } ide_controller; 240 1.1 christos 241 1.1 christos 242 1.1 christos 243 1.1 christos static void 244 1.1 christos set_interrupt(device *me, 245 1.1 christos ide_controller *controller) 246 1.1 christos { 247 1.1 christos if ((controller->reg[ide_control_reg] & 0x2) == 0) { 248 1.1 christos DTRACE(ide, ("controller %d - interrupt set\n", controller->nr)); 249 1.1 christos device_interrupt_event(me, controller->nr, 1, NULL, 0); 250 1.1 christos controller->is_interrupting = 1; 251 1.1 christos } 252 1.1 christos } 253 1.1 christos 254 1.1 christos 255 1.1 christos static void 256 1.1 christos clear_interrupt(device *me, 257 1.1 christos ide_controller *controller) 258 1.1 christos { 259 1.1 christos if (controller->is_interrupting) { 260 1.1 christos DTRACE(ide, ("controller %d - interrupt clear\n", controller->nr)); 261 1.1 christos device_interrupt_event(me, controller->nr, 0, NULL, 0); 262 1.1 christos controller->is_interrupting = 0; 263 1.1 christos } 264 1.1 christos } 265 1.1 christos 266 1.1 christos 267 1.1 christos static void 268 1.1 christos do_event(void *data) 269 1.1 christos { 270 1.1 christos ide_controller *controller = data; 271 1.1 christos device *me = controller->me; 272 1.1 christos controller->event_tag = 0; 273 1.1 christos switch (controller->state) { 274 1.1 christos case busy_loaded_state: 275 1.1 christos case busy_drained_state: 276 1.1 christos if (controller->current_transfer > 0) { 277 1.1 christos controller->state = (controller->state == busy_loaded_state 278 1.1 christos ? loading_state : draining_state); 279 1.1 christos } 280 1.1 christos else { 281 1.1 christos controller->state = idle_state; 282 1.1 christos } 283 1.1 christos set_interrupt(me, controller); 284 1.1 christos break; 285 1.1 christos default: 286 1.1 christos device_error(me, "controller %d - unexpected event", controller->nr); 287 1.1 christos break; 288 1.1 christos } 289 1.1 christos } 290 1.1 christos 291 1.1 christos 292 1.1 christos static void 293 1.1 christos schedule_ready_event(device *me, 294 1.1 christos ide_controller *controller) 295 1.1 christos { 296 1.1 christos if (controller->event_tag != 0) 297 1.1 christos device_error(me, "controller %d - attempting to schedule multiple events", 298 1.1 christos controller->nr); 299 1.1 christos controller->event_tag = 300 1.1 christos device_event_queue_schedule(me, controller->ready_delay, 301 1.1 christos do_event, controller); 302 1.1 christos } 303 1.1 christos 304 1.1 christos 305 1.1 christos static void 306 1.1 christos do_fifo_read(device *me, 307 1.1 christos ide_controller *controller, 308 1.1 christos void *dest, 309 1.1 christos int nr_bytes) 310 1.1 christos { 311 1.1 christos if (controller->state != draining_state) 312 1.1 christos device_error(me, "controller %d - reading fifo when not ready (%s)", 313 1.1 christos controller->nr, 314 1.1 christos ide_state_name(controller->state)); 315 1.1 christos if (controller->fifo_pos + nr_bytes > controller->fifo_size) 316 1.1 christos device_error(me, "controller %d - fifo underflow", controller->nr); 317 1.1 christos if (nr_bytes > 0) { 318 1.1 christos memcpy(dest, &controller->fifo[controller->fifo_pos], nr_bytes); 319 1.1 christos controller->fifo_pos += nr_bytes; 320 1.1 christos } 321 1.1 christos if (controller->fifo_pos == controller->fifo_size) { 322 1.1 christos controller->current_transfer -= 1; 323 1.1 christos if (controller->current_transfer > 0 324 1.1 christos && controller->current_drive != NULL) { 325 1.1 christos DTRACE(ide, ("controller %d:%d - reading %d byte block at 0x%x\n", 326 1.1 christos controller->nr, 327 1.1 christos controller->current_drive->nr, 328 1.1 christos controller->fifo_size, 329 1.1 christos controller->current_byte)); 330 1.1 christos if (device_io_read_buffer(controller->current_drive->device, 331 1.1 christos controller->fifo, 332 1.1 christos 0, controller->current_byte, 333 1.1 christos controller->fifo_size, 334 1.1 christos NULL, 0) 335 1.1 christos != controller->fifo_size) 336 1.1 christos device_error(me, "controller %d - disk %s io read error", 337 1.1 christos controller->nr, 338 1.1 christos device_path(controller->current_drive->device)); 339 1.1 christos } 340 1.1 christos controller->state = busy_drained_state; 341 1.1 christos controller->fifo_pos = 0; 342 1.1 christos controller->current_byte += controller->fifo_size; 343 1.1 christos schedule_ready_event(me, controller); 344 1.1 christos } 345 1.1 christos } 346 1.1 christos 347 1.1 christos 348 1.1 christos static void 349 1.1 christos do_fifo_write(device *me, 350 1.1 christos ide_controller *controller, 351 1.1 christos const void *source, 352 1.1 christos int nr_bytes) 353 1.1 christos { 354 1.1 christos if (controller->state != loading_state) 355 1.1 christos device_error(me, "controller %d - writing fifo when not ready (%s)", 356 1.1 christos controller->nr, 357 1.1 christos ide_state_name(controller->state)); 358 1.1 christos if (controller->fifo_pos + nr_bytes > controller->fifo_size) 359 1.1 christos device_error(me, "controller %d - fifo overflow", controller->nr); 360 1.1 christos if (nr_bytes > 0) { 361 1.1 christos memcpy(&controller->fifo[controller->fifo_pos], source, nr_bytes); 362 1.1 christos controller->fifo_pos += nr_bytes; 363 1.1 christos } 364 1.1 christos if (controller->fifo_pos == controller->fifo_size) { 365 1.1 christos if (controller->current_transfer > 0 366 1.1 christos && controller->current_drive != NULL) { 367 1.1 christos DTRACE(ide, ("controller %d:%d - writing %d byte block at 0x%x\n", 368 1.1 christos controller->nr, 369 1.1 christos controller->current_drive->nr, 370 1.1 christos controller->fifo_size, 371 1.1 christos controller->current_byte)); 372 1.1 christos if (device_io_write_buffer(controller->current_drive->device, 373 1.1 christos controller->fifo, 374 1.1 christos 0, controller->current_byte, 375 1.1 christos controller->fifo_size, 376 1.1 christos NULL, 0) 377 1.1 christos != controller->fifo_size) 378 1.1 christos device_error(me, "controller %d - disk %s io write error", 379 1.1 christos controller->nr, 380 1.1 christos device_path(controller->current_drive->device)); 381 1.1 christos } 382 1.1 christos controller->current_transfer -= 1; 383 1.1 christos controller->fifo_pos = 0; 384 1.1 christos controller->current_byte += controller->fifo_size; 385 1.1 christos controller->state = busy_loaded_state; 386 1.1 christos schedule_ready_event(me, controller); 387 1.1 christos } 388 1.1 christos } 389 1.1 christos 390 1.1 christos 391 1.1 christos static void 392 1.1 christos setup_fifo(device *me, 393 1.1 christos ide_controller *controller, 394 1.1 christos int is_simple, 395 1.1 christos int is_with_disk, 396 1.1 christos io_direction direction) 397 1.1 christos { 398 1.1 christos /* find the disk */ 399 1.1 christos if (is_with_disk) { 400 1.1 christos int drive_nr = (controller->reg[ide_drive_head_reg] & 0x10) != 0; 401 1.1 christos controller->current_drive = &controller->drive[drive_nr]; 402 1.1 christos } 403 1.1 christos else { 404 1.1 christos controller->current_drive = NULL; 405 1.1 christos } 406 1.1 christos 407 1.1 christos /* number of transfers */ 408 1.1 christos if (is_simple) 409 1.1 christos controller->current_transfer = 1; 410 1.1 christos else { 411 1.1 christos int sector_count = controller->reg[ide_sector_count_reg]; 412 1.1 christos if (sector_count == 0) 413 1.1 christos controller->current_transfer = 256; 414 1.1 christos else 415 1.1 christos controller->current_transfer = sector_count; 416 1.1 christos } 417 1.1 christos 418 1.1 christos /* the transfer size */ 419 1.1 christos if (controller->current_drive == NULL) 420 1.1 christos controller->fifo_size = 512; 421 1.1 christos else 422 1.1 christos controller->fifo_size = controller->current_drive->geometry.byte; 423 1.1 christos 424 1.1 christos /* empty the fifo */ 425 1.1 christos controller->fifo_pos = 0; 426 1.1 christos 427 1.1 christos /* the starting address */ 428 1.1 christos if (controller->current_drive == NULL) 429 1.1 christos controller->current_byte = 0; 430 1.1 christos else if (controller->reg[ide_drive_head_reg] & 0x40) { 431 1.1 christos /* LBA addressing mode */ 432 1.1 christos controller->current_byte = controller->fifo_size 433 1.1 christos * (((controller->reg[ide_drive_head_reg] & 0xf) << 24) 434 1.1 christos | (controller->reg[ide_cylinder_reg1] << 16) 435 1.1 christos | (controller->reg[ide_cylinder_reg0] << 8) 436 1.1 christos | (controller->reg[ide_sector_number_reg])); 437 1.1 christos } 438 1.1 christos else if (controller->current_drive->geometry.head != 0 439 1.1 christos && controller->current_drive->geometry.sector != 0) { 440 1.1 christos /* CHS addressing mode */ 441 1.1 christos int head_nr = controller->reg[ide_drive_head_reg] & 0xf; 442 1.1 christos int cylinder_nr = ((controller->reg[ide_cylinder_reg1] << 8) 443 1.1 christos | controller->reg[ide_cylinder_reg0]); 444 1.1 christos int sector_nr = controller->reg[ide_sector_number_reg]; 445 1.1 christos controller->current_byte = controller->fifo_size 446 1.1 christos * ((cylinder_nr * controller->current_drive->geometry.head + head_nr) 447 1.1 christos * controller->current_drive->geometry.sector + sector_nr - 1); 448 1.1 christos } 449 1.1 christos else 450 1.1 christos device_error(me, "controller %d:%d - CHS addressing disabled", 451 1.1 christos controller->nr, controller->current_drive->nr); 452 1.1 christos DTRACE(ide, ("controller %ld:%ld - transfer (%s) %ld blocks of %ld bytes from 0x%lx\n", 453 1.1 christos (long)controller->nr, 454 1.1 christos controller->current_drive == NULL ? -1L : (long)controller->current_drive->nr, 455 1.1 christos direction == is_read ? "read" : "write", 456 1.1 christos (long)controller->current_transfer, 457 1.1 christos (long)controller->fifo_size, 458 1.1 christos (unsigned long)controller->current_byte)); 459 1.1 christos switch (direction) { 460 1.1 christos case is_read: 461 1.1 christos /* force a primeing read */ 462 1.1 christos controller->current_transfer += 1; 463 1.1 christos controller->state = draining_state; 464 1.1 christos controller->fifo_pos = controller->fifo_size; 465 1.1 christos do_fifo_read(me, controller, NULL, 0); 466 1.1 christos break; 467 1.1 christos case is_write: 468 1.1 christos controller->state = loading_state; 469 1.1 christos break; 470 1.1 christos } 471 1.1 christos } 472 1.1 christos 473 1.1 christos 474 1.1 christos static void 475 1.1 christos do_command(device *me, 476 1.1 christos ide_controller *controller, 477 1.1 christos int command) 478 1.1 christos { 479 1.1 christos if (controller->state != idle_state) 480 1.1 christos device_error(me, "controller %d - command when not idle", controller->nr); 481 1.1 christos switch (command) { 482 1.1 christos case 0x20: case 0x21: /* read-sectors */ 483 1.1 christos setup_fifo(me, controller, 0/*is_simple*/, 1/*is_with_disk*/, is_read); 484 1.1 christos break; 485 1.1 christos case 0x30: case 0x31: /* write */ 486 1.1 christos setup_fifo(me, controller, 0/*is_simple*/, 1/*is_with_disk*/, is_write); 487 1.1 christos break; 488 1.1 christos } 489 1.1 christos } 490 1.1 christos 491 1.1.1.3 christos static uint8_t 492 1.1 christos get_status(device *me, 493 1.1 christos ide_controller *controller) 494 1.1 christos { 495 1.1 christos switch (controller->state) { 496 1.1 christos case loading_state: 497 1.1 christos case draining_state: 498 1.1 christos return 0x08; /* data req */ 499 1.1 christos case busy_loaded_state: 500 1.1 christos case busy_drained_state: 501 1.1 christos return 0x80; /* busy */ 502 1.1 christos case idle_state: 503 1.1 christos return 0x40; /* drive ready */ 504 1.1 christos default: 505 1.1 christos device_error(me, "internal error"); 506 1.1 christos return 0; 507 1.1 christos } 508 1.1 christos } 509 1.1 christos 510 1.1 christos 511 1.1 christos /* The address presented to the IDE controler is decoded and then 512 1.1 christos mapped onto a controller:reg pair */ 513 1.1 christos 514 1.1 christos enum { 515 1.1 christos nr_address_blocks = 6, 516 1.1 christos }; 517 1.1 christos 518 1.1 christos typedef struct _address_block { 519 1.1 christos int space; 520 1.1 christos unsigned_word base_addr; 521 1.1 christos unsigned_word bound_addr; 522 1.1 christos int controller; 523 1.1 christos int base_reg; 524 1.1 christos } address_block; 525 1.1 christos 526 1.1 christos typedef struct _address_decoder { 527 1.1 christos address_block block[nr_address_blocks]; 528 1.1 christos } address_decoder; 529 1.1 christos 530 1.1 christos static void 531 1.1 christos decode_address(device *me, 532 1.1 christos address_decoder *decoder, 533 1.1 christos int space, 534 1.1 christos unsigned_word address, 535 1.1 christos int *controller, 536 1.1 christos int *reg, 537 1.1 christos io_direction direction) 538 1.1 christos { 539 1.1 christos int i; 540 1.1 christos for (i = 0; i < nr_address_blocks; i++) { 541 1.1 christos if (space == decoder->block[i].space 542 1.1 christos && address >= decoder->block[i].base_addr 543 1.1 christos && address <= decoder->block[i].bound_addr) { 544 1.1 christos *controller = decoder->block[i].controller; 545 1.1 christos *reg = (address 546 1.1 christos - decoder->block[i].base_addr 547 1.1 christos + decoder->block[i].base_reg); 548 1.1 christos if (direction == is_write) { 549 1.1 christos switch (*reg) { 550 1.1 christos case ide_error_reg: *reg = ide_feature_reg; break; 551 1.1 christos case ide_status_reg: *reg = ide_command_reg; break; 552 1.1 christos case ide_alternate_status_reg: *reg = ide_control_reg; break; 553 1.1 christos default: break; 554 1.1 christos } 555 1.1 christos } 556 1.1 christos return; 557 1.1 christos } 558 1.1 christos } 559 1.1 christos device_error(me, "address %d:0x%lx invalid", 560 1.1 christos space, (unsigned long)address); 561 1.1 christos } 562 1.1 christos 563 1.1 christos 564 1.1 christos static void 565 1.1 christos build_address_decoder(device *me, 566 1.1 christos address_decoder *decoder) 567 1.1 christos { 568 1.1 christos int reg; 569 1.1 christos for (reg = 1; reg < 6; reg++) { 570 1.1 christos reg_property_spec unit; 571 1.1 christos int space; 572 1.1 christos unsigned_word address; 573 1.1 christos unsigned size; 574 1.1 christos /* find and decode the reg property */ 575 1.1 christos if (!device_find_reg_array_property(me, "reg", reg, &unit)) 576 1.1 christos device_error(me, "missing or invalid reg entry %d", reg); 577 1.1 christos device_address_to_attach_address(device_parent(me), &unit.address, 578 1.1 christos &space, &address, me); 579 1.1 christos device_size_to_attach_size(device_parent(me), &unit.size, &size, me); 580 1.1 christos /* insert it into the address decoder */ 581 1.1 christos switch (reg) { 582 1.1 christos case 1: 583 1.1 christos case 2: 584 1.1 christos /* command register block */ 585 1.1 christos if (size != 8) 586 1.1 christos device_error(me, "reg entry %d must have a size of 8", reg); 587 1.1 christos decoder->block[reg-1].space = space; 588 1.1 christos decoder->block[reg-1].base_addr = address; 589 1.1 christos decoder->block[reg-1].bound_addr = address + size - 1; 590 1.1 christos decoder->block[reg-1].controller = (reg + 1) % nr_ide_controllers; 591 1.1 christos decoder->block[reg-1].base_reg = ide_data_reg; 592 1.1 christos DTRACE(ide, ("controller %d command register block at %d:0x%lx..0x%lx\n", 593 1.1 christos decoder->block[reg-1].controller, 594 1.1 christos decoder->block[reg-1].space, 595 1.1 christos (unsigned long)decoder->block[reg-1].base_addr, 596 1.1 christos (unsigned long)decoder->block[reg-1].bound_addr)); 597 1.1 christos break; 598 1.1 christos case 3: 599 1.1 christos case 4: 600 1.1 christos /* control register block */ 601 1.1 christos if (size != 1) 602 1.1 christos device_error(me, "reg entry %d must have a size of 1", reg); 603 1.1 christos decoder->block[reg-1].space = space; 604 1.1 christos decoder->block[reg-1].base_addr = address; 605 1.1 christos decoder->block[reg-1].bound_addr = address + size - 1; 606 1.1 christos decoder->block[reg-1].controller = (reg + 1) % nr_ide_controllers; 607 1.1 christos decoder->block[reg-1].base_reg = ide_alternate_status_reg; 608 1.1 christos DTRACE(ide, ("controller %d control register block at %d:0x%lx..0x%lx\n", 609 1.1 christos decoder->block[reg-1].controller, 610 1.1 christos decoder->block[reg-1].space, 611 1.1 christos (unsigned long)decoder->block[reg-1].base_addr, 612 1.1 christos (unsigned long)decoder->block[reg-1].bound_addr)); 613 1.1 christos break; 614 1.1 christos case 5: 615 1.1 christos /* dma register block */ 616 1.1 christos if (size != 8) 617 1.1 christos device_error(me, "reg entry %d must have a size of 8", reg); 618 1.1 christos decoder->block[reg-1].space = space; 619 1.1 christos decoder->block[reg-1].base_addr = address; 620 1.1 christos decoder->block[reg-1].bound_addr = address + 4 - 1; 621 1.1 christos decoder->block[reg-1].base_reg = ide_dma_command_reg; 622 1.1 christos decoder->block[reg-1].controller = 0; 623 1.1 christos DTRACE(ide, ("controller %d dma register block at %d:0x%lx..0x%lx\n", 624 1.1 christos decoder->block[reg-1].controller, 625 1.1 christos decoder->block[reg-1].space, 626 1.1 christos (unsigned long)decoder->block[reg-1].base_addr, 627 1.1 christos (unsigned long)decoder->block[reg-1].bound_addr)); 628 1.1 christos decoder->block[reg].space = space; 629 1.1 christos decoder->block[reg].base_addr = address + 4; 630 1.1 christos decoder->block[reg].bound_addr = address + 8 - 1; 631 1.1 christos decoder->block[reg].controller = 1; 632 1.1 christos decoder->block[reg].base_reg = ide_dma_command_reg; 633 1.1 christos DTRACE(ide, ("controller %d dma register block at %d:0x%lx..0x%lx\n", 634 1.1 christos decoder->block[reg].controller, 635 1.1 christos decoder->block[reg-1].space, 636 1.1 christos (unsigned long)decoder->block[reg].base_addr, 637 1.1 christos (unsigned long)decoder->block[reg].bound_addr)); 638 1.1 christos break; 639 1.1 christos default: 640 1.1 christos device_error(me, "internal error - bad switch"); 641 1.1 christos break; 642 1.1 christos } 643 1.1 christos } 644 1.1 christos } 645 1.1 christos 646 1.1 christos 647 1.1 christos 648 1.1 christos typedef struct _hw_ide_device { 649 1.1 christos ide_controller controller[nr_ide_controllers]; 650 1.1 christos address_decoder decoder; 651 1.1 christos } hw_ide_device; 652 1.1 christos 653 1.1 christos 654 1.1 christos static void 655 1.1 christos hw_ide_init_address(device *me) 656 1.1 christos { 657 1.1 christos hw_ide_device *ide = device_data(me); 658 1.1 christos int controller; 659 1.1 christos int drive; 660 1.1 christos 661 1.1 christos /* zero some things */ 662 1.1 christos for (controller = 0; controller < nr_ide_controllers; controller++) { 663 1.1 christos memset(&ide->controller[controller], 0, sizeof(ide_controller)); 664 1.1 christos for (drive = 0; drive < nr_ide_drives_per_controller; drive++) { 665 1.1 christos ide->controller[controller].drive[drive].nr = drive; 666 1.1 christos } 667 1.1 christos ide->controller[controller].me = me; 668 1.1 christos if (device_find_property(me, "ready-delay") != NULL) 669 1.1 christos ide->controller[controller].ready_delay = 670 1.1 christos device_find_integer_property(me, "ready-delay"); 671 1.1 christos } 672 1.1 christos 673 1.1 christos /* attach this device to its parent */ 674 1.1 christos generic_device_init_address(me); 675 1.1 christos 676 1.1 christos /* determine our own address map */ 677 1.1 christos build_address_decoder(me, &ide->decoder); 678 1.1 christos 679 1.1 christos } 680 1.1 christos 681 1.1 christos 682 1.1 christos static void 683 1.1 christos hw_ide_attach_address(device *me, 684 1.1 christos attach_type type, 685 1.1 christos int space, 686 1.1 christos unsigned_word addr, 687 1.1 christos unsigned nr_bytes, 688 1.1 christos access_type access, 689 1.1 christos device *client) /*callback/default*/ 690 1.1 christos { 691 1.1 christos hw_ide_device *ide = (hw_ide_device*)device_data(me); 692 1.1 christos int controller_nr = addr / nr_ide_drives_per_controller; 693 1.1 christos int drive_nr = addr % nr_ide_drives_per_controller; 694 1.1 christos ide_controller *controller; 695 1.1 christos ide_drive *drive; 696 1.1 christos if (controller_nr >= nr_ide_controllers) 697 1.1 christos device_error(me, "no controller for disk %s", 698 1.1 christos device_path(client)); 699 1.1 christos 700 1.1 christos controller = &ide->controller[controller_nr]; 701 1.1 christos drive = &controller->drive[drive_nr]; 702 1.1 christos drive->device = client; 703 1.1 christos if (device_find_property(client, "ide-byte-count") != NULL) 704 1.1 christos drive->geometry.byte = device_find_integer_property(client, "ide-byte-count"); 705 1.1 christos else 706 1.1 christos drive->geometry.byte = 512; 707 1.1 christos if (device_find_property(client, "ide-sector-count") != NULL) 708 1.1 christos drive->geometry.sector = device_find_integer_property(client, "ide-sector-count"); 709 1.1 christos if (device_find_property(client, "ide-head-count") != NULL) 710 1.1 christos drive->geometry.head = device_find_integer_property(client, "ide-head-count"); 711 1.1 christos drive->default_geometry = drive->geometry; 712 1.1 christos DTRACE(ide, ("controller %d:%d %s byte-count %d, sector-count %d, head-count %d\n", 713 1.1 christos controller_nr, 714 1.1 christos drive->nr, 715 1.1 christos device_path(client), 716 1.1 christos drive->geometry.byte, 717 1.1 christos drive->geometry.sector, 718 1.1 christos drive->geometry.head)); 719 1.1 christos } 720 1.1 christos 721 1.1 christos 722 1.1 christos static unsigned 723 1.1 christos hw_ide_io_read_buffer(device *me, 724 1.1 christos void *dest, 725 1.1 christos int space, 726 1.1 christos unsigned_word addr, 727 1.1 christos unsigned nr_bytes, 728 1.1 christos cpu *processor, 729 1.1 christos unsigned_word cia) 730 1.1 christos { 731 1.1 christos hw_ide_device *ide = (hw_ide_device *)device_data(me); 732 1.1 christos int control_nr; 733 1.1 christos int reg; 734 1.1 christos ide_controller *controller; 735 1.1 christos 736 1.1 christos /* find the interface */ 737 1.1 christos decode_address(me, &ide->decoder, space, addr, &control_nr, ®, is_read); 738 1.1 christos controller = & ide->controller[control_nr]; 739 1.1 christos 740 1.1 christos /* process the transfer */ 741 1.1 christos memset(dest, 0, nr_bytes); 742 1.1 christos switch (reg) { 743 1.1 christos case ide_data_reg: 744 1.1 christos do_fifo_read(me, controller, dest, nr_bytes); 745 1.1 christos break; 746 1.1 christos case ide_status_reg: 747 1.1.1.3 christos *(uint8_t*)dest = get_status(me, controller); 748 1.1 christos clear_interrupt(me, controller); 749 1.1 christos break; 750 1.1 christos case ide_alternate_status_reg: 751 1.1.1.3 christos *(uint8_t*)dest = get_status(me, controller); 752 1.1 christos break; 753 1.1 christos case ide_error_reg: 754 1.1 christos case ide_sector_count_reg: 755 1.1 christos case ide_sector_number_reg: 756 1.1 christos case ide_cylinder_reg0: 757 1.1 christos case ide_cylinder_reg1: 758 1.1 christos case ide_drive_head_reg: 759 1.1 christos case ide_control_reg: 760 1.1 christos case ide_dma_command_reg: 761 1.1 christos case ide_dma_status_reg: 762 1.1 christos case ide_dma_prd_table_address_reg0: 763 1.1 christos case ide_dma_prd_table_address_reg1: 764 1.1 christos case ide_dma_prd_table_address_reg2: 765 1.1 christos case ide_dma_prd_table_address_reg3: 766 1.1.1.3 christos *(uint8_t*)dest = controller->reg[reg]; 767 1.1 christos break; 768 1.1 christos default: 769 1.1.1.3 christos device_error(me, "bus-error at address 0x%lx", (unsigned long)addr); 770 1.1 christos break; 771 1.1 christos } 772 1.1 christos return nr_bytes; 773 1.1 christos } 774 1.1 christos 775 1.1 christos 776 1.1 christos static unsigned 777 1.1 christos hw_ide_io_write_buffer(device *me, 778 1.1 christos const void *source, 779 1.1 christos int space, 780 1.1 christos unsigned_word addr, 781 1.1 christos unsigned nr_bytes, 782 1.1 christos cpu *processor, 783 1.1 christos unsigned_word cia) 784 1.1 christos { 785 1.1 christos hw_ide_device *ide = (hw_ide_device *)device_data(me); 786 1.1 christos int control_nr; 787 1.1 christos int reg; 788 1.1 christos ide_controller *controller; 789 1.1 christos 790 1.1 christos /* find the interface */ 791 1.1 christos decode_address(me, &ide->decoder, space, addr, &control_nr, ®, is_write); 792 1.1 christos controller = &ide->controller[control_nr]; 793 1.1 christos 794 1.1 christos /* process the access */ 795 1.1 christos switch (reg) { 796 1.1 christos case ide_data_reg: 797 1.1 christos do_fifo_write(me, controller, source, nr_bytes); 798 1.1 christos break; 799 1.1 christos case ide_command_reg: 800 1.1.1.3 christos do_command(me, controller, *(uint8_t*)source); 801 1.1 christos break; 802 1.1 christos case ide_control_reg: 803 1.1.1.3 christos controller->reg[reg] = *(uint8_t*)source; 804 1.1 christos /* possibly cancel interrupts */ 805 1.1 christos if ((controller->reg[reg] & 0x02) == 0x02) 806 1.1 christos clear_interrupt(me, controller); 807 1.1 christos break; 808 1.1 christos case ide_feature_reg: 809 1.1 christos case ide_sector_count_reg: 810 1.1 christos case ide_sector_number_reg: 811 1.1 christos case ide_cylinder_reg0: 812 1.1 christos case ide_cylinder_reg1: 813 1.1 christos case ide_drive_head_reg: 814 1.1 christos case ide_dma_command_reg: 815 1.1 christos case ide_dma_status_reg: 816 1.1 christos case ide_dma_prd_table_address_reg0: 817 1.1 christos case ide_dma_prd_table_address_reg1: 818 1.1 christos case ide_dma_prd_table_address_reg2: 819 1.1 christos case ide_dma_prd_table_address_reg3: 820 1.1.1.3 christos controller->reg[reg] = *(uint8_t*)source; 821 1.1 christos break; 822 1.1 christos default: 823 1.1.1.3 christos device_error(me, "bus-error at 0x%lx", (unsigned long)addr); 824 1.1 christos break; 825 1.1 christos } 826 1.1 christos return nr_bytes; 827 1.1 christos } 828 1.1 christos 829 1.1 christos 830 1.1 christos static const device_interrupt_port_descriptor hw_ide_interrupt_ports[] = { 831 1.1 christos { "a", 0, 0 }, 832 1.1 christos { "b", 1, 0 }, 833 1.1 christos { "c", 2, 0 }, 834 1.1 christos { "d", 3, 0 }, 835 1.1 christos { NULL } 836 1.1 christos }; 837 1.1 christos 838 1.1 christos 839 1.1 christos 840 1.1 christos static device_callbacks const hw_ide_callbacks = { 841 1.1 christos { hw_ide_init_address, }, 842 1.1 christos { hw_ide_attach_address, }, /* attach */ 843 1.1 christos { hw_ide_io_read_buffer, hw_ide_io_write_buffer, }, 844 1.1 christos { NULL, }, /* DMA */ 845 1.1 christos { NULL, NULL, hw_ide_interrupt_ports }, /* interrupt */ 846 1.1 christos { generic_device_unit_decode, 847 1.1 christos generic_device_unit_encode, 848 1.1 christos generic_device_address_to_attach_address, 849 1.1 christos generic_device_size_to_attach_size }, 850 1.1 christos }; 851 1.1 christos 852 1.1 christos 853 1.1 christos static void * 854 1.1 christos hw_ide_create(const char *name, 855 1.1 christos const device_unit *unit_address, 856 1.1 christos const char *args) 857 1.1 christos { 858 1.1 christos hw_ide_device *ide = ZALLOC(hw_ide_device); 859 1.1 christos return ide; 860 1.1 christos } 861 1.1 christos 862 1.1 christos 863 1.1 christos const device_descriptor hw_ide_device_descriptor[] = { 864 1.1 christos { "ide", hw_ide_create, &hw_ide_callbacks }, 865 1.1 christos { NULL, }, 866 1.1 christos }; 867 1.1 christos 868 1.1 christos #endif /* _HW_IDE_ */ 869