Automatically select between the "10" and "16" variants of command set,
authorMichael Brown <mcb30@etherboot.org>
Tue, 12 Dec 2006 18:54:35 +0000 (18:54 +0000)
committerMichael Brown <mcb30@etherboot.org>
Tue, 12 Dec 2006 18:54:35 +0000 (18:54 +0000)
based on the device size.

src/drivers/block/scsi.c
src/include/gpxe/scsi.h

index 0578403..9651583 100644 (file)
@@ -70,7 +70,7 @@ static int scsi_command ( struct scsi_device *scsi,
 }
 
 /**
- * Read block from SCSI device
+ * Read block from SCSI device using READ (10)
  *
  * @v blockdev         Block device
  * @v block            LBA block number
@@ -78,8 +78,33 @@ static int scsi_command ( struct scsi_device *scsi,
  * @v buffer           Data buffer
  * @ret rc             Return status code
  */
-static int scsi_read ( struct block_device *blockdev, uint64_t block,
-                      unsigned long count, userptr_t buffer ) {
+static int scsi_read_10 ( struct block_device *blockdev, uint64_t block,
+                         unsigned long count, userptr_t buffer ) {
+       struct scsi_device *scsi = block_to_scsi ( blockdev );
+       struct scsi_command command;
+       struct scsi_cdb_read_10 *cdb = &command.cdb.read10;
+
+       /* Issue READ (10) */
+       memset ( &command, 0, sizeof ( command ) );
+       cdb->opcode = SCSI_OPCODE_READ_10;
+       cdb->lba = cpu_to_be32 ( block );
+       cdb->len = cpu_to_be16 ( count );
+       command.data_in = buffer;
+       command.data_in_len = ( count * blockdev->blksize );
+       return scsi_command ( scsi, &command );
+}
+
+/**
+ * Read block from SCSI device using READ (16)
+ *
+ * @v blockdev         Block device
+ * @v block            LBA block number
+ * @v count            Block count
+ * @v buffer           Data buffer
+ * @ret rc             Return status code
+ */
+static int scsi_read_16 ( struct block_device *blockdev, uint64_t block,
+                         unsigned long count, userptr_t buffer ) {
        struct scsi_device *scsi = block_to_scsi ( blockdev );
        struct scsi_command command;
        struct scsi_cdb_read_16 *cdb = &command.cdb.read16;
@@ -95,7 +120,7 @@ static int scsi_read ( struct block_device *blockdev, uint64_t block,
 }
 
 /**
- * Write block to SCSI device
+ * Write block to SCSI device using WRITE (10)
  *
  * @v blockdev         Block device
  * @v block            LBA block number
@@ -103,8 +128,33 @@ static int scsi_read ( struct block_device *blockdev, uint64_t block,
  * @v buffer           Data buffer
  * @ret rc             Return status code
  */
-static int scsi_write ( struct block_device *blockdev, uint64_t block,
-                       unsigned long count, userptr_t buffer ) {
+static int scsi_write_10 ( struct block_device *blockdev, uint64_t block,
+                          unsigned long count, userptr_t buffer ) {
+       struct scsi_device *scsi = block_to_scsi ( blockdev );
+       struct scsi_command command;
+       struct scsi_cdb_write_10 *cdb = &command.cdb.write10;
+
+       /* Issue WRITE (10) */
+       memset ( &command, 0, sizeof ( command ) );
+       cdb->opcode = SCSI_OPCODE_WRITE_10;
+       cdb->lba = cpu_to_be32 ( block );
+       cdb->len = cpu_to_be16 ( count );
+       command.data_out = buffer;
+       command.data_out_len = ( count * blockdev->blksize );
+       return scsi_command ( scsi, &command );
+}
+
+/**
+ * Write block to SCSI device using WRITE (16)
+ *
+ * @v blockdev         Block device
+ * @v block            LBA block number
+ * @v count            Block count
+ * @v buffer           Data buffer
+ * @ret rc             Return status code
+ */
+static int scsi_write_16 ( struct block_device *blockdev, uint64_t block,
+                          unsigned long count, userptr_t buffer ) {
        struct scsi_device *scsi = block_to_scsi ( blockdev );
        struct scsi_command command;
        struct scsi_cdb_write_16 *cdb = &command.cdb.write16;
@@ -179,12 +229,17 @@ static int scsi_read_capacity_16 ( struct block_device *blockdev ) {
 }
 
 /**
- * Read capacity of SCSI device
+ * Initialise SCSI device
  *
- * @v blockdev         Block device
+ * @v scsi             SCSI device
  * @ret rc             Return status code
+ *
+ * Initialises a SCSI device.  The scsi_device::command and
+ * scsi_device::lun fields must already be filled in.  This function
+ * will configure scsi_device::blockdev, including issuing a READ
+ * CAPACITY call to determine the block size and total device size.
  */
-static int scsi_read_capacity ( struct block_device *blockdev ) {
+int init_scsidev ( struct scsi_device *scsi ) {
        int rc;
 
        /* Issue a theoretically extraneous READ CAPACITY (10)
@@ -192,10 +247,12 @@ static int scsi_read_capacity ( struct block_device *blockdev ) {
         * (power-on occurred)" that some dumb targets insist on
         * sending as an error at start of day.
         */
-       scsi_read_capacity_10 ( blockdev );
+       scsi_read_capacity_10 ( &scsi->blockdev );
 
        /* Try READ CAPACITY (10), which is a mandatory command, first. */
-       if ( ( rc = scsi_read_capacity_10 ( blockdev ) ) != 0 )
+       scsi->blockdev.read = scsi_read_10;
+       scsi->blockdev.write = scsi_write_10;
+       if ( ( rc = scsi_read_capacity_10 ( &scsi->blockdev ) ) != 0 )
                return rc;
 
        /* If capacity range was exceeded (i.e. capacity.lba was
@@ -203,28 +260,12 @@ static int scsi_read_capacity ( struct block_device *blockdev ) {
         * READ CAPACITY (16) instead.  READ CAPACITY (16) is not
         * mandatory, so we can't just use it straight off.
         */
-       if ( blockdev->blocks == 0 ) {
-               if ( ( rc = scsi_read_capacity_16 ( blockdev ) ) != 0 )
+       if ( scsi->blockdev.blocks == 0 ) {
+               scsi->blockdev.read = scsi_read_16;
+               scsi->blockdev.write = scsi_write_16;
+               if ( ( rc = scsi_read_capacity_16 ( &scsi->blockdev ) ) != 0 )
                        return rc;
        }
 
        return 0;
 }
-
-/**
- * Initialise SCSI device
- *
- * @v scsi             SCSI device
- * @ret rc             Return status code
- *
- * Initialises a SCSI device.  The scsi_device::command and
- * scsi_device::lun fields must already be filled in.  This function
- * will configure scsi_device::blockdev, including issuing a READ
- * CAPACITY call to determine the block size and total device size.
- */
-int init_scsidev ( struct scsi_device *scsi ) {
-       /** Fill in read and write methods, and get device capacity */
-       scsi->blockdev.read = scsi_read;
-       scsi->blockdev.write = scsi_write;
-       return scsi_read_capacity ( &scsi->blockdev );
-}
index 4cc2b86..9d5952d 100644 (file)
@@ -16,7 +16,9 @@
  * @{
  */
 
+#define SCSI_OPCODE_READ_10            0x28    /**< READ (10) */
 #define SCSI_OPCODE_READ_16            0x88    /**< READ (16) */
+#define SCSI_OPCODE_WRITE_10           0x2a    /**< WRITE (10) */
 #define SCSI_OPCODE_WRITE_16           0x8a    /**< WRITE (16) */
 #define SCSI_OPCODE_READ_CAPACITY_10   0x25    /**< READ CAPACITY (10) */
 #define SCSI_OPCODE_SERVICE_ACTION_IN  0x9e    /**< SERVICE ACTION IN */
  * @{
  */
 
+/** A SCSI "READ (10)" CDB */
+struct scsi_cdb_read_10 {
+       /** Opcode (0x28) */
+       uint8_t opcode;
+       /** Flags */
+       uint8_t flags;
+       /** Start address
+        *
+        * This is a logical block number, in big-endian order.
+        */
+       uint32_t lba;
+       /** Group number */
+       uint8_t group;
+       /** Transfer length
+        *
+        * This is a logical block count, in big-endian order.
+        */
+       uint16_t len;
+       /** Control byte */
+       uint8_t control;
+} __attribute__ (( packed ));
+
 /** A SCSI "READ (16)" CDB */
 struct scsi_cdb_read_16 {
        /** Opcode (0x88) */
@@ -62,6 +86,28 @@ struct scsi_cdb_read_16 {
        uint8_t control;
 } __attribute__ (( packed ));
 
+/** A SCSI "WRITE (10)" CDB */
+struct scsi_cdb_write_10 {
+       /** Opcode (0x2a) */
+       uint8_t opcode;
+       /** Flags */
+       uint8_t flags;
+       /** Start address
+        *
+        * This is a logical block number, in big-endian order.
+        */
+       uint32_t lba;
+       /** Group number */
+       uint8_t group;
+       /** Transfer length
+        *
+        * This is a logical block count, in big-endian order.
+        */
+       uint16_t len;
+       /** Control byte */
+       uint8_t control;
+} __attribute__ (( packed ));
+
 /** A SCSI "WRITE (16)" CDB */
 struct scsi_cdb_write_16 {
        /** Opcode (0x8a) */
@@ -143,7 +189,9 @@ struct scsi_capacity_16 {
 
 /** A SCSI Command Data Block */
 union scsi_cdb {
+       struct scsi_cdb_read_10 read10;
        struct scsi_cdb_read_16 read16;
+       struct scsi_cdb_write_10 write10;
        struct scsi_cdb_write_16 write16;
        struct scsi_cdb_read_capacity_10 readcap10;
        struct scsi_cdb_read_capacity_16 readcap16;