Home | History | Annotate | Line # | Download | only in ppc
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, &reg, 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, &reg, 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