1 /* This file is part of the program psim.
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>.
24 #include "device_table.h"
38 cdrom - read-only removable mass storage device
40 disk - mass storage device
42 floppy - removable mass storage device
48 Mass storage devices such as a hard-disk or cdrom-drive are not
49 normally directly connected to the processor. Instead, these
50 devices are attached to a logical bus, such as SCSI or IDE, and
51 then a controller of that bus is made accessible to the processor.
53 Reflecting this, within a device tree, mass storage devices such as
54 a <<cdrom>>, <<disk>> or <<floppy>> are created as children of of a
55 logical bus controller node (such as a SCSI or IDE interface).
56 That controller, in turn, would be made the child of a physical bus
57 node that is directly accessible to the processor.
59 The above mass storage devices provide two interfaces - a logical
62 At the physical level the <<device_io_...>> functions can be used
63 perform reads and writes of the raw media. The address being
64 interpreted as an offset from the start of the disk.
66 At the logical level, it is possible to create an instance of the
67 disk that provides access to any of the physical media, a disk
68 partition, or even a file within a partition. The <<disk-label>>
69 package, which implements this functionality, is described
70 elsewhere. Both the Open Firmware and Moto BUG rom emulations
71 support this interface.
73 Block devices such as the <<floppy>> and <<cdrom>> have removable
74 media. At the programmer level, the media can be changed using the
75 <<change_media>> ioctl. From within GDB, a <<change-media>>
76 operation can be initated by using the command.
84 file = <file-name> (required)
86 The name of the file that contains an image of the disk. For
87 <<disk>> and <<floppy>> devices, the image will be opened for both
88 reading and writing. Multiple image files may be specified, the
89 second and later files being opened when <<change-media>> (with a
90 NULL file name) being specified.
93 block-size = <nr-bytes> (optional)
95 The value is returned by the block-size method. The default value
99 max-transfer = <nr-bytes> (optional)
101 The value is returned by the max-transfer method. The default value
105 #blocks = <nr-blocks> (optional)
107 The value is returned by the #blocks method. If no value is
108 present then -1 is returned.
111 read-only = <anything> (optional)
113 If this property is present, the disk file image is always opened
121 | $ psim -t 'disk-device' \
124 Add a CDROM and disk to an IDE bus. Specify the host operating
125 system's cd drive as the CD-ROM image.
127 | -o '/pci/ide/disk@0/file "disk-image' \
128 | -o '/pci/ide/cdrom@1/file "/dev/cd0a' \
131 As part of the code implementing a logical bus device (for instance
132 the IDE controller), locate the CDROM device and then read block
135 | device *cdrom = device_tree_find_device(me, "cdrom");
137 | device_io_read_buffer(cdrom, buf, 0,
138 0, 47 * sizeof(block), // space, address
139 sizeof(block), NULL, 0);
142 Use the device instance interface to read block 47 of the file
143 called <<netbsd.elf>> on the disks default partition. Similar code
144 would be used in an operating systems pre-boot loader.
146 | device_instance *netbsd =
147 | device_create_instance(root, "/pci/ide/disk:,\netbsd.elf");
149 | device_instance_seek(netbsd, 0, 47 * sizeof(block));
150 | device_instance_read(netbsd, block, sizeof(block));
156 The block device specification includes mechanisms for determining
157 the physical device characteristics - such as the disks size.
158 Currently this mechanism is not implemented.
160 The functionality of this device (in particular the device instance
161 interface) depends on the implementation of <<disk-label>> package.
162 That package may not be fully implemented.
164 The disk does not know its size. Hence it relies on the failure of
165 fread(), fwrite() and fseek() calls to detect errors.
167 The disk size is limited by the addressable range covered by
168 unsigned_word (addr). An extension would be to instead use the
169 concatenated value space:addr.
171 The method #blocks should `stat' the disk to determine the number
172 of blocks if there is no #blocks property.
174 It would appear that OpenFirmware does not define a client call for
175 changing (ejecting) the media of a device.
179 typedef struct _hw_disk_device
{
184 /* unsigned_word size; */
188 typedef struct _hw_disk_instance
{
190 hw_disk_device
*disk
;
195 open_disk_image(device
*me
,
196 hw_disk_device
*disk
,
199 if (disk
->image
!= NULL
)
201 if (disk
->name
!= NULL
)
203 disk
->name
= strdup(name
);
204 disk
->image
= fopen(disk
->name
, disk
->read_only
? "r" : "r+");
205 if (disk
->image
== NULL
) {
206 perror(device_name(me
));
207 device_error(me
, "open %s failed\n", disk
->name
);
210 DTRACE(disk
, ("image %s (%s)\n",
212 (disk
->read_only
? "read-only" : "read-write")));
216 hw_disk_init_address(device
*me
)
218 hw_disk_device
*disk
= device_data(me
);
219 unsigned_word address
;
223 /* attach to the parent. Since the bus is logical, attach using just
224 the unit-address (size must be zero) */
225 device_address_to_attach_address(device_parent(me
), device_unit_address(me
),
226 &space
, &address
, me
);
227 device_attach_address(device_parent(me
), attach_callback
,
228 space
, address
, 0/*size*/, access_read_write_exec
,
231 /* Tell the world we are a disk. */
232 device_add_string_property(me
, "device_type", "block");
234 /* get the name of the file specifying the disk image */
235 disk
->name_index
= 0;
236 disk
->nr_names
= device_find_string_array_property(me
, "file",
237 disk
->name_index
, &name
);
239 device_error(me
, "invalid file property");
241 /* is it a RO device? */
243 (strcmp(device_name(me
), "disk") != 0
244 && strcmp(device_name(me
), "floppy") != 0
245 && device_find_property(me
, "read-only") == NULL
);
248 open_disk_image(me
, disk
, name
);
252 hw_disk_ioctl(device
*me
,
255 device_ioctl_request request
,
259 case device_ioctl_change_media
:
261 hw_disk_device
*disk
= device_data(me
);
262 const char *name
= va_arg(ap
, const char *);
264 disk
->name_index
= -1;
267 disk
->name_index
= (disk
->name_index
+ 1) % disk
->nr_names
;
268 if (!device_find_string_array_property(me
, "file",
269 disk
->name_index
, &name
))
270 device_error(me
, "invalid file property");
272 open_disk_image(me
, disk
, name
);
276 device_error(me
, "insupported ioctl request");
287 hw_disk_io_read_buffer(device
*me
,
295 hw_disk_device
*disk
= device_data(me
);
296 unsigned nr_bytes_read
;
298 device_error(me
, "read - extended disk addressing unimplemented");
301 else if (fseek(disk
->image
, addr
, SEEK_SET
) < 0)
303 else if (fread(dest
, nr_bytes
, 1, disk
->image
) != 1)
306 nr_bytes_read
= nr_bytes
;
307 DTRACE(disk
, ("io-read - address 0x%lx, nr-bytes-read %d, requested %d\n",
308 (unsigned long) addr
, (int)nr_bytes_read
, (int)nr_bytes
));
309 return nr_bytes_read
;
314 hw_disk_io_write_buffer(device
*me
,
322 hw_disk_device
*disk
= device_data(me
);
323 unsigned nr_bytes_written
;
325 device_error(me
, "write - extended disk addressing unimplemented");
327 nr_bytes_written
= 0;
328 else if (nr_bytes
== 0)
329 nr_bytes_written
= 0;
330 else if (fseek(disk
->image
, addr
, SEEK_SET
) < 0)
331 nr_bytes_written
= 0;
332 else if (fwrite(source
, nr_bytes
, 1, disk
->image
) != 1)
333 nr_bytes_written
= 0;
335 nr_bytes_written
= nr_bytes
;
336 DTRACE(disk
, ("io-write - address 0x%lx, nr-bytes-written %d, requested %d\n",
337 (unsigned long) addr
, (int)nr_bytes_written
, (int)nr_bytes
));
338 return nr_bytes_written
;
342 /* instances of the hw_disk device */
345 hw_disk_instance_delete(device_instance
*instance
)
347 hw_disk_instance
*data
= device_instance_data(instance
);
348 DITRACE(disk
, ("delete - instance=%ld\n",
349 (unsigned long)device_instance_to_external(instance
)));
354 hw_disk_instance_read(device_instance
*instance
,
358 hw_disk_instance
*data
= device_instance_data(instance
);
359 DITRACE(disk
, ("read - instance=%ld len=%ld\n",
360 (unsigned long)device_instance_to_external(instance
),
362 if ((data
->pos
+ len
) < data
->pos
)
363 return -1; /* overflow */
364 if (fseek(data
->disk
->image
, data
->pos
, SEEK_SET
) < 0)
366 if (fread(buf
, len
, 1, data
->disk
->image
) != 1)
368 data
->pos
= ftell(data
->disk
->image
);
373 hw_disk_instance_write(device_instance
*instance
,
377 hw_disk_instance
*data
= device_instance_data(instance
);
378 DITRACE(disk
, ("write - instance=%ld len=%ld\n",
379 (unsigned long)device_instance_to_external(instance
),
381 if ((data
->pos
+ len
) < data
->pos
)
382 return -1; /* overflow */
383 if (data
->disk
->read_only
)
385 if (fseek(data
->disk
->image
, data
->pos
, SEEK_SET
) < 0)
387 if (fwrite(buf
, len
, 1, data
->disk
->image
) != 1)
389 data
->pos
= ftell(data
->disk
->image
);
394 hw_disk_instance_seek(device_instance
*instance
,
395 unsigned_word pos_hi
,
396 unsigned_word pos_lo
)
398 hw_disk_instance
*data
= device_instance_data(instance
);
400 device_error(device_instance_device(instance
),
401 "seek - extended addressing unimplemented");
402 DITRACE(disk
, ("seek - instance=%ld pos_hi=%ld pos_lo=%ld\n",
403 (unsigned long)device_instance_to_external(instance
),
404 (long)pos_hi
, (long)pos_lo
));
410 hw_disk_max_transfer(device_instance
*instance
,
412 uint32_t stack_args
[/*n_stack_args*/],
414 uint32_t stack_returns
[/*n_stack_returns*/])
416 device
*me
= device_instance_device(instance
);
417 if ((n_stack_args
!= 0)
418 || (n_stack_returns
!= 1)) {
419 device_error(me
, "Incorrect number of arguments for max-transfer method\n");
423 unsigned_cell max_transfer
;
424 if (device_find_property(me
, "max-transfer"))
425 max_transfer
= device_find_integer_property(me
, "max-transfer");
428 DITRACE(disk
, ("max-transfer - instance=%ld max-transfer=%ld\n",
429 (unsigned long)device_instance_to_external(instance
),
430 (long int)max_transfer
));
431 stack_returns
[0] = max_transfer
;
437 hw_disk_block_size(device_instance
*instance
,
439 uint32_t stack_args
[/*n_stack_args*/],
441 uint32_t stack_returns
[/*n_stack_returns*/])
443 device
*me
= device_instance_device(instance
);
444 if ((n_stack_args
!= 0)
445 || (n_stack_returns
!= 1)) {
446 device_error(me
, "Incorrect number of arguments for block-size method\n");
450 unsigned_cell block_size
;
451 if (device_find_property(me
, "block-size"))
452 block_size
= device_find_integer_property(me
, "block-size");
455 DITRACE(disk
, ("block-size - instance=%ld block-size=%ld\n",
456 (unsigned long)device_instance_to_external(instance
),
457 (long int)block_size
));
458 stack_returns
[0] = block_size
;
464 hw_disk_nr_blocks(device_instance
*instance
,
466 uint32_t stack_args
[/*n_stack_args*/],
468 uint32_t stack_returns
[/*n_stack_returns*/])
470 device
*me
= device_instance_device(instance
);
471 if ((n_stack_args
!= 0)
472 || (n_stack_returns
!= 1)) {
473 device_error(me
, "Incorrect number of arguments for block-size method\n");
477 unsigned_word nr_blocks
;
478 if (device_find_property(me
, "#blocks"))
479 nr_blocks
= device_find_integer_property(me
, "#blocks");
482 DITRACE(disk
, ("#blocks - instance=%ld #blocks=%ld\n",
483 (unsigned long)device_instance_to_external(instance
),
484 (long int)nr_blocks
));
485 stack_returns
[0] = nr_blocks
;
490 static device_instance_methods hw_disk_instance_methods
[] = {
491 { "max-transfer", hw_disk_max_transfer
},
492 { "block-size", hw_disk_block_size
},
493 { "#blocks", hw_disk_nr_blocks
},
497 static const device_instance_callbacks hw_disk_instance_callbacks
= {
498 hw_disk_instance_delete
,
499 hw_disk_instance_read
,
500 hw_disk_instance_write
,
501 hw_disk_instance_seek
,
502 hw_disk_instance_methods
,
505 static device_instance
*
506 hw_disk_create_instance(device
*me
,
510 device_instance
*instance
;
511 hw_disk_device
*disk
= device_data(me
);
512 hw_disk_instance
*data
= ZALLOC(hw_disk_instance
);
515 instance
= device_create_instance_from(me
, NULL
,
518 &hw_disk_instance_callbacks
);
519 DITRACE(disk
, ("create - path=%s(%s) instance=%ld\n",
521 (unsigned long)device_instance_to_external(instance
)));
522 return pk_disklabel_create_instance(instance
, args
);
525 static device_callbacks
const hw_disk_callbacks
= {
526 { hw_disk_init_address
, NULL
},
527 { NULL
, }, /* address */
528 { hw_disk_io_read_buffer
,
529 hw_disk_io_write_buffer
, },
531 { NULL
, }, /* interrupt */
532 { NULL
, }, /* unit */
533 hw_disk_create_instance
,
539 hw_disk_create(const char *name
,
540 const device_unit
*unit_address
,
543 /* create the descriptor */
544 hw_disk_device
*hw_disk
= ZALLOC(hw_disk_device
);
549 const device_descriptor hw_disk_device_descriptor
[] = {
550 { "disk", hw_disk_create
, &hw_disk_callbacks
},
551 { "cdrom", hw_disk_create
, &hw_disk_callbacks
},
552 { "floppy", hw_disk_create
, &hw_disk_callbacks
},
556 #endif /* _HW_DISK_C_ */