Просмотр исходного кода

Defined SCSI device interface, and added SCSI block device

implementation.
tags/v0.9.3
Michael Brown 18 лет назад
Родитель
Сommit
f33f01c126
2 измененных файлов: 279 добавлений и 7 удалений
  1. 142
    0
      src/drivers/block/scsi.c
  2. 137
    7
      src/include/gpxe/scsi.h

+ 142
- 0
src/drivers/block/scsi.c Просмотреть файл

@@ -0,0 +1,142 @@
1
+/*
2
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <stddef.h>
20
+#include <string.h>
21
+#include <byteswap.h>
22
+#include <gpxe/blockdev.h>
23
+#include <gpxe/scsi.h>
24
+
25
+/** @file
26
+ *
27
+ * SCSI block device
28
+ *
29
+ */
30
+
31
+static inline __attribute__ (( always_inline )) struct scsi_device *
32
+block_to_scsi ( struct block_device *blockdev ) {
33
+	return container_of ( blockdev, struct scsi_device, blockdev );
34
+}
35
+
36
+/**
37
+ * Issue SCSI command
38
+ *
39
+ * @v scsi		SCSI device
40
+ * @v command		SCSI command
41
+ * @ret rc		Return status code
42
+ */
43
+static int scsi_command ( struct scsi_device *scsi,
44
+			  struct scsi_command *command ) {
45
+	return scsi->command ( scsi, command );
46
+}
47
+
48
+/**
49
+ * Read block from SCSI device
50
+ *
51
+ * @v blockdev		Block device
52
+ * @v block		LBA block number
53
+ * @v buffer		Data buffer
54
+ * @ret rc		Return status code
55
+ */
56
+static int scsi_read ( struct block_device *blockdev, uint64_t block,
57
+		       void *buffer ) {
58
+	struct scsi_device *scsi = block_to_scsi ( blockdev );
59
+	struct scsi_command command;
60
+	struct scsi_cdb_read_16 *cdb = &command.cdb.read16;
61
+
62
+	/* Issue READ (16) */
63
+	memset ( &command, 0, sizeof ( command ) );
64
+	cdb->opcode = SCSI_OPCODE_READ_16;
65
+	cdb->lba = cpu_to_be64 ( block );
66
+	cdb->len = cpu_to_be32 ( 1 ); /* always a single block */
67
+	command.data_in = buffer;
68
+	command.data_in_len = blockdev->blksize;
69
+	return scsi_command ( scsi, &command );
70
+}
71
+
72
+/**
73
+ * Write block to SCSI device
74
+ *
75
+ * @v blockdev		Block device
76
+ * @v block		LBA block number
77
+ * @v buffer		Data buffer
78
+ * @ret rc		Return status code
79
+ */
80
+static int scsi_write ( struct block_device *blockdev, uint64_t block,
81
+			const void *buffer ) {
82
+	struct scsi_device *scsi = block_to_scsi ( blockdev );
83
+	struct scsi_command command;
84
+	struct scsi_cdb_write_16 *cdb = &command.cdb.write16;
85
+
86
+	/* Issue WRITE (16) */
87
+	memset ( &command, 0, sizeof ( command ) );
88
+	cdb->opcode = SCSI_OPCODE_WRITE_16;
89
+	cdb->lba = cpu_to_be64 ( block );
90
+	cdb->len = cpu_to_be32 ( 1 ); /* always a single block */
91
+	command.data_out = buffer;
92
+	command.data_out_len = blockdev->blksize;
93
+	return scsi_command ( scsi, &command );
94
+}
95
+
96
+/**
97
+ * Read capacity of SCSI device
98
+ *
99
+ * @v blockdev		Block device
100
+ * @ret rc		Return status code
101
+ */
102
+static int scsi_read_capacity ( struct block_device *blockdev ) {
103
+	struct scsi_device *scsi = block_to_scsi ( blockdev );
104
+	struct scsi_command command;
105
+	struct scsi_cdb_read_capacity_16 *cdb = &command.cdb.readcap16;
106
+	struct scsi_capacity_16 capacity;
107
+	int rc;
108
+
109
+	/* Issue READ CAPACITY (16) */
110
+	memset ( &command, 0, sizeof ( command ) );
111
+	cdb->opcode = SCSI_OPCODE_SERVICE_ACTION_IN;
112
+	cdb->service_action = SCSI_SERVICE_ACTION_READ_CAPACITY_16;
113
+	cdb->len = cpu_to_be32 ( sizeof ( capacity ) );
114
+	command.data_in = &capacity;
115
+	command.data_in_len = sizeof ( capacity );
116
+
117
+	if ( ( rc = scsi_command ( scsi, &command ) ) != 0 )
118
+		return rc;
119
+
120
+	/* Fill in block device fields */
121
+	blockdev->blksize = be32_to_cpu ( capacity.blksize );
122
+	blockdev->blocks = ( be64_to_cpu ( capacity.lba ) + 1 );
123
+	return 0;
124
+}
125
+
126
+/**
127
+ * Initialise SCSI device
128
+ *
129
+ * @v scsi		SCSI device
130
+ * @ret rc		Return status code
131
+ *
132
+ * Initialises a SCSI device.  The scsi_device::command and
133
+ * scsi_device::lun fields must already be filled in.  This function
134
+ * will configure scsi_device::blockdev, including issuing a READ
135
+ * CAPACITY call to determine the block size and total device size.
136
+ */
137
+int init_scsidev ( struct scsi_device *scsi ) {
138
+	/** Fill in read and write methods, and get device capacity */
139
+	scsi->blockdev.read = scsi_read;
140
+	scsi->blockdev.write = scsi_write;
141
+	return scsi_read_capacity ( &scsi->blockdev );
142
+}

+ 137
- 7
src/include/gpxe/scsi.h Просмотреть файл

@@ -2,9 +2,61 @@
2 2
 #define _GPXE_SCSI_H
3 3
 
4 4
 #include <stdint.h>
5
+#include <gpxe/blockdev.h>
5 6
 
6
-struct scsi_cdb_read_10 {
7
-	/** Opcode */
7
+/**
8
+ * @defgroup scsiops SCSI operation codes
9
+ * @{
10
+ */
11
+
12
+#define SCSI_OPCODE_READ_16		0x88	/**< READ (16) */
13
+#define SCSI_OPCODE_WRITE_16		0x8a	/**< WRITE (16) */
14
+#define SCSI_OPCODE_SERVICE_ACTION_IN	0x9e	/**< SERVICE ACTION IN */
15
+#define SCSI_SERVICE_ACTION_READ_CAPACITY_16 0x10 /**< READ CAPACITY (16) */
16
+
17
+/** @} */
18
+
19
+/**
20
+ * @defgroup scsiflags SCSI flags
21
+ * @{
22
+ */
23
+
24
+#define SCSI_FL_FUA_NV		0x02	/**< Force unit access to NVS */
25
+#define SCSI_FL_FUA		0x08	/**< Force unit access */
26
+#define SCSI_FL_DPO		0x10	/**< Disable cache page out */
27
+
28
+/** @} */
29
+
30
+/**
31
+ * @defgroup scsicdbs SCSI command data blocks
32
+ * @{
33
+ */
34
+
35
+/** A SCSI "READ (16)" CDB */
36
+struct scsi_cdb_read_16 {
37
+	/** Opcode (0x88) */
38
+	uint8_t opcode;
39
+	/** Flags */
40
+	uint8_t flags;
41
+	/** Start address
42
+	 *
43
+	 * This is a logical block number, in big-endian order.
44
+	 */
45
+	uint64_t lba;
46
+	/** Transfer length
47
+	 *
48
+	 * This is a logical block count, in big-endian order.
49
+	 */
50
+	uint32_t len;
51
+	/** Group number */
52
+	uint8_t group;
53
+	/** Control byte */
54
+	uint8_t control;
55
+} __attribute__ (( packed ));
56
+
57
+/** A SCSI "WRITE (16)" CDB */
58
+struct scsi_cdb_write_16 {
59
+	/** Opcode (0x8a) */
8 60
 	uint8_t opcode;
9 61
 	/** Flags */
10 62
 	uint8_t flags;
@@ -12,23 +64,101 @@ struct scsi_cdb_read_10 {
12 64
 	 *
13 65
 	 * This is a logical block number, in big-endian order.
14 66
 	 */
15
-	uint32_t lba;
67
+	uint64_t lba;
68
+	/** Transfer length
69
+	 *
70
+	 * This is a logical block count, in big-endian order.
71
+	 */
72
+	uint32_t len;
16 73
 	/** Group number */
17 74
 	uint8_t group;
75
+	/** Control byte */
76
+	uint8_t control;
77
+} __attribute__ (( packed ));
78
+
79
+/** A SCSI "READ CAPACITY (16)" CDB */
80
+struct scsi_cdb_read_capacity_16 {
81
+	/** Opcode (0x9e) */
82
+	uint8_t opcode;
83
+	/** Service action */
84
+	uint8_t service_action;
85
+	/** Logical block address
86
+	 *
87
+	 * Applicable only if the PMI bit is set.
88
+	 */
89
+	uint64_t lba;
18 90
 	/** Transfer length
19 91
 	 *
20
-	 * This is a logical block count.
92
+	 * This is the size of the data-in buffer, in bytes.
21 93
 	 */
22
-	uint16_t len;
94
+	uint32_t len;
95
+	/** Reserved */
96
+	uint8_t reserved;
23 97
 	/** Control byte */
24 98
 	uint8_t control;
25 99
 } __attribute__ (( packed ));
26 100
 
27
-#define SCSI_OPCODE_READ_10 0x28
101
+/** SCSI "READ CAPACITY (16)" parameter data */
102
+struct scsi_capacity_16 {
103
+	/** Maximum logical block number */
104
+	uint64_t lba;
105
+	/** Block length in bytes */
106
+	uint32_t blksize;
107
+	/** Reserved */
108
+	uint8_t reserved[20];
109
+} __attribute__ (( packed ));
28 110
 
111
+/** A SCSI Command Data Block */
29 112
 union scsi_cdb {
30
-	struct scsi_cdb_read_10 read_10;
113
+	struct scsi_cdb_read_16 read16;
114
+	struct scsi_cdb_write_16 write16;
115
+	struct scsi_cdb_read_capacity_16 readcap16;
31 116
 	char bytes[16];
32 117
 };
33 118
 
119
+/** @} */
120
+
121
+/** A SCSI command */
122
+struct scsi_command {
123
+	/** CDB for this command */
124
+	union scsi_cdb cdb;
125
+	/** Data-out buffer (may be NULL) */
126
+	const void *data_out;
127
+	/** Data-out buffer length
128
+	 *
129
+	 * Must be zero if @c data_out is NULL
130
+	 */
131
+	size_t data_out_len;
132
+	/** Data-in buffer (may be NULL) */
133
+	void *data_in;
134
+	/** Data-in buffer length
135
+	 *
136
+	 * Must be zero if @c data_in is NULL
137
+	 */
138
+	size_t data_in_len;
139
+};
140
+
141
+/** A SCSI device */
142
+struct scsi_device {
143
+	/** Block device interface */
144
+	struct block_device blockdev;
145
+	/** Logical unit number (LUN)
146
+	 *
147
+	 * This is a four-level LUN as specified by SAM-2, in
148
+	 * big-endian order.
149
+	 */
150
+	uint64_t lun;
151
+	/**
152
+	 * Issue SCSI command
153
+	 *
154
+	 * @v scsi		SCSI device
155
+	 * @v command		SCSI command
156
+	 * @ret rc		Return status code
157
+	 */
158
+	int ( * command ) ( struct scsi_device *scsi,
159
+			    struct scsi_command *command );
160
+};
161
+
162
+extern int init_scsidev ( struct scsi_device *scsi );
163
+
34 164
 #endif /* _GPXE_SCSI_H */

Загрузка…
Отмена
Сохранить