aboutsummaryrefslogtreecommitdiffstats
path: root/gpxe/src/drivers/block/scsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/drivers/block/scsi.c')
-rw-r--r--gpxe/src/drivers/block/scsi.c93
1 files changed, 83 insertions, 10 deletions
diff --git a/gpxe/src/drivers/block/scsi.c b/gpxe/src/drivers/block/scsi.c
index b22bd20f..a51b3af6 100644
--- a/gpxe/src/drivers/block/scsi.c
+++ b/gpxe/src/drivers/block/scsi.c
@@ -16,11 +16,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+FILE_LICENCE ( GPL2_OR_LATER );
+
#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
#include <byteswap.h>
#include <errno.h>
#include <gpxe/blockdev.h>
+#include <gpxe/process.h>
#include <gpxe/scsi.h>
/** @file
@@ -42,6 +46,18 @@ block_to_scsi ( struct block_device *blockdev ) {
}
/**
+ * Handle SCSI command with no backing device
+ *
+ * @v scsi SCSI device
+ * @v command SCSI command
+ * @ret rc Return status code
+ */
+int scsi_detached_command ( struct scsi_device *scsi __unused,
+ struct scsi_command *command __unused ) {
+ return -ENODEV;
+}
+
+/**
* Issue SCSI command
*
* @v scsi SCSI device
@@ -52,24 +68,38 @@ static int scsi_command ( struct scsi_device *scsi,
struct scsi_command *command ) {
int rc;
+ DBGC2 ( scsi, "SCSI %p " SCSI_CDB_FORMAT "\n",
+ scsi, SCSI_CDB_DATA ( command->cdb ) );
+
/* Clear sense response code before issuing command */
command->sense_response = 0;
+ /* Flag command as in-progress */
+ command->rc = -EINPROGRESS;
+
/* Issue SCSI command */
if ( ( rc = scsi->command ( scsi, command ) ) != 0 ) {
- /* Something went wrong with the issuing mechanism,
- * (rather than with the command itself)
- */
- DBG ( "SCSI %p " SCSI_CDB_FORMAT " err %s\n",
- scsi, SCSI_CDB_DATA ( command->cdb ), strerror ( rc ) );
+ /* Something went wrong with the issuing mechanism */
+ DBGC ( scsi, "SCSI %p " SCSI_CDB_FORMAT " err %s\n",
+ scsi, SCSI_CDB_DATA ( command->cdb ), strerror ( rc ) );
+ return rc;
+ }
+
+ /* Wait for command to complete */
+ while ( command->rc == -EINPROGRESS )
+ step();
+ if ( ( rc = command->rc ) != 0 ) {
+ /* Something went wrong with the command execution */
+ DBGC ( scsi, "SCSI %p " SCSI_CDB_FORMAT " err %s\n",
+ scsi, SCSI_CDB_DATA ( command->cdb ), strerror ( rc ) );
return rc;
}
/* Check for SCSI errors */
if ( command->status != 0 ) {
- DBG ( "SCSI %p " SCSI_CDB_FORMAT " status %02x sense %02x\n",
- scsi, SCSI_CDB_DATA ( command->cdb ),
- command->status, command->sense_response );
+ DBGC ( scsi, "SCSI %p " SCSI_CDB_FORMAT " status %02x sense "
+ "%02x\n", scsi, SCSI_CDB_DATA ( command->cdb ),
+ command->status, command->sense_response );
return -EIO;
}
@@ -271,12 +301,17 @@ int init_scsidev ( struct scsi_device *scsi ) {
for ( i = 0 ; i < SCSI_MAX_DUMMY_READ_CAP ; i++ ) {
if ( ( rc = scsi_read_capacity_10 ( &scsi->blockdev ) ) == 0 )
break;
+ DBGC ( scsi, "SCSI %p ignoring start-of-day error (#%d)\n",
+ scsi, ( i + 1 ) );
}
/* Try READ CAPACITY (10), which is a mandatory command, first. */
scsi->blockdev.op = &scsi_operations_10;
- if ( ( rc = scsi_read_capacity_10 ( &scsi->blockdev ) ) != 0 )
+ if ( ( rc = scsi_read_capacity_10 ( &scsi->blockdev ) ) != 0 ) {
+ DBGC ( scsi, "SCSI %p could not READ CAPACITY (10): %s\n",
+ scsi, strerror ( rc ) );
return rc;
+ }
/* If capacity range was exceeded (i.e. capacity.lba was
* 0xffffffff, meaning that blockdev->blocks is now zero), use
@@ -285,8 +320,46 @@ int init_scsidev ( struct scsi_device *scsi ) {
*/
if ( scsi->blockdev.blocks == 0 ) {
scsi->blockdev.op = &scsi_operations_16;
- if ( ( rc = scsi_read_capacity_16 ( &scsi->blockdev ) ) != 0 )
+ if ( ( rc = scsi_read_capacity_16 ( &scsi->blockdev ) ) != 0 ){
+ DBGC ( scsi, "SCSI %p could not READ CAPACITY (16): "
+ "%s\n", scsi, strerror ( rc ) );
return rc;
+ }
+ }
+
+ DBGC ( scsi, "SCSI %p using READ/WRITE (%d) commands\n", scsi,
+ ( ( scsi->blockdev.op == &scsi_operations_10 ) ? 10 : 16 ) );
+ DBGC ( scsi, "SCSI %p capacity is %ld MB (%#llx blocks)\n", scsi,
+ ( ( unsigned long ) ( scsi->blockdev.blocks >> 11 ) ),
+ scsi->blockdev.blocks );
+
+ return 0;
+}
+
+/**
+ * Parse SCSI LUN
+ *
+ * @v lun_string LUN string representation
+ * @v lun LUN to fill in
+ * @ret rc Return status code
+ */
+int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun ) {
+ char *p;
+ int i;
+
+ memset ( lun, 0, sizeof ( *lun ) );
+ if ( lun_string ) {
+ p = ( char * ) lun_string;
+ for ( i = 0 ; i < 4 ; i++ ) {
+ lun->u16[i] = htons ( strtoul ( p, &p, 16 ) );
+ if ( *p == '\0' )
+ break;
+ if ( *p != '-' )
+ return -EINVAL;
+ p++;
+ }
+ if ( *p )
+ return -EINVAL;
}
return 0;