hw_ide.c revision 1.1.1.2 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 christos The controller has separate independant 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 christos Note: the fouth 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 christos unsigned8 reg[nr_ide_registers];
228 1.1 christos unsigned8 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 christos signed64 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 christos static unsigned8
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 christos *(unsigned8*)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 christos *(unsigned8*)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 christos *(unsigned8*)dest = controller->reg[reg];
767 1.1 christos break;
768 1.1 christos default:
769 1.1 christos device_error(me, "bus-error at address 0x%lx", 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 christos do_command(me, controller, *(unsigned8*)source);
801 1.1 christos break;
802 1.1 christos case ide_control_reg:
803 1.1 christos controller->reg[reg] = *(unsigned8*)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 christos controller->reg[reg] = *(unsigned8*)source;
821 1.1 christos break;
822 1.1 christos default:
823 1.1 christos device_error(me, "bus-error at 0x%lx", 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