~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/disk/scsi.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* scsi.c - scsi support.  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2008,2009  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/disk.h>
 
21
#include <grub/dl.h>
 
22
#include <grub/kernel.h>
 
23
#include <grub/misc.h>
 
24
#include <grub/mm.h>
 
25
#include <grub/types.h>
 
26
#include <grub/scsi.h>
 
27
#include <grub/scsicmd.h>
 
28
#include <grub/time.h>
 
29
 
 
30
 
 
31
static grub_scsi_dev_t grub_scsi_dev_list;
 
32
 
 
33
void
 
34
grub_scsi_dev_register (grub_scsi_dev_t dev)
 
35
{
 
36
  dev->next = grub_scsi_dev_list;
 
37
  grub_scsi_dev_list = dev;
 
38
}
 
39
 
 
40
void
 
41
grub_scsi_dev_unregister (grub_scsi_dev_t dev)
 
42
{
 
43
  grub_scsi_dev_t *p, q;
 
44
 
 
45
  for (p = &grub_scsi_dev_list, q = *p; q; p = &(q->next), q = q->next)
 
46
    if (q == dev)
 
47
      {
 
48
        *p = q->next;
 
49
        break;
 
50
      }
 
51
}
 
52
 
 
53
 
 
54
/* Check result of previous operation.  */
 
55
static grub_err_t
 
56
grub_scsi_request_sense (grub_scsi_t scsi)
 
57
{
 
58
  struct grub_scsi_request_sense rs;
 
59
  struct grub_scsi_request_sense_data rsd;
 
60
  grub_err_t err;
 
61
 
 
62
  rs.opcode = grub_scsi_cmd_request_sense;
 
63
  rs.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
 
64
  rs.reserved1 = 0;
 
65
  rs.reserved2 = 0;
 
66
  rs.alloc_length = 0x12; /* XXX: Hardcoded for now */
 
67
  rs.control = 0;
 
68
  grub_memset (rs.pad, 0, sizeof(rs.pad));
 
69
 
 
70
  err = scsi->dev->read (scsi, sizeof (rs), (char *) &rs,
 
71
                         sizeof (rsd), (char *) &rsd);
 
72
  if (err)
 
73
    return err;
 
74
 
 
75
  return GRUB_ERR_NONE;
 
76
}
 
77
/* Self commenting... */
 
78
static grub_err_t
 
79
grub_scsi_test_unit_ready (grub_scsi_t scsi)
 
80
{
 
81
  struct grub_scsi_test_unit_ready tur;
 
82
  grub_err_t err;
 
83
  grub_err_t err_sense;
 
84
  
 
85
  tur.opcode = grub_scsi_cmd_test_unit_ready;
 
86
  tur.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
 
87
  tur.reserved1 = 0;
 
88
  tur.reserved2 = 0;
 
89
  tur.reserved3 = 0;
 
90
  tur.control = 0;
 
91
  grub_memset (tur.pad, 0, sizeof(tur.pad));
 
92
 
 
93
  err = scsi->dev->read (scsi, sizeof (tur), (char *) &tur,
 
94
                         0, NULL);
 
95
 
 
96
  /* Each SCSI command should be followed by Request Sense.
 
97
     If not so, many devices STALLs or definitely freezes. */
 
98
  err_sense = grub_scsi_request_sense (scsi);
 
99
  if (err_sense != GRUB_ERR_NONE)
 
100
        grub_errno = err;
 
101
  /* err_sense is ignored for now and Request Sense Data also... */
 
102
  
 
103
  if (err)
 
104
    return err;
 
105
 
 
106
  return GRUB_ERR_NONE;
 
107
}
 
108
 
 
109
/* Determine if the device is removable and the type of the device
 
110
   SCSI.  */
 
111
static grub_err_t
 
112
grub_scsi_inquiry (grub_scsi_t scsi)
 
113
{
 
114
  struct grub_scsi_inquiry iq;
 
115
  struct grub_scsi_inquiry_data iqd;
 
116
  grub_err_t err;
 
117
  grub_err_t err_sense;
 
118
 
 
119
  iq.opcode = grub_scsi_cmd_inquiry;
 
120
  iq.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
 
121
  iq.page = 0;
 
122
  iq.reserved = 0;
 
123
  iq.alloc_length = 0x24; /* XXX: Hardcoded for now */
 
124
  iq.control = 0;
 
125
  grub_memset (iq.pad, 0, sizeof(iq.pad));
 
126
 
 
127
  err = scsi->dev->read (scsi, sizeof (iq), (char *) &iq,
 
128
                         sizeof (iqd), (char *) &iqd);
 
129
 
 
130
  /* Each SCSI command should be followed by Request Sense.
 
131
     If not so, many devices STALLs or definitely freezes. */
 
132
  err_sense = grub_scsi_request_sense (scsi);
 
133
  if (err_sense != GRUB_ERR_NONE)
 
134
        grub_errno = err;
 
135
  /* err_sense is ignored for now and Request Sense Data also... */
 
136
 
 
137
  if (err)
 
138
    return err;
 
139
 
 
140
  scsi->devtype = iqd.devtype & GRUB_SCSI_DEVTYPE_MASK;
 
141
  scsi->removable = iqd.rmb >> GRUB_SCSI_REMOVABLE_BIT;
 
142
 
 
143
  return GRUB_ERR_NONE;
 
144
}
 
145
 
 
146
/* Read the capacity and block size of SCSI.  */
 
147
static grub_err_t
 
148
grub_scsi_read_capacity (grub_scsi_t scsi)
 
149
{
 
150
  struct grub_scsi_read_capacity rc;
 
151
  struct grub_scsi_read_capacity_data rcd;
 
152
  grub_err_t err;
 
153
  grub_err_t err_sense;
 
154
 
 
155
  rc.opcode = grub_scsi_cmd_read_capacity;
 
156
  rc.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
 
157
  rc.logical_block_addr = 0;
 
158
  rc.reserved1 = 0;
 
159
  rc.reserved2 = 0;
 
160
  rc.PMI = 0;
 
161
  rc.control = 0;
 
162
  rc.pad = 0;
 
163
        
 
164
  err = scsi->dev->read (scsi, sizeof (rc), (char *) &rc,
 
165
                         sizeof (rcd), (char *) &rcd);
 
166
 
 
167
  /* Each SCSI command should be followed by Request Sense.
 
168
     If not so, many devices STALLs or definitely freezes. */
 
169
  err_sense = grub_scsi_request_sense (scsi);
 
170
  if (err_sense != GRUB_ERR_NONE)
 
171
        grub_errno = err;
 
172
/* err_sense is ignored for now and Request Sense Data also... */
 
173
 
 
174
  if (err)
 
175
    return err;
 
176
 
 
177
  scsi->size = grub_be_to_cpu32 (rcd.size);
 
178
  scsi->blocksize = grub_be_to_cpu32 (rcd.blocksize);
 
179
 
 
180
  return GRUB_ERR_NONE;
 
181
}
 
182
 
 
183
/* Send a SCSI request for DISK: read SIZE sectors starting with
 
184
   sector SECTOR to BUF.  */
 
185
static grub_err_t
 
186
grub_scsi_read10 (grub_disk_t disk, grub_disk_addr_t sector,
 
187
                  grub_size_t size, char *buf)
 
188
{
 
189
  grub_scsi_t scsi;
 
190
  struct grub_scsi_read10 rd;
 
191
  grub_err_t err;
 
192
  grub_err_t err_sense;
 
193
 
 
194
  scsi = disk->data;
 
195
 
 
196
  rd.opcode = grub_scsi_cmd_read10;
 
197
  rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
 
198
  rd.lba = grub_cpu_to_be32 (sector);
 
199
  rd.reserved = 0;
 
200
  rd.size = grub_cpu_to_be16 (size);
 
201
  rd.reserved2 = 0;
 
202
  rd.pad = 0;
 
203
 
 
204
  err = scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->blocksize, buf);
 
205
 
 
206
  /* Each SCSI command should be followed by Request Sense.
 
207
     If not so, many devices STALLs or definitely freezes. */
 
208
  err_sense = grub_scsi_request_sense (scsi);
 
209
  if (err_sense != GRUB_ERR_NONE)
 
210
        grub_errno = err;
 
211
  /* err_sense is ignored for now and Request Sense Data also... */
 
212
 
 
213
  return err;
 
214
}
 
215
 
 
216
/* Send a SCSI request for DISK: read SIZE sectors starting with
 
217
   sector SECTOR to BUF.  */
 
218
static grub_err_t
 
219
grub_scsi_read12 (grub_disk_t disk, grub_disk_addr_t sector,
 
220
                  grub_size_t size, char *buf)
 
221
{
 
222
  grub_scsi_t scsi;
 
223
  struct grub_scsi_read12 rd;
 
224
  grub_err_t err;
 
225
  grub_err_t err_sense;
 
226
 
 
227
  scsi = disk->data;
 
228
 
 
229
  rd.opcode = grub_scsi_cmd_read12;
 
230
  rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
 
231
  rd.lba = grub_cpu_to_be32 (sector);
 
232
  rd.size = grub_cpu_to_be32 (size);
 
233
  rd.reserved = 0;
 
234
  rd.control = 0;
 
235
 
 
236
  err = scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->blocksize, buf);
 
237
 
 
238
  /* Each SCSI command should be followed by Request Sense.
 
239
     If not so, many devices STALLs or definitely freezes. */
 
240
  err_sense = grub_scsi_request_sense (scsi);
 
241
  if (err_sense != GRUB_ERR_NONE)
 
242
        grub_errno = err;
 
243
  /* err_sense is ignored for now and Request Sense Data also... */
 
244
 
 
245
  return err;
 
246
}
 
247
 
 
248
#if 0
 
249
/* Send a SCSI request for DISK: write the data stored in BUF to SIZE
 
250
   sectors starting with SECTOR.  */
 
251
static grub_err_t
 
252
grub_scsi_write10 (grub_disk_t disk, grub_disk_addr_t sector,
 
253
                   grub_size_t size, char *buf)
 
254
{
 
255
  grub_scsi_t scsi;
 
256
  struct grub_scsi_write10 wr;
 
257
  grub_err_t err;
 
258
  grub_err_t err_sense;
 
259
 
 
260
  scsi = disk->data;
 
261
 
 
262
  wr.opcode = grub_scsi_cmd_write10;
 
263
  wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
 
264
  wr.lba = grub_cpu_to_be32 (sector);
 
265
  wr.reserved = 0;
 
266
  wr.size = grub_cpu_to_be16 (size);
 
267
  wr.reserved2 = 0;
 
268
  wr.pad = 0;
 
269
 
 
270
  err = scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi->blocksize, buf);
 
271
 
 
272
  /* Each SCSI command should be followed by Request Sense.
 
273
     If not so, many devices STALLs or definitely freezes. */
 
274
  err_sense = grub_scsi_request_sense (scsi);
 
275
  if (err_sense != GRUB_ERR_NONE)
 
276
        grub_errno = err;
 
277
  /* err_sense is ignored for now and Request Sense Data also... */
 
278
 
 
279
  return err;
 
280
}
 
281
 
 
282
/* Send a SCSI request for DISK: write the data stored in BUF to SIZE
 
283
   sectors starting with SECTOR.  */
 
284
static grub_err_t
 
285
grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector,
 
286
                   grub_size_t size, char *buf)
 
287
{
 
288
  grub_scsi_t scsi;
 
289
  struct grub_scsi_write12 wr;
 
290
  grub_err_t err;
 
291
  grub_err_t err_sense;
 
292
 
 
293
  scsi = disk->data;
 
294
 
 
295
  wr.opcode = grub_scsi_cmd_write12;
 
296
  wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
 
297
  wr.lba = grub_cpu_to_be32 (sector);
 
298
  wr.size = grub_cpu_to_be32 (size);
 
299
  wr.reserved = 0;
 
300
  wr.control = 0;
 
301
 
 
302
  err = scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi->blocksize, buf);
 
303
 
 
304
  /* Each SCSI command should be followed by Request Sense.
 
305
     If not so, many devices STALLs or definitely freezes. */
 
306
  err_sense = grub_scsi_request_sense (scsi);
 
307
  if (err_sense != GRUB_ERR_NONE)
 
308
        grub_errno = err;
 
309
  /* err_sense is ignored for now and Request Sense Data also... */
 
310
 
 
311
  return err;
 
312
}
 
313
#endif
 
314
 
 
315
 
 
316
static int
 
317
grub_scsi_iterate (int (*hook) (const char *name))
 
318
{
 
319
  grub_scsi_dev_t p;
 
320
 
 
321
  auto int scsi_iterate (int bus, int luns);
 
322
 
 
323
  int scsi_iterate (int bus, int luns)
 
324
    {
 
325
      int i;
 
326
 
 
327
      /* In case of a single LUN, just return `usbX'.  */
 
328
      if (luns == 1)
 
329
        {
 
330
          char *sname;
 
331
          int ret;
 
332
          sname = grub_xasprintf ("%s%d", p->name, bus);
 
333
          if (!sname)
 
334
            return 1;
 
335
          ret = hook (sname);
 
336
          grub_free (sname);
 
337
          return ret;
 
338
        }
 
339
 
 
340
      /* In case of multiple LUNs, every LUN will get a prefix to
 
341
         distinguish it.  */
 
342
      for (i = 0; i < luns; i++)
 
343
        {
 
344
          char *sname;
 
345
          int ret;
 
346
          sname = grub_xasprintf ("%s%d%c", p->name, bus, 'a' + i);
 
347
          if (!sname)
 
348
            return 1;
 
349
          ret = hook (sname);
 
350
          grub_free (sname);
 
351
          if (ret)
 
352
            return 1;
 
353
        }
 
354
      return 0;
 
355
    }
 
356
 
 
357
  for (p = grub_scsi_dev_list; p; p = p->next)
 
358
    if (p->iterate && (p->iterate) (scsi_iterate))
 
359
      return 1;
 
360
 
 
361
  return 0;
 
362
}
 
363
 
 
364
static grub_err_t
 
365
grub_scsi_open (const char *name, grub_disk_t disk)
 
366
{
 
367
  grub_scsi_dev_t p;
 
368
  grub_scsi_t scsi;
 
369
  grub_err_t err;
 
370
  int lun, bus;
 
371
  grub_uint64_t maxtime;
 
372
  const char *nameend;
 
373
 
 
374
  nameend = name + grub_strlen (name) - 1;
 
375
  /* Try to detect a LUN ('a'-'z'), otherwise just use the first
 
376
     LUN.  */
 
377
  if (nameend >= name && *nameend >= 'a' && *nameend <= 'z')
 
378
    {
 
379
      lun = *nameend - 'a';
 
380
      nameend--;
 
381
    }
 
382
  else
 
383
    lun = 0;
 
384
 
 
385
  while (nameend >= name && grub_isdigit (*nameend))
 
386
    nameend--;
 
387
 
 
388
  if (!nameend[1] || !grub_isdigit (nameend[1]))
 
389
    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk");
 
390
 
 
391
  bus = grub_strtoul (nameend + 1, 0, 0);
 
392
 
 
393
  scsi = grub_malloc (sizeof (*scsi));
 
394
  if (! scsi)
 
395
    return grub_errno;
 
396
 
 
397
  for (p = grub_scsi_dev_list; p; p = p->next)
 
398
    {
 
399
      if (grub_strncmp (p->name, name, nameend - name) != 0)
 
400
        continue;
 
401
 
 
402
      if (p->open (bus, scsi))
 
403
        continue;
 
404
 
 
405
      disk->id = grub_make_scsi_id (p->id, bus, lun);
 
406
      disk->data = scsi;
 
407
      scsi->dev = p;
 
408
      scsi->lun = lun;
 
409
      scsi->bus = bus;
 
410
 
 
411
      grub_dprintf ("scsi", "dev opened\n");
 
412
 
 
413
      err = grub_scsi_inquiry (scsi);
 
414
      if (err)
 
415
        {
 
416
          grub_free (scsi);
 
417
          grub_dprintf ("scsi", "inquiry failed\n");
 
418
          return err;
 
419
        }
 
420
 
 
421
      grub_dprintf ("scsi", "inquiry: devtype=0x%02x removable=%d\n",
 
422
                    scsi->devtype, scsi->removable);
 
423
 
 
424
      /* Try to be conservative about the device types
 
425
         supported.  */
 
426
      if (scsi->devtype != grub_scsi_devtype_direct
 
427
          && scsi->devtype != grub_scsi_devtype_cdrom)
 
428
        {
 
429
          grub_free (scsi);
 
430
          return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
 
431
                             "unknown SCSI device");
 
432
        }
 
433
 
 
434
      /* According to USB MS tests specification, issue Test Unit Ready
 
435
       * until OK */
 
436
      maxtime = grub_get_time_ms () + 5000; /* It is safer value */
 
437
      do
 
438
        {
 
439
          /* Timeout is necessary - for example in case when we have
 
440
           * universal card reader with more LUNs and we have only
 
441
           * one card inserted (or none), so only one LUN (or none)
 
442
           * will be ready - and we want not to hang... */
 
443
          if (grub_get_time_ms () > maxtime)
 
444
            {
 
445
              err = GRUB_ERR_READ_ERROR;
 
446
              grub_free (scsi);
 
447
              grub_dprintf ("scsi", "LUN is not ready - timeout\n");
 
448
              return err;
 
449
            }
 
450
          err = grub_scsi_test_unit_ready (scsi);
 
451
        }
 
452
      while (err == GRUB_ERR_READ_ERROR);
 
453
      /* Reset grub_errno !
 
454
       * It is set to some error code in loop before... */
 
455
      grub_errno = GRUB_ERR_NONE;
 
456
 
 
457
      /* Read capacity of media */
 
458
      err = grub_scsi_read_capacity (scsi);
 
459
      if (err)
 
460
        {
 
461
          grub_free (scsi);
 
462
          grub_dprintf ("scsi", "READ CAPACITY failed\n");
 
463
          return err;
 
464
        }
 
465
 
 
466
      /* SCSI blocks can be something else than 512, although GRUB
 
467
         wants 512 byte blocks.  */
 
468
      disk->total_sectors = ((grub_uint64_t)scsi->size
 
469
                             * (grub_uint64_t)scsi->blocksize)
 
470
                            >> GRUB_DISK_SECTOR_BITS;
 
471
 
 
472
      grub_dprintf ("scsi", "blocks=%u, blocksize=%u\n",
 
473
                    scsi->size, scsi->blocksize);
 
474
      grub_dprintf ("scsi", "Disk total 512 sectors = %llu\n",
 
475
                    (unsigned long long) disk->total_sectors);
 
476
 
 
477
      return GRUB_ERR_NONE;
 
478
    }
 
479
 
 
480
  grub_free (scsi);
 
481
 
 
482
  return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk");
 
483
}
 
484
 
 
485
static void
 
486
grub_scsi_close (grub_disk_t disk)
 
487
{
 
488
  grub_scsi_t scsi;
 
489
 
 
490
  scsi = disk->data;
 
491
  if (scsi->dev->close)
 
492
    scsi->dev->close (scsi);
 
493
  grub_free (scsi);
 
494
}
 
495
 
 
496
static grub_err_t
 
497
grub_scsi_read (grub_disk_t disk, grub_disk_addr_t sector,
 
498
                grub_size_t size, char *buf)
 
499
{
 
500
  grub_scsi_t scsi;
 
501
 
 
502
  scsi = disk->data;
 
503
 
 
504
  /* SCSI sectors are variable in size.  GRUB uses 512 byte
 
505
     sectors.  */
 
506
  if (scsi->blocksize != GRUB_DISK_SECTOR_SIZE)
 
507
    {
 
508
      unsigned spb = scsi->blocksize >> GRUB_DISK_SECTOR_BITS;
 
509
      if (! (spb != 0 && (scsi->blocksize & GRUB_DISK_SECTOR_SIZE) == 0))
 
510
        return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
 
511
                           "unsupported SCSI block size");
 
512
 
 
513
      grub_uint32_t sector_mod = 0;
 
514
      sector = grub_divmod64 (sector, spb, &sector_mod);
 
515
 
 
516
      if (! (sector_mod == 0 && size % spb == 0))
 
517
        return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
 
518
                           "unaligned SCSI read not supported");
 
519
 
 
520
      size /= spb;
 
521
    }
 
522
 
 
523
  /* Depending on the type, select a read function.  */
 
524
  switch (scsi->devtype)
 
525
    {
 
526
    case grub_scsi_devtype_direct:
 
527
      return grub_scsi_read10 (disk, sector, size, buf);
 
528
 
 
529
    case grub_scsi_devtype_cdrom:
 
530
      return grub_scsi_read12 (disk, sector, size, buf);
 
531
    }
 
532
 
 
533
  /* XXX: Never reached.  */
 
534
  return GRUB_ERR_NONE;
 
535
 
 
536
#if 0 /* Workaround - it works - but very slowly, from some reason
 
537
       * unknown to me (specially on OHCI). Do not use it. */
 
538
  /* Split transfer requests to device sector size because */
 
539
  /* some devices are not able to transfer more than 512-1024 bytes */
 
540
  grub_err_t err = GRUB_ERR_NONE;
 
541
 
 
542
  for ( ; size; size--)
 
543
    {
 
544
      /* Depending on the type, select a read function.  */
 
545
      switch (scsi->devtype)
 
546
        {
 
547
          case grub_scsi_devtype_direct:
 
548
            err = grub_scsi_read10 (disk, sector, 1, buf);
 
549
            break;
 
550
 
 
551
          case grub_scsi_devtype_cdrom:
 
552
            err = grub_scsi_read12 (disk, sector, 1, buf);
 
553
            break;
 
554
 
 
555
          default: /* This should not happen */
 
556
            return GRUB_ERR_READ_ERROR;
 
557
        }
 
558
      if (err)
 
559
        return err;
 
560
      sector++;
 
561
      buf += scsi->blocksize;
 
562
    }
 
563
 
 
564
  return err;
 
565
#endif
 
566
}
 
567
 
 
568
static grub_err_t
 
569
grub_scsi_write (grub_disk_t disk __attribute((unused)),
 
570
                 grub_disk_addr_t sector __attribute((unused)),
 
571
                 grub_size_t size __attribute((unused)),
 
572
                 const char *buf __attribute((unused)))
 
573
{
 
574
#if 0
 
575
  /* XXX: Not tested yet!  */
 
576
 
 
577
  /* XXX: This should depend on the device type?  */
 
578
  return grub_scsi_write10 (disk, sector, size, buf);
 
579
#endif
 
580
  return GRUB_ERR_NOT_IMPLEMENTED_YET;
 
581
}
 
582
 
 
583
 
 
584
static struct grub_disk_dev grub_scsi_dev =
 
585
  {
 
586
    .name = "scsi",
 
587
    .id = GRUB_DISK_DEVICE_SCSI_ID,
 
588
    .iterate = grub_scsi_iterate,
 
589
    .open = grub_scsi_open,
 
590
    .close = grub_scsi_close,
 
591
    .read = grub_scsi_read,
 
592
    .write = grub_scsi_write,
 
593
    .next = 0
 
594
  };
 
595
 
 
596
GRUB_MOD_INIT(scsi)
 
597
{
 
598
  grub_disk_dev_register (&grub_scsi_dev);
 
599
}
 
600
 
 
601
GRUB_MOD_FINI(scsi)
 
602
{
 
603
  grub_disk_dev_unregister (&grub_scsi_dev);
 
604
}