Automatically select between the "10" and "16" variants of command set,
[people/xl0/gpxe.git] / src / drivers / block / scsi.c
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 <errno.h>
23 #include <gpxe/blockdev.h>
24 #include <gpxe/scsi.h>
25
26 /** @file
27  *
28  * SCSI block device
29  *
30  */
31
32 static inline __attribute__ (( always_inline )) struct scsi_device *
33 block_to_scsi ( struct block_device *blockdev ) {
34         return container_of ( blockdev, struct scsi_device, blockdev );
35 }
36
37 /**
38  * Issue SCSI command
39  *
40  * @v scsi              SCSI device
41  * @v command           SCSI command
42  * @ret rc              Return status code
43  */
44 static int scsi_command ( struct scsi_device *scsi,
45                           struct scsi_command *command ) {
46         int rc;
47
48         /* Clear sense response code before issuing command */
49         command->sense_response = 0;
50
51         /* Issue SCSI command */
52         if ( ( rc = scsi->command ( scsi, command ) ) != 0 ) {
53                 /* Something went wrong with the issuing mechanism,
54                  * (rather than with the command itself)
55                  */
56                 DBG ( "SCSI %p " SCSI_CDB_FORMAT " err %d\n",
57                       scsi, SCSI_CDB_DATA ( command->cdb ), rc );
58                 return rc;
59         }
60
61         /* Check for SCSI errors */
62         if ( command->status != 0 ) {
63                 DBG ( "SCSI %p " SCSI_CDB_FORMAT " status %02x sense %02x\n",
64                       scsi, SCSI_CDB_DATA ( command->cdb ),
65                       command->status, command->sense_response );
66                 return -EIO;
67         }
68
69         return 0;
70 }
71
72 /**
73  * Read block from SCSI device using READ (10)
74  *
75  * @v blockdev          Block device
76  * @v block             LBA block number
77  * @v count             Block count
78  * @v buffer            Data buffer
79  * @ret rc              Return status code
80  */
81 static int scsi_read_10 ( struct block_device *blockdev, uint64_t block,
82                           unsigned long count, userptr_t buffer ) {
83         struct scsi_device *scsi = block_to_scsi ( blockdev );
84         struct scsi_command command;
85         struct scsi_cdb_read_10 *cdb = &command.cdb.read10;
86
87         /* Issue READ (10) */
88         memset ( &command, 0, sizeof ( command ) );
89         cdb->opcode = SCSI_OPCODE_READ_10;
90         cdb->lba = cpu_to_be32 ( block );
91         cdb->len = cpu_to_be16 ( count );
92         command.data_in = buffer;
93         command.data_in_len = ( count * blockdev->blksize );
94         return scsi_command ( scsi, &command );
95 }
96
97 /**
98  * Read block from SCSI device using READ (16)
99  *
100  * @v blockdev          Block device
101  * @v block             LBA block number
102  * @v count             Block count
103  * @v buffer            Data buffer
104  * @ret rc              Return status code
105  */
106 static int scsi_read_16 ( struct block_device *blockdev, uint64_t block,
107                           unsigned long count, userptr_t buffer ) {
108         struct scsi_device *scsi = block_to_scsi ( blockdev );
109         struct scsi_command command;
110         struct scsi_cdb_read_16 *cdb = &command.cdb.read16;
111
112         /* Issue READ (16) */
113         memset ( &command, 0, sizeof ( command ) );
114         cdb->opcode = SCSI_OPCODE_READ_16;
115         cdb->lba = cpu_to_be64 ( block );
116         cdb->len = cpu_to_be32 ( count );
117         command.data_in = buffer;
118         command.data_in_len = ( count * blockdev->blksize );
119         return scsi_command ( scsi, &command );
120 }
121
122 /**
123  * Write block to SCSI device using WRITE (10)
124  *
125  * @v blockdev          Block device
126  * @v block             LBA block number
127  * @v count             Block count
128  * @v buffer            Data buffer
129  * @ret rc              Return status code
130  */
131 static int scsi_write_10 ( struct block_device *blockdev, uint64_t block,
132                            unsigned long count, userptr_t buffer ) {
133         struct scsi_device *scsi = block_to_scsi ( blockdev );
134         struct scsi_command command;
135         struct scsi_cdb_write_10 *cdb = &command.cdb.write10;
136
137         /* Issue WRITE (10) */
138         memset ( &command, 0, sizeof ( command ) );
139         cdb->opcode = SCSI_OPCODE_WRITE_10;
140         cdb->lba = cpu_to_be32 ( block );
141         cdb->len = cpu_to_be16 ( count );
142         command.data_out = buffer;
143         command.data_out_len = ( count * blockdev->blksize );
144         return scsi_command ( scsi, &command );
145 }
146
147 /**
148  * Write block to SCSI device using WRITE (16)
149  *
150  * @v blockdev          Block device
151  * @v block             LBA block number
152  * @v count             Block count
153  * @v buffer            Data buffer
154  * @ret rc              Return status code
155  */
156 static int scsi_write_16 ( struct block_device *blockdev, uint64_t block,
157                            unsigned long count, userptr_t buffer ) {
158         struct scsi_device *scsi = block_to_scsi ( blockdev );
159         struct scsi_command command;
160         struct scsi_cdb_write_16 *cdb = &command.cdb.write16;
161
162         /* Issue WRITE (16) */
163         memset ( &command, 0, sizeof ( command ) );
164         cdb->opcode = SCSI_OPCODE_WRITE_16;
165         cdb->lba = cpu_to_be64 ( block );
166         cdb->len = cpu_to_be32 ( count );
167         command.data_out = buffer;
168         command.data_out_len = ( count * blockdev->blksize );
169         return scsi_command ( scsi, &command );
170 }
171
172 /**
173  * Read capacity of SCSI device via READ CAPACITY (10)
174  *
175  * @v blockdev          Block device
176  * @ret rc              Return status code
177  */
178 static int scsi_read_capacity_10 ( struct block_device *blockdev ) {
179         struct scsi_device *scsi = block_to_scsi ( blockdev );
180         struct scsi_command command;
181         struct scsi_cdb_read_capacity_10 *cdb = &command.cdb.readcap10;
182         struct scsi_capacity_10 capacity;
183         int rc;
184
185         /* Issue READ CAPACITY (10) */
186         memset ( &command, 0, sizeof ( command ) );
187         cdb->opcode = SCSI_OPCODE_READ_CAPACITY_10;
188         command.data_in = virt_to_user ( &capacity );
189         command.data_in_len = sizeof ( capacity );
190
191         if ( ( rc = scsi_command ( scsi, &command ) ) != 0 )
192                 return rc;
193
194         /* Fill in block device fields */
195         blockdev->blksize = be32_to_cpu ( capacity.blksize );
196         blockdev->blocks = ( be32_to_cpu ( capacity.lba ) + 1 );
197
198         return 0;
199 }
200
201 /**
202  * Read capacity of SCSI device via READ CAPACITY (16)
203  *
204  * @v blockdev          Block device
205  * @ret rc              Return status code
206  */
207 static int scsi_read_capacity_16 ( struct block_device *blockdev ) {
208         struct scsi_device *scsi = block_to_scsi ( blockdev );
209         struct scsi_command command;
210         struct scsi_cdb_read_capacity_16 *cdb = &command.cdb.readcap16;
211         struct scsi_capacity_16 capacity;
212         int rc;
213
214         /* Issue READ CAPACITY (16) */
215         memset ( &command, 0, sizeof ( command ) );
216         cdb->opcode = SCSI_OPCODE_SERVICE_ACTION_IN;
217         cdb->service_action = SCSI_SERVICE_ACTION_READ_CAPACITY_16;
218         cdb->len = cpu_to_be32 ( sizeof ( capacity ) );
219         command.data_in = virt_to_user ( &capacity );
220         command.data_in_len = sizeof ( capacity );
221
222         if ( ( rc = scsi_command ( scsi, &command ) ) != 0 )
223                 return rc;
224
225         /* Fill in block device fields */
226         blockdev->blksize = be32_to_cpu ( capacity.blksize );
227         blockdev->blocks = ( be64_to_cpu ( capacity.lba ) + 1 );
228         return 0;
229 }
230
231 /**
232  * Initialise SCSI device
233  *
234  * @v scsi              SCSI device
235  * @ret rc              Return status code
236  *
237  * Initialises a SCSI device.  The scsi_device::command and
238  * scsi_device::lun fields must already be filled in.  This function
239  * will configure scsi_device::blockdev, including issuing a READ
240  * CAPACITY call to determine the block size and total device size.
241  */
242 int init_scsidev ( struct scsi_device *scsi ) {
243         int rc;
244
245         /* Issue a theoretically extraneous READ CAPACITY (10)
246          * command, solely in order to draw out the "CHECK CONDITION
247          * (power-on occurred)" that some dumb targets insist on
248          * sending as an error at start of day.
249          */
250         scsi_read_capacity_10 ( &scsi->blockdev );
251
252         /* Try READ CAPACITY (10), which is a mandatory command, first. */
253         scsi->blockdev.read = scsi_read_10;
254         scsi->blockdev.write = scsi_write_10;
255         if ( ( rc = scsi_read_capacity_10 ( &scsi->blockdev ) ) != 0 )
256                 return rc;
257
258         /* If capacity range was exceeded (i.e. capacity.lba was
259          * 0xffffffff, meaning that blockdev->blocks is now zero), use
260          * READ CAPACITY (16) instead.  READ CAPACITY (16) is not
261          * mandatory, so we can't just use it straight off.
262          */
263         if ( scsi->blockdev.blocks == 0 ) {
264                 scsi->blockdev.read = scsi_read_16;
265                 scsi->blockdev.write = scsi_write_16;
266                 if ( ( rc = scsi_read_capacity_16 ( &scsi->blockdev ) ) != 0 )
267                         return rc;
268         }
269
270         return 0;
271 }