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