Catch SCSI errors, and work around the start-of-day CHECK CONDITION
[people/mcb30/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
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 ( 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_16 *cdb = &command.cdb.read16;
86
87         /* Issue READ (16) */
88         memset ( &command, 0, sizeof ( command ) );
89         cdb->opcode = SCSI_OPCODE_READ_16;
90         cdb->lba = cpu_to_be64 ( block );
91         cdb->len = cpu_to_be32 ( count );
92         command.data_in = buffer;
93         command.data_in_len = ( count * blockdev->blksize );
94         return scsi_command ( scsi, &command );
95 }
96
97 /**
98  * Write block to SCSI device
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_write ( 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_write_16 *cdb = &command.cdb.write16;
111
112         /* Issue WRITE (16) */
113         memset ( &command, 0, sizeof ( command ) );
114         cdb->opcode = SCSI_OPCODE_WRITE_16;
115         cdb->lba = cpu_to_be64 ( block );
116         cdb->len = cpu_to_be32 ( count );
117         command.data_out = buffer;
118         command.data_out_len = ( count * blockdev->blksize );
119         return scsi_command ( scsi, &command );
120 }
121
122 /**
123  * Read capacity of SCSI device via READ CAPACITY (10)
124  *
125  * @v blockdev          Block device
126  * @ret rc              Return status code
127  */
128 static int scsi_read_capacity_10 ( struct block_device *blockdev ) {
129         struct scsi_device *scsi = block_to_scsi ( blockdev );
130         struct scsi_command command;
131         struct scsi_cdb_read_capacity_10 *cdb = &command.cdb.readcap10;
132         struct scsi_capacity_10 capacity;
133         int rc;
134
135         /* Issue READ CAPACITY (10) */
136         memset ( &command, 0, sizeof ( command ) );
137         cdb->opcode = SCSI_OPCODE_READ_CAPACITY_10;
138         command.data_in = virt_to_user ( &capacity );
139         command.data_in_len = sizeof ( capacity );
140
141         if ( ( rc = scsi_command ( scsi, &command ) ) != 0 )
142                 return rc;
143
144         /* Fill in block device fields */
145         blockdev->blksize = be32_to_cpu ( capacity.blksize );
146         blockdev->blocks = ( be32_to_cpu ( capacity.lba ) + 1 );
147
148         return 0;
149 }
150
151 /**
152  * Read capacity of SCSI device via READ CAPACITY (16)
153  *
154  * @v blockdev          Block device
155  * @ret rc              Return status code
156  */
157 static int scsi_read_capacity_16 ( struct block_device *blockdev ) {
158         struct scsi_device *scsi = block_to_scsi ( blockdev );
159         struct scsi_command command;
160         struct scsi_cdb_read_capacity_16 *cdb = &command.cdb.readcap16;
161         struct scsi_capacity_16 capacity;
162         int rc;
163
164         /* Issue READ CAPACITY (16) */
165         memset ( &command, 0, sizeof ( command ) );
166         cdb->opcode = SCSI_OPCODE_SERVICE_ACTION_IN;
167         cdb->service_action = SCSI_SERVICE_ACTION_READ_CAPACITY_16;
168         cdb->len = cpu_to_be32 ( sizeof ( capacity ) );
169         command.data_in = virt_to_user ( &capacity );
170         command.data_in_len = sizeof ( capacity );
171
172         if ( ( rc = scsi_command ( scsi, &command ) ) != 0 )
173                 return rc;
174
175         /* Fill in block device fields */
176         blockdev->blksize = be32_to_cpu ( capacity.blksize );
177         blockdev->blocks = ( be64_to_cpu ( capacity.lba ) + 1 );
178         return 0;
179 }
180
181 /**
182  * Read capacity of SCSI device
183  *
184  * @v blockdev          Block device
185  * @ret rc              Return status code
186  */
187 static int scsi_read_capacity ( struct block_device *blockdev ) {
188         int rc;
189
190         /* Issue a theoretically extraneous READ CAPACITY (10)
191          * command, solely in order to draw out the "CHECK CONDITION
192          * (power-on occurred)" that some dumb targets insist on
193          * sending as an error at start of day.
194          */
195         scsi_read_capacity_10 ( blockdev );
196
197         /* Try READ CAPACITY (10), which is a mandatory command, first. */
198         if ( ( rc = scsi_read_capacity_10 ( blockdev ) ) != 0 )
199                 return rc;
200
201         /* If capacity range was exceeded (i.e. capacity.lba was
202          * 0xffffffff, meaning that blockdev->blocks is now zero), use
203          * READ CAPACITY (16) instead.  READ CAPACITY (16) is not
204          * mandatory, so we can't just use it straight off.
205          */
206         if ( blockdev->blocks == 0 ) {
207                 if ( ( rc = scsi_read_capacity_16 ( blockdev ) ) != 0 )
208                         return rc;
209         }
210
211         return 0;
212 }
213
214 /**
215  * Initialise SCSI device
216  *
217  * @v scsi              SCSI device
218  * @ret rc              Return status code
219  *
220  * Initialises a SCSI device.  The scsi_device::command and
221  * scsi_device::lun fields must already be filled in.  This function
222  * will configure scsi_device::blockdev, including issuing a READ
223  * CAPACITY call to determine the block size and total device size.
224  */
225 int init_scsidev ( struct scsi_device *scsi ) {
226         /** Fill in read and write methods, and get device capacity */
227         scsi->blockdev.read = scsi_read;
228         scsi->blockdev.write = scsi_write;
229         return scsi_read_capacity ( &scsi->blockdev );
230 }