Browse Source

[scsi] Wait for a successful TEST UNIT READY command

Some SCSI targets (observed with an EMC CLARiiON Fibre Channel target)
will not respond to commands correctly until a TEST UNIT READY has
been issued.  In particular, a READ CAPACITY (10) command will return
with a success status, but no capacity data.

Fix by issuing a TEST UNIT READY command automatically, and delaying
further SCSI commands until the TEST UNIT READY has succeeded.

Reported-by: Hadar Hen Zion <hadarh@mellanox.co.il>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 years ago
parent
commit
57bab0ae4a
2 changed files with 144 additions and 3 deletions
  1. 132
    3
      src/drivers/block/scsi.c
  2. 12
    0
      src/include/ipxe/scsi.h

+ 132
- 3
src/drivers/block/scsi.c View File

24
 #include <byteswap.h>
24
 #include <byteswap.h>
25
 #include <errno.h>
25
 #include <errno.h>
26
 #include <ipxe/list.h>
26
 #include <ipxe/list.h>
27
+#include <ipxe/process.h>
28
+#include <ipxe/xfer.h>
27
 #include <ipxe/blockdev.h>
29
 #include <ipxe/blockdev.h>
28
 #include <ipxe/scsi.h>
30
 #include <ipxe/scsi.h>
29
 
31
 
202
 
204
 
203
 	/** SCSI LUN */
205
 	/** SCSI LUN */
204
 	struct scsi_lun lun;
206
 	struct scsi_lun lun;
207
+	/** Flags */
208
+	unsigned int flags;
209
+
210
+	/** TEST UNIT READY interface */
211
+	struct interface ready;
212
+	/** TEST UNIT READY process */
213
+	struct process process;
205
 
214
 
206
 	/** List of commands */
215
 	/** List of commands */
207
 	struct list_head cmds;
216
 	struct list_head cmds;
208
 };
217
 };
209
 
218
 
219
+/** SCSI device flags */
220
+enum scsi_device_flags {
221
+	/** Unit is ready */
222
+	SCSIDEV_UNIT_READY = 0x0001,
223
+};
224
+
210
 /** A SCSI command */
225
 /** A SCSI command */
211
 struct scsi_command {
226
 struct scsi_command {
212
 	/** Reference count */
227
 	/** Reference count */
624
 	.done = scsicmd_read_capacity_done,
639
 	.done = scsicmd_read_capacity_done,
625
 };
640
 };
626
 
641
 
642
+/**
643
+ * Construct SCSI TEST UNIT READY command
644
+ *
645
+ * @v scsicmd		SCSI command
646
+ * @v command		SCSI command IU
647
+ */
648
+static void scsicmd_test_unit_ready_cmd ( struct scsi_command *scsicmd __unused,
649
+					  struct scsi_cmd *command ) {
650
+	struct scsi_cdb_test_unit_ready *testready = &command->cdb.testready;
651
+
652
+	testready->opcode = SCSI_OPCODE_TEST_UNIT_READY;
653
+}
654
+
655
+/** SCSI TEST UNIT READY command type */
656
+static struct scsi_command_type scsicmd_test_unit_ready = {
657
+	.name = "TEST UNIT READY",
658
+	.cmd = scsicmd_test_unit_ready_cmd,
659
+	.done = scsicmd_close,
660
+};
661
+
627
 /** SCSI command block interface operations */
662
 /** SCSI command block interface operations */
628
 static struct interface_operation scsicmd_block_op[] = {
663
 static struct interface_operation scsicmd_block_op[] = {
629
 	INTF_OP ( intf_close, struct scsi_command *, scsicmd_close ),
664
 	INTF_OP ( intf_close, struct scsi_command *, scsicmd_close ),
751
 				 0, 0, UNULL, 0 );
786
 				 0, 0, UNULL, 0 );
752
 }
787
 }
753
 
788
 
789
+/**
790
+ * Test to see if SCSI device is ready
791
+ *
792
+ * @v scsidev		SCSI device
793
+ * @v block		Block data interface
794
+ * @ret rc		Return status code
795
+ */
796
+static int scsidev_test_unit_ready ( struct scsi_device *scsidev,
797
+				     struct interface *block ) {
798
+	return scsidev_command ( scsidev, block, &scsicmd_test_unit_ready,
799
+				 0, 0, UNULL, 0 );
800
+}
801
+
802
+/**
803
+ * Check SCSI device flow-control window
804
+ *
805
+ * @v scsidev		SCSI device
806
+ * @ret len		Length of window
807
+ */
808
+static size_t scsidev_window ( struct scsi_device *scsidev ) {
809
+
810
+	/* Refuse commands until unit is confirmed ready */
811
+	if ( ! ( scsidev->flags & SCSIDEV_UNIT_READY ) )
812
+		return 0;
813
+
814
+	return xfer_window ( &scsidev->scsi );
815
+}
816
+
754
 /**
817
 /**
755
  * Close SCSI device
818
  * Close SCSI device
756
  *
819
  *
761
 	struct scsi_command *scsicmd;
824
 	struct scsi_command *scsicmd;
762
 	struct scsi_command *tmp;
825
 	struct scsi_command *tmp;
763
 
826
 
827
+	/* Stop process */
828
+	process_del ( &scsidev->process );
829
+
764
 	/* Shut down interfaces */
830
 	/* Shut down interfaces */
765
 	intf_shutdown ( &scsidev->block, rc );
831
 	intf_shutdown ( &scsidev->block, rc );
766
 	intf_shutdown ( &scsidev->scsi, rc );
832
 	intf_shutdown ( &scsidev->scsi, rc );
833
+	intf_shutdown ( &scsidev->ready, rc );
767
 
834
 
768
 	/* Shut down any remaining commands */
835
 	/* Shut down any remaining commands */
769
 	list_for_each_entry_safe ( scsicmd, tmp, &scsidev->cmds, list ) {
836
 	list_for_each_entry_safe ( scsicmd, tmp, &scsidev->cmds, list ) {
775
 
842
 
776
 /** SCSI device block interface operations */
843
 /** SCSI device block interface operations */
777
 static struct interface_operation scsidev_block_op[] = {
844
 static struct interface_operation scsidev_block_op[] = {
845
+	INTF_OP ( xfer_window, struct scsi_device *, scsidev_window ),
778
 	INTF_OP ( block_read, struct scsi_device *, scsidev_read ),
846
 	INTF_OP ( block_read, struct scsi_device *, scsidev_read ),
779
 	INTF_OP ( block_write, struct scsi_device *, scsidev_write ),
847
 	INTF_OP ( block_write, struct scsi_device *, scsidev_write ),
780
 	INTF_OP ( block_read_capacity, struct scsi_device *,
848
 	INTF_OP ( block_read_capacity, struct scsi_device *,
787
 	INTF_DESC_PASSTHRU ( struct scsi_device, block,
855
 	INTF_DESC_PASSTHRU ( struct scsi_device, block,
788
 			     scsidev_block_op, scsi );
856
 			     scsidev_block_op, scsi );
789
 
857
 
858
+/**
859
+ * Handle SCSI TEST UNIT READY response
860
+ *
861
+ * @v scsidev		SCSI device
862
+ * @v rc		Reason for close
863
+ */
864
+static void scsidev_ready ( struct scsi_device *scsidev, int rc ) {
865
+
866
+	/* Shut down interface */
867
+	intf_shutdown ( &scsidev->ready, rc );
868
+
869
+	/* Close device on failure */
870
+	if ( rc != 0 ) {
871
+		DBGC ( scsidev, "SCSI %p not ready: %s\n",
872
+		       scsidev, strerror ( rc ) );
873
+		scsidev_close ( scsidev, rc );
874
+		return;
875
+	}
876
+
877
+	/* Mark device as ready */
878
+	scsidev->flags |= SCSIDEV_UNIT_READY;
879
+	xfer_window_changed ( &scsidev->block );
880
+	DBGC ( scsidev, "SCSI %p unit is ready\n", scsidev );
881
+}
882
+
883
+/** SCSI device TEST UNIT READY interface operations */
884
+static struct interface_operation scsidev_ready_op[] = {
885
+	INTF_OP ( intf_close, struct scsi_device *, scsidev_ready ),
886
+};
887
+
888
+/** SCSI device TEST UNIT READY interface descriptor */
889
+static struct interface_descriptor scsidev_ready_desc =
890
+	INTF_DESC ( struct scsi_device, ready, scsidev_ready_op );
891
+
892
+/**
893
+ * SCSI TEST UNIT READY process
894
+ *
895
+ * @v process		Process
896
+ */
897
+static void scsidev_step ( struct process *process ) {
898
+	struct scsi_device *scsidev =
899
+		container_of ( process, struct scsi_device, process );
900
+	int rc;
901
+
902
+	/* Wait until underlying SCSI device is ready */
903
+	if ( xfer_window ( &scsidev->scsi ) == 0 )
904
+		return;
905
+
906
+	/* Stop process */
907
+	process_del ( &scsidev->process );
908
+
909
+	DBGC ( scsidev, "SCSI %p waiting for unit to become ready\n",
910
+	       scsidev );
911
+
912
+	/* Issue TEST UNIT READY command */
913
+	if ( ( rc = scsidev_test_unit_ready ( scsidev, &scsidev->ready )) !=0){
914
+		scsidev_close ( scsidev, rc );
915
+		return;
916
+	}
917
+}
918
+
790
 /** SCSI device SCSI interface operations */
919
 /** SCSI device SCSI interface operations */
791
 static struct interface_operation scsidev_scsi_op[] = {
920
 static struct interface_operation scsidev_scsi_op[] = {
792
 	INTF_OP ( intf_close, struct scsi_device *, scsidev_close ),
921
 	INTF_OP ( intf_close, struct scsi_device *, scsidev_close ),
816
 	ref_init ( &scsidev->refcnt, NULL );
945
 	ref_init ( &scsidev->refcnt, NULL );
817
 	intf_init ( &scsidev->block, &scsidev_block_desc, &scsidev->refcnt );
946
 	intf_init ( &scsidev->block, &scsidev_block_desc, &scsidev->refcnt );
818
 	intf_init ( &scsidev->scsi, &scsidev_scsi_desc, &scsidev->refcnt );
947
 	intf_init ( &scsidev->scsi, &scsidev_scsi_desc, &scsidev->refcnt );
948
+	intf_init ( &scsidev->ready, &scsidev_ready_desc, &scsidev->refcnt );
949
+	process_init ( &scsidev->process, scsidev_step, &scsidev->refcnt );
819
 	INIT_LIST_HEAD ( &scsidev->cmds );
950
 	INIT_LIST_HEAD ( &scsidev->cmds );
820
 	memcpy ( &scsidev->lun, lun, sizeof ( scsidev->lun ) );
951
 	memcpy ( &scsidev->lun, lun, sizeof ( scsidev->lun ) );
821
 	DBGC ( scsidev, "SCSI %p created for LUN " SCSI_LUN_FORMAT "\n",
952
 	DBGC ( scsidev, "SCSI %p created for LUN " SCSI_LUN_FORMAT "\n",
822
 	       scsidev, SCSI_LUN_DATA ( scsidev->lun ) );
953
 	       scsidev, SCSI_LUN_DATA ( scsidev->lun ) );
823
 
954
 
824
-	/* Attach to SCSI and parent and interfaces, mortalise self,
825
-	 * and return
826
-	 */
955
+	/* Attach to SCSI and parent interfaces, mortalise self, and return */
827
 	intf_plug_plug ( &scsidev->scsi, scsi );
956
 	intf_plug_plug ( &scsidev->scsi, scsi );
828
 	intf_plug_plug ( &scsidev->block, block );
957
 	intf_plug_plug ( &scsidev->block, block );
829
 	ref_put ( &scsidev->refcnt );
958
 	ref_put ( &scsidev->refcnt );

+ 12
- 0
src/include/ipxe/scsi.h View File

28
 #define SCSI_OPCODE_READ_CAPACITY_10	0x25	/**< READ CAPACITY (10) */
28
 #define SCSI_OPCODE_READ_CAPACITY_10	0x25	/**< READ CAPACITY (10) */
29
 #define SCSI_OPCODE_SERVICE_ACTION_IN	0x9e	/**< SERVICE ACTION IN */
29
 #define SCSI_OPCODE_SERVICE_ACTION_IN	0x9e	/**< SERVICE ACTION IN */
30
 #define SCSI_SERVICE_ACTION_READ_CAPACITY_16 0x10 /**< READ CAPACITY (16) */
30
 #define SCSI_SERVICE_ACTION_READ_CAPACITY_16 0x10 /**< READ CAPACITY (16) */
31
+#define SCSI_OPCODE_TEST_UNIT_READY	0x00	/**< TEST UNIT READY */
31
 
32
 
32
 /** @} */
33
 /** @} */
33
 
34
 
192
 	uint8_t reserved[20];
193
 	uint8_t reserved[20];
193
 } __attribute__ (( packed ));
194
 } __attribute__ (( packed ));
194
 
195
 
196
+/** A SCSI "TEST UNIT READY" CDB */
197
+struct scsi_cdb_test_unit_ready {
198
+	/** Opcode (0x00) */
199
+	uint8_t opcode;
200
+	/** Reserved */
201
+	uint8_t reserved[4];
202
+	/** Control byte */
203
+	uint8_t control;
204
+} __attribute__ (( packed ));
205
+
195
 /** A SCSI Command Data Block */
206
 /** A SCSI Command Data Block */
196
 union scsi_cdb {
207
 union scsi_cdb {
197
 	struct scsi_cdb_read_10 read10;
208
 	struct scsi_cdb_read_10 read10;
200
 	struct scsi_cdb_write_16 write16;
211
 	struct scsi_cdb_write_16 write16;
201
 	struct scsi_cdb_read_capacity_10 readcap10;
212
 	struct scsi_cdb_read_capacity_10 readcap10;
202
 	struct scsi_cdb_read_capacity_16 readcap16;
213
 	struct scsi_cdb_read_capacity_16 readcap16;
214
+	struct scsi_cdb_test_unit_ready testready;
203
 	unsigned char bytes[16];
215
 	unsigned char bytes[16];
204
 };
216
 };
205
 
217
 

Loading…
Cancel
Save