grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ATAPI split-off


From: Marco Gerards
Subject: ATAPI split-off
Date: Tue, 12 Aug 2008 23:30:17 +0200
User-agent: Gnus/5.110006 (No Gnus v0.6) Emacs/21.4 (gnu/linux)

Hi,

Here is a patch to remove the ATAPI code and add support for SCSI
commands.  I changed ata.c to use scsi.c.  This results in cleaner,
sharable code.  Meanwhile, the hard coded disk size is removed,
together with some other hacks.

You can make me happy by testing this :-)


--
Marco

2008-08-12  Marco Gerards  <address@hidden>

        * conf/i386-pc.rmk (pkglib_MODULES): Add scsi.mod.
        (scsi_mod_SOURCES): New variable.
        (scsi_mod_CFLAGS): Likewise
        (scsi_mod_LDFLAGS): Likewise.

        * disk/scsi.c: New file.

        * include/grub/scsi.h: Likewise.

        * include/grub/scsicmd.h: Likewise.

        * disk/ata.c: Include <grub/scsi.h>.
        (grub_atapi_packet): Do not use grub_ata_cmd, use registers
        instead.
        (grub_ata_iterate): Skip ATAPI devices.
        (grub_ata_open): Only handle ATAPI devices.
        (struct grub_atapi_read): Removed.
        (grub_atapi_readsector): Likewise.
        (grub_ata_read): No longer handle ATAPI devices.
        (grub_ata_write): Likewise.
        (grub_atapi_iterate): New function.
        (grub_atapi_read): Likewise.
        (grub_atapi_write): Likewise.
        (grub_atapi_open): Likewise.
        (grub_atapi_close): Likewise.
        (grub_atapi_dev): New variable.
        (GRUB_MOD_INIT(ata)): Register ATAPI as SCSI device.
        (GRUB_MOD_FINI(ata)): Unregister ATAPI.

        * include/grub/disk.h (enum grub_disk_dev_id): Add
        `GRUB_DISK_DEVICE_SCSI_ID'.


Index: conf/i386-pc.rmk
===================================================================
--- conf/i386-pc.rmk    (revision 1802)
+++ conf/i386-pc.rmk    (working copy)
@@ -163,7 +163,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod
        vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \
        videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod  \
        ata.mod vga.mod memdisk.mod jpeg.mod png.mod pci.mod lspci.mod \
-       aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod
+       aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod scsi.mod
 
 # For biosdisk.mod.
 biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
@@ -340,4 +340,9 @@ pxecmd_mod_SOURCES = commands/i386/pc/px
 pxecmd_mod_CFLAGS = $(COMMON_CFLAGS)
 pxecmd_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For scsi.mod
+scsi_mod_SOURCES = disk/scsi.c
+scsi_mod_CFLAGS = $(COMMON_CFLAGS)
+scsi_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 include $(srcdir)/conf/common.mk
Index: disk/scsi.c
===================================================================
--- disk/scsi.c (revision 0)
+++ disk/scsi.c (revision 0)
@@ -0,0 +1,377 @@
+/* scsi.c - scsi support.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/disk.h>
+#include <grub/dl.h>
+#include <grub/kernel.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/types.h>
+#include <grub/machine/kernel.h>
+#include <grub/scsi.h>
+#include <grub/scsicmd.h>
+
+
+static grub_scsi_dev_t grub_scsi_dev_list;
+
+void
+grub_scsi_dev_register (grub_scsi_dev_t dev)
+{
+  dev->next = grub_scsi_dev_list;
+  grub_scsi_dev_list = dev;
+}
+
+void
+grub_scsi_dev_unregister (grub_scsi_dev_t dev)
+{
+  grub_scsi_dev_t *p, q;
+  
+  for (p = &grub_scsi_dev_list, q = *p; q; p = &(q->next), q = q->next)
+    if (q == dev)
+      {
+        *p = q->next;
+       break;
+      }
+}
+
+
+/* Determine the the device is removable and the type of the device
+   SCSI.  */ 
+static grub_err_t
+grub_scsi_inquiry (grub_scsi_t scsi)
+{
+  struct grub_scsi_inquiry iq;
+  struct grub_scsi_inquiry_data iqd;
+  grub_err_t err;
+
+  iq.opcode = grub_scsi_cmd_inquiry;
+  iq.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+  iq.reserved = 0;
+  iq.alloc_length = 0x24; /* XXX: Hardcoded for now */
+  iq.reserved2 = 0;
+
+  err = scsi->dev->read (scsi, sizeof (iq), (char *) &iq,
+                        sizeof (iqd), (char *) &iqd);
+  if (err)
+    return err;
+
+  scsi->devtype = iqd.devtype & GRUB_SCSI_DEVTYPE_MASK;
+  scsi->removable = iqd.rmb >> GRUB_SCSI_REMOVABLE_BIT;
+
+  return GRUB_ERR_NONE;
+}
+
+/* Read the capacity and block size of SCSI.  */
+static grub_err_t
+grub_scsi_read_capacity (grub_scsi_t scsi)
+{
+  struct grub_scsi_read_capacity rc;
+  struct grub_scsi_read_capacity_data rcd;
+  grub_err_t err;
+
+  rc.opcode = grub_scsi_cmd_read_capacity;
+  rc.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+  grub_memset (rc.reserved, 0, sizeof (rc.reserved));
+
+  err = scsi->dev->read (scsi, sizeof (rc), (char *) &rc,
+                        sizeof (rcd), (char *) &rcd);
+  if (err)
+    return err;
+
+  scsi->size = grub_be_to_cpu32 (rcd.size);
+  scsi->blocksize = grub_be_to_cpu32 (rcd.blocksize);
+
+  return GRUB_ERR_NONE;
+}
+
+/* Send a SCSI request for DISK: read SIZE sectors starting with
+   sector SECTOR to BUF.  */
+static grub_err_t
+grub_scsi_read10 (grub_disk_t disk, grub_disk_addr_t sector,
+                 grub_size_t size, char *buf)
+{
+  grub_scsi_t scsi;
+  struct grub_scsi_read10 rd;
+
+  scsi = disk->data;
+
+  rd.opcode = grub_scsi_cmd_read10;
+  rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+  rd.lba = grub_cpu_to_be32 (sector);
+  rd.reserved = 0;
+  rd.size = grub_cpu_to_be16 (size);
+  rd.reserved2 = 0;
+  rd.pad = 0;
+
+  return scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * 512, buf);
+}
+
+/* Send a SCSI request for DISK: read SIZE sectors starting with
+   sector SECTOR to BUF.  */
+static grub_err_t
+grub_scsi_read12 (grub_disk_t disk, grub_disk_addr_t sector,
+                 grub_size_t size, char *buf)
+{
+  grub_scsi_t scsi;
+  struct grub_scsi_read12 rd;
+
+  scsi = disk->data;
+
+  rd.opcode = grub_scsi_cmd_read12;
+  rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+  rd.lba = grub_cpu_to_be32 (sector);
+  rd.size = grub_cpu_to_be32 (size);
+  rd.reserved = 0;
+  rd.control = 0;
+
+  return scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * 512, buf);
+}
+
+/* Send a SCSI request for DISK: write the data stored in BUF to SIZE
+   sectors starting with SECTOR.  */
+static grub_err_t
+grub_scsi_write10 (grub_disk_t disk, grub_disk_addr_t sector,
+                  grub_size_t size, char *buf)
+{
+  grub_scsi_t scsi;
+  struct grub_scsi_write10 wr;
+
+  scsi = disk->data;
+
+  wr.opcode = grub_scsi_cmd_write10;
+  wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+  wr.lba = grub_cpu_to_be32 (sector);
+  wr.reserved = 0;
+  wr.size = grub_cpu_to_be16 (size);
+  wr.reserved2 = 0;
+  wr.pad = 0;
+
+  return scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * 512, buf);
+}
+
+/* Send a SCSI request for DISK: write the data stored in BUF to SIZE
+   sectors starting with SECTOR.  */
+static grub_err_t
+grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector,
+                  grub_size_t size, char *buf)
+{
+  grub_scsi_t scsi;
+  struct grub_scsi_write10 wr;
+
+  scsi = disk->data;
+
+  wr.opcode = grub_scsi_cmd_write12;
+  wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+  wr.lba = grub_cpu_to_be32 (sector);
+  wr.size = grub_cpu_to_be32 (size);
+  wr.reserved = 0;
+  wr.pad = 0;
+
+  return scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * 512, buf);
+}
+
+
+static int
+grub_scsi_iterate (int (*hook) (const char *name))
+{
+  grub_scsi_dev_t p;
+
+  auto int scsi_iterate (const char *name, int luns);
+
+  int scsi_iterate (const char *name, int luns)
+    {
+      char sname[40];
+      int i;
+
+      /* In case of a single LUN, just return `usbX'.  */
+      if (luns == 1)
+       return hook (name);
+
+      /* In case of multiple LUNs, every LUN will get a prefix to
+        distinguish it.  */
+      for (i = 0; i < luns; i++)
+       {
+         grub_sprintf (sname, "%s%c", name, 'a' + i);
+         if (hook (sname))
+           return 1;
+       }
+      return 0;
+    }
+
+  for (p = grub_scsi_dev_list; p; p = p->next)
+    if (p->iterate && (p->iterate) (scsi_iterate))
+      return 1;
+
+  return 0;
+}
+
+static grub_err_t
+grub_scsi_open (const char *name, grub_disk_t disk)
+{
+  grub_scsi_dev_t p;
+  grub_scsi_t scsi;
+  grub_err_t err;
+  int len;
+  int lun;
+  
+  scsi = grub_malloc (sizeof (*scsi));
+  if (! scsi)
+    return grub_errno;
+
+  len = grub_strlen (name);
+  lun = name[len - 1] - 'a';
+
+  /* Try to detect a LUN ('a'-'z'), otherwise just use the first
+     LUN.  */
+  if (lun < 0 || lun > 26)
+    lun = 0;
+
+  for (p = grub_scsi_dev_list; p; p = p->next)
+    {
+      if (! p->open (name, scsi))
+       {
+         disk->id = (unsigned long) "scsi"; /* XXX */
+         disk->has_partitions = 0;
+         disk->data = scsi;
+         scsi->dev = p;
+         scsi->lun = lun;
+         scsi->name = grub_strdup (name);
+         if (! scsi->name)
+           {
+             p->close (scsi);
+             return grub_errno;
+           }
+
+         grub_dprintf ("scsi", "dev opened\n");
+
+         err = grub_scsi_inquiry (scsi);
+         if (err)
+           {
+             grub_dprintf ("scsi", "inquiry failed\n");
+             p->close (scsi);
+             return grub_errno;
+           }
+
+         grub_dprintf ("scsi", "inquiry: devtype=0x%02x removable=%d\n",
+                       scsi->devtype, scsi->removable);
+         
+         /* Try to be conservative about the device types
+            supported.  */
+         if (scsi->devtype != grub_scsi_devtype_direct
+             && scsi->devtype != grub_scsi_devtype_cdrom)
+           {
+             p->close (scsi);
+             return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+                                "unknown SCSI device");
+           }
+
+         err = grub_scsi_read_capacity (scsi);
+         if (err)
+           {
+             grub_dprintf ("scsi", "READ CAPACITY failed\n");
+             p->close (scsi);
+             return grub_errno;
+           }
+
+         /* SCSI blocks can be something else than 512, although GRUB
+            wants 512 byte blocks.  */
+         disk->total_sectors = ((scsi->size * scsi->blocksize)
+                                << GRUB_DISK_SECTOR_BITS);
+
+         grub_dprintf ("scsi", "capacity=%d, blksize=%d\n",
+                       (int) disk->total_sectors, scsi->blocksize);
+
+         return GRUB_ERR_NONE;
+       }
+    }
+
+  return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk");
+}
+
+static void
+grub_scsi_close (grub_disk_t disk)
+{
+  grub_scsi_t scsi;
+
+  scsi = disk->data;
+  return scsi->dev->close (scsi);
+}
+
+static grub_err_t
+grub_scsi_read (grub_disk_t disk, grub_disk_addr_t sector,
+               grub_size_t size, char *buf)
+{
+  grub_scsi_t scsi;
+
+  scsi = disk->data;
+
+  /* SCSI sectors are variable in size.  GRUB uses 512 byte
+     sectors.  */
+  sector = grub_divmod64 (sector, scsi->blocksize >> GRUB_DISK_SECTOR_BITS,
+                         NULL);
+
+  /* Depending on the type, select a read function.  */
+  switch (scsi->devtype)
+    {
+    case grub_scsi_devtype_direct:
+      return grub_scsi_read10 (disk, sector, size, buf);
+
+    case grub_scsi_devtype_cdrom:
+      return grub_scsi_read12 (disk, sector, size, buf);
+    }
+
+  /* XXX: Never reached.  */
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_scsi_write (grub_disk_t disk __attribute((unused)), grub_disk_addr_t 
sector,
+                grub_size_t size, const char *buf)
+{
+#if 0
+  /* XXX: Not tested yet!  */
+
+  /* XXX: This should depend on the device type?  */
+  return grub_scsi_write10 (disk, sector, size, buf);
+#endif
+  return GRUB_ERR_NOT_IMPLEMENTED_YET;
+}
+
+
+static struct grub_disk_dev grub_scsi_dev =
+  {
+    .name = "scsi",
+    .id = GRUB_DISK_DEVICE_SCSI_ID,
+    .iterate = grub_scsi_iterate,
+    .open = grub_scsi_open,
+    .close = grub_scsi_close,
+    .read = grub_scsi_read,
+    .write = grub_scsi_write,
+    .next = 0
+  };
+
+GRUB_MOD_INIT(scsi)
+{
+  grub_disk_dev_register (&grub_scsi_dev);
+}
+
+GRUB_MOD_FINI(scsi)
+{
+  grub_disk_dev_unregister (&grub_scsi_dev);
+}
Index: disk/ata.c
===================================================================
--- disk/ata.c  (revision 1802)
+++ disk/ata.c  (working copy)
@@ -23,6 +23,7 @@
 #include <grub/mm.h>
 #include <grub/time.h>
 #include <grub/pci.h>
+#include <grub/scsi.h>
 /* XXX: For now this only works on i386.  */
 #include <grub/cpu/io.h>
 
@@ -299,14 +300,17 @@ grub_atapi_identify (struct grub_ata_dev
 static grub_err_t
 grub_atapi_packet (struct grub_ata_device *dev, char *packet)
 {
+  grub_err_t err;
+
   grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
   grub_ata_regset (dev, GRUB_ATA_REG_FEATURES, 0);
   grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0);
   grub_ata_regset (dev, GRUB_ATA_REG_LBAHIGH, 0xFF);
   grub_ata_regset (dev, GRUB_ATA_REG_LBAMID, 0xFF);
 
-  if (grub_ata_cmd (dev, GRUB_ATA_CMD_PACKET))
-    return grub_errno;
+  grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_PACKET);
+
+  grub_ata_wait ();
 
   if (grub_ata_pio_write (dev, packet, 12))
     return grub_errno;
@@ -757,6 +761,9 @@ grub_ata_iterate (int (*hook) (const cha
       char devname[5];
       grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
 
+      if (dev->atapi)
+       continue;
+
       if (hook (devname))
        return 1;
     }
@@ -781,13 +788,13 @@ grub_ata_open (const char *name, grub_di
     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device");
 
   if (dev->atapi)
-    disk->total_sectors = 9000000; /* XXX */
-  else
-    disk->total_sectors = dev->size;
+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk");
+
+  disk->total_sectors = dev->size;
 
   disk->id = (unsigned long) dev;
   
-  disk->has_partitions = !dev->atapi;
+  disk->has_partitions = 1;
   disk->data = dev;
 
   return 0;
@@ -799,33 +806,6 @@ grub_ata_close (grub_disk_t disk __attri
   
 }
 
-struct grub_atapi_read
-{
-  grub_uint8_t code;
-  grub_uint8_t reserved1;
-  grub_uint32_t lba;
-  grub_uint32_t length;
-  grub_uint8_t reserved2[2];
-} __attribute__((packed));
-
-static grub_err_t
-grub_atapi_readsector (struct grub_ata_device *dev,
-                      char *buf, grub_disk_addr_t sector)
-{
-  struct grub_atapi_read readcmd;
-
-  readcmd.code = 0xA8;
-  readcmd.lba = grub_cpu_to_be32 (sector);
-  readcmd.length = grub_cpu_to_be32 (1);
-
-  grub_atapi_packet (dev, (char *) &readcmd);
-  grub_ata_wait ();
-  if (grub_ata_pio_read (dev, buf, GRUB_CDROM_SECTOR_SIZE))
-    return grub_errno;
-
-  return 0;
-}
-
 static grub_err_t
 grub_ata_read (grub_disk_t disk, grub_disk_addr_t sector,
               grub_size_t size, char *buf)
@@ -834,41 +814,7 @@ grub_ata_read (grub_disk_t disk, grub_di
   int cdsector;
   char *sbuf;
 
-  if (! dev->atapi)
-    return grub_ata_readwrite (disk, sector, size, buf, 0);
-
-  /* ATAPI is being used, so try to read from CDROM using ATAPI.  */
-
-  sbuf = grub_malloc (GRUB_CDROM_SECTOR_SIZE);
-  if (! sbuf)
-    return grub_errno;
-
-  /* CDROMs have sectors of 2048 bytes, so chop them into pieces of
-     512 bytes.  */
-  while (size > 0)
-    {
-      int rsize;
-      int offset;
-      int max;
-
-      cdsector = sector >> 2;
-      rsize = ((size * GRUB_DISK_SECTOR_SIZE > GRUB_CDROM_SECTOR_SIZE)
-              ? GRUB_CDROM_SECTOR_SIZE : size * GRUB_DISK_SECTOR_SIZE);
-      offset = (sector & 3) * GRUB_DISK_SECTOR_SIZE;
-      max = GRUB_CDROM_SECTOR_SIZE - offset;
-      rsize = (rsize > max) ? max : rsize;
-
-      grub_atapi_readsector (dev, sbuf, cdsector);
-      grub_memcpy (buf + offset, sbuf, rsize);
-
-      buf += rsize;
-      size -= rsize / GRUB_DISK_SECTOR_SIZE;
-      sector += rsize / GRUB_DISK_SECTOR_SIZE;
-    }
-
-  grub_free (sbuf);
-
-  return 0;
+  return grub_ata_readwrite (disk, sector, size, buf, 0);
 }
 
 static grub_err_t
@@ -879,10 +825,7 @@ grub_ata_write (grub_disk_t disk,
 {
   struct grub_ata_device *dev = (struct grub_ata_device *) disk->data;
 
-  if (! dev->atapi)
-    return grub_ata_readwrite (disk, sector, size, (char *) buf, 1);
-
-  return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "ATAPI write not 
supported");
+  return grub_ata_readwrite (disk, sector, size, (char *) buf, 1);
 }
 
 static struct grub_disk_dev grub_atadisk_dev =
@@ -897,6 +840,105 @@ static struct grub_disk_dev grub_atadisk
     .next = 0
   };
 
+
+
+/* ATAPI code.  */
+
+static int
+grub_atapi_iterate (int (*hook) (const char *name, int luns))
+{
+  struct grub_ata_device *dev;
+
+  for (dev = grub_ata_devices; dev; dev = dev->next)
+    {
+      char devname[7];
+      grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
+
+      if (! dev->atapi)
+       continue;
+
+      if (hook (devname, 1))
+       return 1;
+    }
+
+  return 0;
+
+}
+
+static grub_err_t
+grub_atapi_read (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+                grub_size_t size, char *buf)
+{
+  struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data;
+
+  if (grub_atapi_packet (dev, cmd))
+    return grub_errno;
+
+  grub_ata_wait (); /* XXX */
+
+  return grub_ata_pio_read (dev, buf, size);
+}
+
+static grub_err_t
+grub_atapi_write (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+                 grub_size_t size, char *buf)
+{
+  struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data;
+
+  if (grub_atapi_packet (dev, cmd))
+    return grub_errno;
+
+  grub_ata_wait (); /* XXX */
+
+  return grub_ata_pio_write (dev, buf, size);
+}
+
+static grub_err_t
+grub_atapi_open (const char *name, struct grub_scsi *scsi)
+{
+  struct grub_ata_device *dev;
+  struct grub_ata_device *devfnd;
+
+  for (dev = grub_ata_devices; dev; dev = dev->next)
+    {
+      char devname[7];
+      grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
+
+      if (!grub_strcmp (devname, name))
+       {
+         devfnd = dev;
+         break;
+       }
+    }
+
+  grub_dprintf ("ata", "opening ATAPI dev `%s'\n", name);
+
+  if (! devfnd)
+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such ATAPI device");
+
+  scsi->data = devfnd;
+  scsi->name = grub_strdup (name);
+  scsi->luns = 1;
+
+  return GRUB_ERR_NONE;
+}
+
+static void
+grub_atapi_close (struct grub_scsi *scsi)
+{
+  grub_free (scsi->name);
+}
+
+static struct grub_scsi_dev grub_atapi_dev =
+  {
+    .name = "ATAPI",
+    .iterate = grub_atapi_iterate,
+    .open = grub_atapi_open,
+    .close = grub_atapi_close,
+    .read = grub_atapi_read,
+    .write = grub_atapi_write
+  }; 
+
 
 
 GRUB_MOD_INIT(ata)
@@ -915,9 +957,13 @@ GRUB_MOD_INIT(ata)
   grub_ata_initialize ();
 
   grub_disk_dev_register (&grub_atadisk_dev);
+
+  /* ATAPI devices are handled by scsi.mod.  */
+  grub_scsi_dev_register (&grub_atapi_dev);
 }
 
 GRUB_MOD_FINI(ata)
 {
+  grub_scsi_dev_unregister (&grub_atapi_dev);
   grub_disk_dev_unregister (&grub_atadisk_dev);
 }
Index: include/grub/scsi.h
===================================================================
--- include/grub/scsi.h (revision 0)
+++ include/grub/scsi.h (revision 0)
@@ -0,0 +1,88 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef        GRUB_SCSI_H
+#define        GRUB_SCSI_H     1
+
+typedef struct grub_scsi_dev *grub_scsi_dev_t;
+
+void grub_scsi_dev_register (grub_scsi_dev_t dev);
+void grub_scsi_dev_unregister (grub_scsi_dev_t dev);
+
+struct grub_scsi;
+
+struct grub_scsi_dev
+{
+  /* The device name.  */
+  const char *name;
+
+  /* Call HOOK with each device name, until HOOK returns non-zero.  */
+  int (*iterate) (int (*hook) (const char *name, int luns));
+
+  /* Open the device named NAME, and set up SCSI.  */
+  grub_err_t (*open) (const char *name, struct grub_scsi *scsi);
+
+  /* Close the scsi device SCSI.  */
+  void (*close) (struct grub_scsi *scsi);
+
+  /* Read SIZE bytes from the device SCSI into BUF after sending the
+     command CMD of size CMDSIZE.  */
+  grub_err_t (*read) (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+                     grub_size_t size, char *buf);
+
+  /* Write SIZE  bytes from BUF to  the device SCSI  after sending the
+     command CMD of size CMDSIZE.  */
+  grub_err_t (*write) (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+                      grub_size_t size, char *buf);
+
+  /* The next scsi device.  */
+  struct grub_scsi_dev *next;
+};
+
+struct grub_scsi
+{
+  /* The scsi device name.  */
+  char *name;
+
+  /* The underlying scsi device.  */
+  grub_scsi_dev_t dev;
+
+  /* Type of SCSI device.  XXX: Make enum.  */
+  grub_uint8_t devtype;
+
+  /* Number of LUNs.  */
+  int luns;
+
+  /* LUN for this `struct grub_scsi'.  */
+  int lun;
+
+  /* Set to 0 when not removable, 1 when removable.  */
+  int removable;
+
+  /* Size of the device in blocks.  */
+  int size;
+
+  /* Size of one block.  */
+  int blocksize;
+
+  /* Device-specific data.  */
+  void *data;
+};
+typedef struct grub_scsi *grub_scsi_t;
+
+#endif /* GRUB_SCSI_H */
Index: include/grub/scsicmd.h
===================================================================
--- include/grub/scsicmd.h      (revision 0)
+++ include/grub/scsicmd.h      (revision 0)
@@ -0,0 +1,122 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef        GRUB_SCSICMD_H
+#define        GRUB_SCSICMD_H  1
+
+#include <grub/types.h>
+
+#define GRUB_SCSI_DEVTYPE_MASK 31
+#define GRUB_SCSI_REMOVABLE_BIT        7
+#define GRUB_SCSI_LUN_SHIFT    5
+
+struct grub_scsi_inquiry
+{
+  grub_uint8_t opcode;
+  grub_uint8_t lun;
+  grub_uint16_t reserved;
+  grub_uint16_t alloc_length;
+  grub_uint8_t reserved2;
+  grub_uint8_t pad[5];
+} __attribute__((packed));
+
+struct grub_scsi_inquiry_data
+{
+  grub_uint8_t devtype;
+  grub_uint8_t rmb;
+  grub_uint16_t reserved;
+  grub_uint8_t length;
+  grub_uint8_t reserved2[3];
+  char vendor[8];
+  char prodid[16];
+  char prodrev[4];
+} __attribute__((packed));
+
+struct grub_scsi_read_capacity
+{
+  grub_uint8_t opcode;
+  grub_uint8_t lun;
+  grub_uint8_t reserved[8];
+  grub_uint8_t pad[2];
+} __attribute__((packed));
+
+struct grub_scsi_read_capacity_data
+{
+  grub_uint32_t size;
+  grub_uint32_t blocksize;
+} __attribute__((packed));
+
+struct grub_scsi_read10
+{
+  grub_uint8_t opcode;
+  grub_uint8_t lun;
+  grub_uint32_t lba;
+  grub_uint8_t reserved;
+  grub_uint16_t size;
+  grub_uint8_t reserved2;
+  grub_uint16_t pad;
+} __attribute__((packed));
+
+struct grub_scsi_read12
+{
+  grub_uint8_t opcode;
+  grub_uint8_t lun;
+  grub_uint32_t lba;
+  grub_uint32_t size;
+  grub_uint8_t reserved;
+  grub_uint8_t control;
+} __attribute__((packed));
+
+struct grub_scsi_write10
+{
+  grub_uint8_t opcode;
+  grub_uint8_t lun;
+  grub_uint32_t lba;
+  grub_uint8_t reserved;
+  grub_uint16_t size;
+  grub_uint8_t reserved2;
+  grub_uint16_t pad;
+} __attribute__((packed));
+
+struct grub_scsi_write12
+{
+  grub_uint8_t opcode;
+  grub_uint8_t lun;
+  grub_uint32_t lba;
+  grub_uint32_t size;
+  grub_uint8_t reserved;
+  grub_uint8_t control;
+} __attribute__((packed));
+
+typedef enum
+  {
+    grub_scsi_cmd_inquiry = 0x12,
+    grub_scsi_cmd_read_capacity = 0x25,
+    grub_scsi_cmd_read10 = 0x28,
+    grub_scsi_cmd_write10 = 0x2a,
+    grub_scsi_cmd_read12 = 0xa8,
+    grub_scsi_cmd_write12 = 0xaa
+  } grub_scsi_cmd_t;
+
+typedef enum
+  {
+    grub_scsi_devtype_direct = 0x00,
+    grub_scsi_devtype_cdrom = 0x05
+  } grub_scsi_devtype_t;
+
+#endif /* GRUB_SCSICMD_H */
Index: include/grub/disk.h
===================================================================
--- include/grub/disk.h (revision 1802)
+++ include/grub/disk.h (working copy)
@@ -40,6 +40,7 @@ enum grub_disk_dev_id
     GRUB_DISK_DEVICE_NAND_ID,
     GRUB_DISK_DEVICE_UUID_ID,
     GRUB_DISK_DEVICE_PXE_ID,
+    GRUB_DISK_DEVICE_SCSI_ID,
   };
 
 struct grub_disk;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]