~ubuntu-branches/ubuntu/trusty/grub2/trusty-updates

« back to all changes in this revision

Viewing changes to disk/ata.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Millan
  • Date: 2007-11-01 13:18:51 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 15.
  • Revision ID: james.westby@ubuntu.com-20071101131851-63uqsb4dax2h1cbm
Tags: upstream-1.95+20071101
ImportĀ upstreamĀ versionĀ 1.95+20071101

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ata.c - ATA disk access.  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2007  Free Software Foundation, Inc.
 
5
 *
 
6
 *  GRUB is free software: you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation, either version 3 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  GRUB is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <grub/dl.h>
 
21
#include <grub/misc.h>
 
22
#include <grub/disk.h>
 
23
#include <grub/mm.h>
 
24
/* XXX: For now this only works on i386.  */
 
25
#include <grub/cpu/io.h>
 
26
#include <grub/machine/time.h>
 
27
#include <grub/machine/biosdisk.h>
 
28
 
 
29
typedef enum
 
30
  {
 
31
    GRUB_ATA_CHS,
 
32
    GRUB_ATA_LBA,
 
33
    GRUB_ATA_LBA48
 
34
  } grub_ata_addressing_t;
 
35
 
 
36
/* At the moment, only two IDE ports are supported.  */
 
37
static const int grub_ata_ioaddress[] = { 0x1f0, 0x170 };
 
38
static const int grub_ata_ioaddress2[] = { 0x3f6, 0x376 };
 
39
 
 
40
#define GRUB_CDROM_SECTOR_SIZE  2048
 
41
 
 
42
#define GRUB_ATA_REG_DATA       0
 
43
#define GRUB_ATA_REG_ERROR      1
 
44
#define GRUB_ATA_REG_FEATURES   1
 
45
#define GRUB_ATA_REG_SECTORS    2
 
46
#define GRUB_ATA_REG_SECTNUM    3
 
47
#define GRUB_ATA_REG_CYLLSB     4
 
48
#define GRUB_ATA_REG_CYLMSB     5
 
49
#define GRUB_ATA_REG_LBALOW     3
 
50
#define GRUB_ATA_REG_LBAMID     4
 
51
#define GRUB_ATA_REG_LBAHIGH    5
 
52
#define GRUB_ATA_REG_DISK       6
 
53
#define GRUB_ATA_REG_CMD        7
 
54
#define GRUB_ATA_REG_STATUS     7
 
55
 
 
56
#define GRUB_ATA_REG2_CONTROL   0
 
57
 
 
58
enum grub_ata_commands
 
59
  {
 
60
    GRUB_ATA_CMD_READ_SECTORS = 0x20,
 
61
    GRUB_ATA_CMD_READ_SECTORS_EXT = 0x24,
 
62
    GRUB_ATA_CMD_WRITE_SECTORS = 0x30,
 
63
    GRUB_ATA_CMD_WRITE_SECTORS_EXT = 0x34,
 
64
    GRUB_ATA_CMD_IDENTIFY_DEVICE = 0xEC,
 
65
    GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE = 0xA1,
 
66
    GRUB_ATA_CMD_PACKET = 0xA0
 
67
  };
 
68
 
 
69
struct grub_ata_device
 
70
{
 
71
  /* IDE port to use.  */
 
72
  int port;
 
73
 
 
74
  /* IO addresses on which the registers for this device can be
 
75
     found.  */
 
76
  int ioaddress;
 
77
  int ioaddress2;
 
78
 
 
79
  /* Two devices can be connected to a single cable.  Use this field
 
80
     to select device 0 (commonly known as "master") or device 1
 
81
     (commonly known as "slave").  */
 
82
  int device;
 
83
 
 
84
  /* Addressing methods available for accessing this device.  If CHS
 
85
     is only available, use that.  Otherwise use LBA, except for the
 
86
     high sectors.  In that case use LBA48.  */
 
87
  grub_ata_addressing_t addr;
 
88
 
 
89
  /* Sector count.  */
 
90
  grub_size_t size;
 
91
 
 
92
  /* CHS maximums.  */
 
93
  grub_uint16_t cylinders;
 
94
  grub_uint16_t heads;
 
95
  grub_uint16_t sectors_per_track;
 
96
 
 
97
  /* Set to 0 for ATA, set to 1 for ATAPI.  */
 
98
  int atapi;
 
99
 
 
100
  struct grub_ata_device *next;
 
101
};
 
102
 
 
103
static struct grub_ata_device *grub_ata_devices;
 
104
 
 
105
static inline void
 
106
grub_ata_regset (struct grub_ata_device *dev, int reg, int val)
 
107
{
 
108
  grub_outb (val, dev->ioaddress + reg);
 
109
}
 
110
 
 
111
static inline int
 
112
grub_ata_regget (struct grub_ata_device *dev, int reg)
 
113
{
 
114
  return grub_inb (dev->ioaddress + reg);
 
115
}
 
116
 
 
117
static inline void
 
118
grub_ata_regset2 (struct grub_ata_device *dev, int reg, int val)
 
119
{
 
120
  grub_outb (val, dev->ioaddress2 + reg);
 
121
}
 
122
 
 
123
static inline int
 
124
grub_ata_regget2 (struct grub_ata_device *dev, int reg)
 
125
{
 
126
  return grub_inb (dev->ioaddress2 + reg);
 
127
}
 
128
 
 
129
/* Wait until the device DEV has the status set to ready.  */
 
130
static inline void
 
131
grub_ata_wait_busy (struct grub_ata_device *dev)
 
132
{
 
133
  while ((grub_ata_regget (dev, GRUB_ATA_REG_STATUS) & 0x80));
 
134
}
 
135
 
 
136
static inline void
 
137
grub_ata_wait_drq (struct grub_ata_device *dev)
 
138
{
 
139
  while (! (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) & 0x08));
 
140
}
 
141
 
 
142
static inline void
 
143
grub_ata_wait (void)
 
144
{
 
145
  grub_uint32_t  time;
 
146
  time = grub_get_rtc ();
 
147
 
 
148
  while (time + 1 > grub_get_rtc ());
 
149
}
 
150
 
 
151
/* Byteorder has to be changed before strings can be read.  */
 
152
static inline void
 
153
grub_ata_strncpy (char *dst, char *src, grub_size_t len)
 
154
{
 
155
  grub_uint16_t *src16 = (grub_uint16_t *) src;
 
156
  grub_uint16_t *dst16 = (grub_uint16_t *) dst;
 
157
  unsigned int i;
 
158
 
 
159
  for (i = 0; i < len / 2; i++)
 
160
    *(dst16++) = grub_be_to_cpu16(*(src16++));
 
161
  dst[len] = '\0';
 
162
}
 
163
 
 
164
static int
 
165
grub_ata_pio_read (struct grub_ata_device *dev, char *buf,
 
166
                   grub_size_t size)
 
167
{
 
168
  grub_uint16_t *buf16 = (grub_uint16_t *) buf;
 
169
  unsigned int i;
 
170
 
 
171
  /* Make sure the read command is processed.  */
 
172
  grub_ata_wait ();
 
173
 
 
174
  if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) & 1)
 
175
    return grub_ata_regget (dev, GRUB_ATA_REG_ERROR);
 
176
 
 
177
  /* Wait until the data is available.  */
 
178
  grub_ata_wait_drq (dev);
 
179
 
 
180
  /* Read in the data, word by word.  */
 
181
  for (i = 0; i < size / 2; i++)
 
182
    buf16[i] = grub_le_to_cpu16 (grub_inw(dev->ioaddress + GRUB_ATA_REG_DATA));
 
183
 
 
184
  /* XXX: Do some error checks.  */
 
185
 
 
186
  return 0;
 
187
}
 
188
 
 
189
static grub_err_t
 
190
grub_ata_pio_write (struct grub_ata_device *dev, char *buf,
 
191
                    grub_size_t size)
 
192
{
 
193
  grub_uint16_t *buf16 = (grub_uint16_t *) buf;
 
194
  unsigned int i;
 
195
 
 
196
  /* Make sure the write command is processed.  */
 
197
  grub_ata_wait ();
 
198
 
 
199
  /* Wait until the device is ready to write.  */
 
200
  grub_ata_wait_drq (dev);
 
201
 
 
202
  /* Write the data, word by word.  */
 
203
  for (i = 0; i < size / 2; i++)
 
204
    grub_outw(grub_cpu_to_le16 (buf16[i]), dev->ioaddress + GRUB_ATA_REG_DATA);
 
205
 
 
206
  /* XXX: Do some error checks.  */
 
207
 
 
208
  return 0;
 
209
}
 
210
 
 
211
static void
 
212
grub_ata_dumpinfo (struct grub_ata_device *dev, char *info)
 
213
{
 
214
  char text[41];
 
215
 
 
216
  /* The device information was read, dump it for debugging.  */
 
217
  grub_ata_strncpy (text, info + 20, 20);
 
218
  grub_printf ("Serial: %s\n", text);
 
219
  grub_ata_strncpy (text, info + 46, 8);
 
220
  grub_printf ("Firmware: %s\n", text);
 
221
  grub_ata_strncpy (text, info + 54, 40);
 
222
  grub_printf ("Model: %s\n", text);
 
223
 
 
224
  grub_printf ("Addressing: %d\n", dev->addr);
 
225
  grub_printf ("#sectors: %d\n", dev->size);
 
226
 
 
227
}
 
228
 
 
229
static grub_err_t
 
230
grub_atapi_identify (struct grub_ata_device *dev)
 
231
{
 
232
  char *info;
 
233
 
 
234
  info = grub_malloc (256);
 
235
  if (! info)
 
236
    return grub_errno;
 
237
 
 
238
  grub_ata_wait_busy (dev);
 
239
 
 
240
  grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
 
241
  grub_ata_regset (dev, GRUB_ATA_REG_CMD,
 
242
                   GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE);
 
243
 
 
244
  grub_ata_pio_read (dev, info, 256);
 
245
 
 
246
  dev->atapi = 1;
 
247
 
 
248
  grub_ata_dumpinfo (dev, info);
 
249
 
 
250
  grub_free (info);
 
251
 
 
252
  return 0;
 
253
}
 
254
 
 
255
static grub_err_t
 
256
grub_atapi_packet (struct grub_ata_device *dev, char *packet)
 
257
{
 
258
  grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
 
259
  grub_ata_regset (dev, GRUB_ATA_REG_FEATURES, 0);
 
260
  grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0);
 
261
  grub_ata_regset (dev, GRUB_ATA_REG_LBAHIGH, 0xFF);
 
262
  grub_ata_regset (dev, GRUB_ATA_REG_LBAMID, 0xFF);
 
263
  grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_PACKET);
 
264
 
 
265
  grub_ata_pio_write (dev, packet, 12);
 
266
 
 
267
  return 0;
 
268
}
 
269
 
 
270
static grub_err_t
 
271
grub_ata_identify (struct grub_ata_device *dev)
 
272
{
 
273
  char *info;
 
274
  grub_uint16_t *info16;
 
275
  int ataerr;
 
276
 
 
277
  info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
 
278
  if (! info)
 
279
    return grub_errno;
 
280
 
 
281
  info16 = (grub_uint16_t *) info;
 
282
 
 
283
  grub_ata_wait_busy (dev);
 
284
 
 
285
  grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
 
286
  grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_DEVICE);
 
287
 
 
288
  ataerr = grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE);
 
289
  if (ataerr & 4)
 
290
    {
 
291
      /* ATAPI device detected.  */
 
292
      grub_free(info);
 
293
      return grub_atapi_identify (dev);
 
294
    }
 
295
  else if (ataerr)
 
296
    {
 
297
      /* Error.  */
 
298
      grub_free(info);
 
299
      return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
 
300
                         "device can not be identified");
 
301
    }
 
302
 
 
303
  /* Now it is certain that this is not an ATAPI device.  */
 
304
  dev->atapi = 0;
 
305
 
 
306
  /* CHS is always supported.  */
 
307
  dev->addr = GRUB_ATA_CHS;
 
308
 
 
309
  /* Check if LBA is supported.  */
 
310
  if (info16[49] & (1 << 9))
 
311
    {
 
312
      /* Check if LBA48 is supported.  */
 
313
      if (info16[83] & (1 << 10))
 
314
        dev->addr = GRUB_ATA_LBA48;
 
315
      else
 
316
        dev->addr = GRUB_ATA_LBA;
 
317
    }
 
318
 
 
319
  /* Determine the amount of sectors.  */
 
320
  if (dev->addr != GRUB_ATA_LBA48)
 
321
    dev->size = grub_le_to_cpu32(*((grub_uint32_t *) &info16[60]));
 
322
  else
 
323
    dev->size = grub_le_to_cpu64(*((grub_uint32_t *) &info16[100]));
 
324
 
 
325
  /* Read CHS information.  */
 
326
  dev->cylinders = info16[1];
 
327
  dev->heads = info16[3];
 
328
  dev->sectors_per_track = info16[6];
 
329
 
 
330
  grub_ata_dumpinfo (dev, info);
 
331
 
 
332
  grub_free(info);
 
333
 
 
334
  return 0;
 
335
}
 
336
 
 
337
static grub_err_t
 
338
grub_ata_initialize (void)
 
339
{
 
340
  struct grub_ata_device *dev;
 
341
  struct grub_ata_device **devp;
 
342
  int port;
 
343
  int device;
 
344
 
 
345
  for (port = 0; port <= 1; port++)
 
346
    {
 
347
      for (device = 0; device <= 1; device++)
 
348
        {
 
349
          dev = grub_malloc (sizeof(*dev));
 
350
          if (! dev)
 
351
            return grub_errno;
 
352
 
 
353
          /* Setup the device information.  */
 
354
          dev->port = port;
 
355
          dev->device = device;
 
356
          dev->ioaddress = grub_ata_ioaddress[dev->port];
 
357
          dev->ioaddress2 = grub_ata_ioaddress2[dev->port];
 
358
          dev->next = NULL;
 
359
 
 
360
          /* Try to detect if the port is in use by writing to it,
 
361
             waiting for a while and reading it again.  If the value
 
362
             was preserved, there is a device connected.  */
 
363
          grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
 
364
          grub_ata_wait ();
 
365
          grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A);  
 
366
          grub_ata_wait ();
 
367
          if (grub_ata_regget (dev, GRUB_ATA_REG_SECTORS) != 0x5A)
 
368
            {
 
369
              grub_free(dev);
 
370
              continue;
 
371
            }
 
372
 
 
373
          /* Detect if the device is present by issuing a reset.  */
 
374
          grub_ata_regset2 (dev, GRUB_ATA_REG2_CONTROL, 6);
 
375
          grub_ata_wait ();
 
376
          grub_ata_regset2 (dev, GRUB_ATA_REG2_CONTROL, 2);
 
377
          grub_ata_wait ();
 
378
          grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
 
379
          grub_ata_wait ();
 
380
 
 
381
          /* XXX: Check some registers to see if the reset worked as
 
382
             expected for this device.  */
 
383
#if 1
 
384
          /* Enable for ATAPI .  */
 
385
          if (grub_ata_regget (dev, GRUB_ATA_REG_CYLLSB) != 0x14
 
386
              || grub_ata_regget (dev, GRUB_ATA_REG_CYLMSB) != 0xeb)
 
387
#endif
 
388
          if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) == 0
 
389
              || (grub_ata_regget (dev, GRUB_ATA_REG_CYLLSB) != 0
 
390
                  && grub_ata_regget (dev, GRUB_ATA_REG_CYLMSB) != 0
 
391
                  && grub_ata_regget (dev, GRUB_ATA_REG_CYLLSB) != 0x3c
 
392
                  && grub_ata_regget (dev, GRUB_ATA_REG_CYLLSB) != 0xc3))
 
393
            {
 
394
              grub_free (dev);
 
395
              continue;
 
396
            }
 
397
 
 
398
          /* Use the IDENTIFY DEVICE command to query the device.  */
 
399
          if (grub_ata_identify (dev))
 
400
            {
 
401
              grub_free (dev);
 
402
              continue;
 
403
            }
 
404
 
 
405
          /* Register the device.  */
 
406
          for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next);
 
407
          *devp = dev;
 
408
        }
 
409
    }
 
410
 
 
411
  return 0;
 
412
}
 
413
 
 
414
static void
 
415
grub_ata_setlba (struct grub_ata_device *dev, grub_disk_addr_t sector,
 
416
                 grub_size_t size)
 
417
{
 
418
  grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, size);
 
419
  grub_ata_regset (dev, GRUB_ATA_REG_LBALOW, sector & 0xFF);
 
420
  grub_ata_regset (dev, GRUB_ATA_REG_LBAMID, (sector >> 8) & 0xFF);
 
421
  grub_ata_regset (dev, GRUB_ATA_REG_LBAHIGH, (sector >> 16) & 0xFF);
 
422
}
 
423
 
 
424
static grub_err_t
 
425
grub_ata_setaddress (struct grub_ata_device *dev,
 
426
                     grub_ata_addressing_t addressing,
 
427
                     grub_disk_addr_t sector,
 
428
                     grub_size_t size)
 
429
{
 
430
  grub_ata_wait_busy (dev);
 
431
 
 
432
  switch (addressing)
 
433
    {
 
434
    case GRUB_ATA_CHS:
 
435
      {
 
436
        unsigned int cylinder;
 
437
        unsigned int head;
 
438
        unsigned int sect;
 
439
 
 
440
        /* Calculate the sector, cylinder and head to use.  */
 
441
        sect = ((grub_uint32_t) sector % dev->sectors_per_track) + 1;
 
442
        cylinder = (((grub_uint32_t) sector / dev->sectors_per_track)
 
443
                    / dev->heads);
 
444
        head = ((grub_uint32_t) sector / dev->sectors_per_track) % dev->heads;
 
445
 
 
446
        if (sect > dev->sectors_per_track
 
447
            || cylinder > dev->cylinders
 
448
            || head > dev->heads)
 
449
          return grub_error (GRUB_ERR_OUT_OF_RANGE,
 
450
                             "sector %d can not be addressed "
 
451
                             "using CHS addressing", sector);
 
452
 
 
453
        grub_ata_regset (dev, GRUB_ATA_REG_SECTNUM, sect);
 
454
        grub_ata_regset (dev, GRUB_ATA_REG_CYLLSB, cylinder & 0xFF);
 
455
        grub_ata_regset (dev, GRUB_ATA_REG_CYLMSB, cylinder >> 8);
 
456
        grub_ata_regset (dev, GRUB_ATA_REG_DISK, (dev->device << 4) | head);
 
457
 
 
458
        break;
 
459
      }
 
460
 
 
461
    case GRUB_ATA_LBA:
 
462
      if (size == 256)
 
463
        size = 0;
 
464
      grub_ata_setlba (dev, sector, size);
 
465
      grub_ata_regset (dev, GRUB_ATA_REG_DISK,
 
466
                       0xE0 | (dev->device << 4) | ((sector >> 24) & 0x0F));
 
467
      break;
 
468
 
 
469
    case GRUB_ATA_LBA48:
 
470
      if (size == 65536)
 
471
        size = 0;
 
472
 
 
473
      /* Set "Previous".  */
 
474
      grub_ata_setlba (dev, sector >> 24, size >> 8);
 
475
      /* Set "Current".  */
 
476
      grub_ata_setlba (dev, sector, size);
 
477
      grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | (dev->device << 4));
 
478
 
 
479
      break;
 
480
    }
 
481
 
 
482
  return GRUB_ERR_NONE;
 
483
}
 
484
 
 
485
static grub_err_t
 
486
grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
 
487
                    grub_size_t size, char *buf, int rw)
 
488
{
 
489
  struct grub_ata_device *dev = (struct grub_ata_device *) disk->data;
 
490
  grub_size_t cnt;
 
491
  grub_size_t batch;
 
492
  grub_ata_addressing_t addressing;
 
493
  int cmd;
 
494
  int cmd_write;
 
495
 
 
496
  addressing = dev->addr;
 
497
 
 
498
  if (addressing == GRUB_ATA_LBA48 && ((sector + size) >> 28) != 0)
 
499
    {
 
500
      batch = 65536;
 
501
      cmd = GRUB_ATA_CMD_READ_SECTORS_EXT;
 
502
      cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_EXT;
 
503
    }
 
504
  else
 
505
    {
 
506
      if (addressing == GRUB_ATA_LBA48)
 
507
        addressing = GRUB_ATA_LBA;
 
508
      batch = 256;
 
509
      cmd = GRUB_ATA_CMD_READ_SECTORS;
 
510
      cmd_write = GRUB_ATA_CMD_WRITE_SECTORS;
 
511
    }
 
512
 
 
513
  cnt = size / batch;
 
514
 
 
515
  /* Read/write batches of 256/65536 sectors, when more than 256/65536
 
516
     sectors should be read/written.  */
 
517
  for (; cnt; cnt--)
 
518
    {
 
519
      if (grub_ata_setaddress (dev, addressing, sector, batch))
 
520
        return grub_errno;
 
521
 
 
522
      if (rw == 0)
 
523
        {
 
524
          /* Read 256/65536 sectors.  */
 
525
          grub_ata_regset (dev, GRUB_ATA_REG_CMD, cmd);
 
526
          if (grub_ata_pio_read (dev, buf,
 
527
                                 batch * GRUB_DISK_SECTOR_SIZE))
 
528
            return grub_errno;
 
529
        }
 
530
      else
 
531
        {
 
532
          /* Write 256/65536 sectors.  */
 
533
          grub_ata_regset (dev, GRUB_ATA_REG_CMD, cmd_write);
 
534
          if (grub_ata_pio_write (dev, buf,
 
535
                                  batch * GRUB_DISK_SECTOR_SIZE))
 
536
            return grub_errno;
 
537
        }
 
538
 
 
539
      buf += batch * GRUB_DISK_SECTOR_SIZE;
 
540
      sector += batch * GRUB_DISK_SECTOR_SIZE;
 
541
    }
 
542
 
 
543
  /* Read/write just a "few" sectors.  */
 
544
  if (grub_ata_setaddress (dev, addressing, sector, size % batch))
 
545
    return grub_errno;
 
546
 
 
547
  if (rw == 0)
 
548
    {
 
549
      /* Read sectors.  */
 
550
      grub_ata_regset (dev, GRUB_ATA_REG_CMD, cmd);
 
551
      if (grub_ata_pio_read (dev, buf,
 
552
                             (size % batch) * GRUB_DISK_SECTOR_SIZE))
 
553
        return grub_errno;
 
554
    } else {
 
555
      /* Write sectors.  */
 
556
      grub_ata_regset (dev, GRUB_ATA_REG_CMD, cmd_write);
 
557
      if (grub_ata_pio_write (dev, buf,
 
558
                              (size % batch) * GRUB_DISK_SECTOR_SIZE))
 
559
        return grub_errno;
 
560
    }
 
561
 
 
562
  return GRUB_ERR_NONE;
 
563
}
 
564
 
 
565
 
 
566
 
 
567
static int
 
568
grub_ata_iterate (int (*hook) (const char *name))
 
569
{
 
570
  struct grub_ata_device *dev;
 
571
 
 
572
  for (dev = grub_ata_devices; dev; dev = dev->next)
 
573
    {
 
574
      char devname[5];
 
575
      grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
 
576
 
 
577
      if (hook (devname))
 
578
        return 1;
 
579
    }
 
580
 
 
581
  return 0;
 
582
}
 
583
 
 
584
static grub_err_t
 
585
grub_ata_open (const char *name, grub_disk_t disk)
 
586
{
 
587
  struct grub_ata_device *dev;
 
588
 
 
589
  for (dev = grub_ata_devices; dev; dev = dev->next)
 
590
    {
 
591
      char devname[5];
 
592
      grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
 
593
      if (grub_strcmp (name, devname) == 0)
 
594
        break;
 
595
    }
 
596
 
 
597
  if (! dev)
 
598
    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device");
 
599
 
 
600
  if (dev->atapi)
 
601
    disk->total_sectors = 9000000; /* XXX */
 
602
  else
 
603
    disk->total_sectors = dev->size;
 
604
 
 
605
  disk->id = (int) dev;
 
606
  
 
607
  disk->has_partitions = !dev->atapi;
 
608
  disk->data = dev;
 
609
 
 
610
  return 0;
 
611
}
 
612
 
 
613
static void
 
614
grub_ata_close (grub_disk_t disk __attribute__((unused)))
 
615
{
 
616
  
 
617
}
 
618
 
 
619
struct grub_atapi_read
 
620
{
 
621
  grub_uint8_t code;
 
622
  grub_uint8_t reserved1;
 
623
  grub_uint32_t lba;
 
624
  grub_uint32_t length;
 
625
  grub_uint8_t reserved2[2];
 
626
} __attribute__((packed));
 
627
 
 
628
static grub_err_t
 
629
grub_atapi_readsector (struct grub_ata_device *dev,
 
630
                       char *buf, grub_disk_addr_t sector)
 
631
{
 
632
  struct grub_atapi_read readcmd;
 
633
 
 
634
  readcmd.code = 0xA8;
 
635
  readcmd.lba = grub_cpu_to_be32 (sector);
 
636
  readcmd.length = grub_cpu_to_be32 (1);
 
637
 
 
638
  grub_atapi_packet (dev, (char *) &readcmd);
 
639
  grub_ata_pio_read (dev, buf, GRUB_CDROM_SECTOR_SIZE);
 
640
 
 
641
  return 0;
 
642
}
 
643
 
 
644
static grub_err_t
 
645
grub_ata_read (grub_disk_t disk, grub_disk_addr_t sector,
 
646
               grub_size_t size, char *buf)
 
647
{
 
648
  struct grub_ata_device *dev = (struct grub_ata_device *) disk->data;
 
649
  int cdsector;
 
650
  char *sbuf;
 
651
 
 
652
  if (! dev->atapi)
 
653
    return grub_ata_readwrite (disk, sector, size, buf, 0);
 
654
 
 
655
  /* ATAPI is being used, so try to read from CDROM using ATAPI.  */
 
656
 
 
657
  sbuf = grub_malloc (GRUB_CDROM_SECTOR_SIZE);
 
658
  if (! sbuf)
 
659
    return grub_errno;
 
660
 
 
661
  /* CDROMs have sectors of 2048 bytes, so chop them into pieces of
 
662
     512 bytes.  */
 
663
  while (size > 0)
 
664
    {
 
665
      int rsize;
 
666
      int offset;
 
667
      int max;
 
668
 
 
669
      cdsector = sector >> 2;
 
670
      rsize = ((size * GRUB_DISK_SECTOR_SIZE > GRUB_CDROM_SECTOR_SIZE)
 
671
               ? GRUB_CDROM_SECTOR_SIZE : size * GRUB_DISK_SECTOR_SIZE);
 
672
      offset = (sector & 3) * GRUB_DISK_SECTOR_SIZE;
 
673
      max = GRUB_CDROM_SECTOR_SIZE - offset;
 
674
      rsize = (rsize > max) ? max : rsize;
 
675
 
 
676
      grub_atapi_readsector (dev, sbuf, cdsector);
 
677
      grub_memcpy (buf + offset, sbuf, rsize);
 
678
 
 
679
      buf += rsize;
 
680
      size -= rsize / GRUB_DISK_SECTOR_SIZE;
 
681
      sector += rsize / GRUB_DISK_SECTOR_SIZE;
 
682
    }
 
683
 
 
684
  grub_free (sbuf);
 
685
 
 
686
  return 0;
 
687
}
 
688
 
 
689
static grub_err_t
 
690
grub_ata_write (grub_disk_t disk,
 
691
                grub_disk_addr_t sector,
 
692
                grub_size_t size,
 
693
                const char *buf)
 
694
{
 
695
#if 1
 
696
  return GRUB_ERR_NOT_IMPLEMENTED_YET;
 
697
#else
 
698
  return grub_ata_readwrite (disk, sector, size, (char *) buf, 1);
 
699
#endif
 
700
}
 
701
 
 
702
static struct grub_disk_dev grub_atadisk_dev =
 
703
  {
 
704
    .name = "ATA",
 
705
    .id = GRUB_DISK_DEVICE_ATA_ID,
 
706
    .iterate = grub_ata_iterate,
 
707
    .open = grub_ata_open,
 
708
    .close = grub_ata_close,
 
709
    .read = grub_ata_read,
 
710
    .write = grub_ata_write,
 
711
    .next = 0
 
712
  };
 
713
 
 
714
 
 
715
 
 
716
GRUB_MOD_INIT(ata)
 
717
{
 
718
  (void) mod;                   /* To stop warning. */
 
719
 
 
720
  /* XXX: To prevent two drivers operating on the same disks.  */
 
721
  grub_biosdisk_fini ();
 
722
  
 
723
  /* ATA initialization.  */
 
724
  grub_ata_initialize ();
 
725
 
 
726
  grub_disk_dev_register (&grub_atadisk_dev);
 
727
}
 
728
 
 
729
GRUB_MOD_FINI(ata)
 
730
{
 
731
  grub_disk_dev_unregister (&grub_atadisk_dev);
 
732
}