blob: 59f5763858974b4e74c7d25ec9fc7800b68f3e12 [file] [log] [blame]
Kevin O'Connor76977b22010-02-17 01:01:32 -05001// Support for several common scsi like command data block requests
2//
3// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
4// Copyright (C) 2002 MandrakeSoft S.A.
5//
6// This file may be distributed under the terms of the GNU LGPLv3 license.
7
Kevin O'Connor2d2fa312013-09-14 21:55:26 -04008#include "ahci.h" // atapi_cmd_data
9#include "ata.h" // atapi_cmd_data
Kevin O'Connor76977b22010-02-17 01:01:32 -050010#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040011#include "blockcmd.h" // struct cdb_request_sense
12#include "boot.h" // boot_add_hd
Kevin O'Connorb3064592012-08-14 21:20:10 -040013#include "byteorder.h" // be32_to_cpu
Kevin O'Connor76977b22010-02-17 01:01:32 -050014#include "disk.h" // struct disk_op_s
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040015#include "esp-scsi.h" // esp_scsi_cmd_data
16#include "lsi-scsi.h" // lsi_scsi_cmd_data
17#include "megasas.h" // megasas_cmd_data
18#include "output.h" // dprintf
19#include "string.h" // memset
Kevin O'Connor7149fc82010-02-17 23:24:42 -050020#include "usb-msc.h" // usb_cmd_data
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +020021#include "usb-uas.h" // usb_cmd_data
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040022#include "util.h" // timer_calc
Paolo Bonzinic5c488f2012-02-27 17:22:23 +010023#include "virtio-scsi.h" // virtio_scsi_cmd_data
Kevin O'Connor76977b22010-02-17 01:01:32 -050024
Kevin O'Connor7149fc82010-02-17 23:24:42 -050025// Route command to low-level handler.
Kevin O'Connor76977b22010-02-17 01:01:32 -050026static int
27cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
28{
29 u8 type = GET_GLOBAL(op->drive_g->type);
30 switch (type) {
Kevin O'Connorbd6afe52012-07-21 12:01:12 -040031 case DTYPE_ATA_ATAPI:
Kevin O'Connor76977b22010-02-17 01:01:32 -050032 return atapi_cmd_data(op, cdbcmd, blocksize);
Kevin O'Connor7149fc82010-02-17 23:24:42 -050033 case DTYPE_USB:
34 return usb_cmd_data(op, cdbcmd, blocksize);
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +020035 case DTYPE_UAS:
36 return uas_cmd_data(op, cdbcmd, blocksize);
Kevin O'Connorbd6afe52012-07-21 12:01:12 -040037 case DTYPE_AHCI_ATAPI:
Gerd Hoffmannd52fdf62010-11-29 09:42:13 +010038 return ahci_cmd_data(op, cdbcmd, blocksize);
Paolo Bonzinic5c488f2012-02-27 17:22:23 +010039 case DTYPE_VIRTIO_SCSI:
40 return virtio_scsi_cmd_data(op, cdbcmd, blocksize);
Gerd Hoffmann9d6bac12012-07-20 10:59:25 +020041 case DTYPE_LSI_SCSI:
42 return lsi_scsi_cmd_data(op, cdbcmd, blocksize);
Paolo Bonzini7a39e722012-08-06 13:15:06 +020043 case DTYPE_ESP_SCSI:
44 return esp_scsi_cmd_data(op, cdbcmd, blocksize);
Hannes Reinecke2df70bf2012-11-13 15:03:31 +010045 case DTYPE_MEGASAS:
46 return megasas_cmd_data(op, cdbcmd, blocksize);
Kevin O'Connor76977b22010-02-17 01:01:32 -050047 default:
48 op->count = 0;
49 return DISK_RET_EPARAM;
50 }
51}
52
Kevin O'Connor1fd9a892012-03-14 21:27:45 -040053// Determine if the command is a request to pull data from the device
54int
55cdb_is_read(u8 *cdbcmd, u16 blocksize)
56{
57 return blocksize && cdbcmd[0] != CDB_CMD_WRITE_10;
58}
59
Kevin O'Connor7149fc82010-02-17 23:24:42 -050060int
Paolo Bonzini8c976e32011-11-16 13:02:51 +010061scsi_is_ready(struct disk_op_s *op)
62{
63 dprintf(6, "scsi_is_ready (drive=%p)\n", op->drive_g);
64
65 /* Retry TEST UNIT READY for 5 seconds unless MEDIUM NOT PRESENT is
66 * reported by the device. If the device reports "IN PROGRESS",
67 * 30 seconds is added. */
68 int in_progress = 0;
Kevin O'Connor018bdd72013-07-20 18:22:57 -040069 u32 end = timer_calc(5000);
Paolo Bonzini8c976e32011-11-16 13:02:51 +010070 for (;;) {
Kevin O'Connor018bdd72013-07-20 18:22:57 -040071 if (timer_check(end)) {
Paolo Bonzini8c976e32011-11-16 13:02:51 +010072 dprintf(1, "test unit ready failed\n");
73 return -1;
74 }
75
76 int ret = cdb_test_unit_ready(op);
77 if (!ret)
78 // Success
79 break;
80
81 struct cdbres_request_sense sense;
82 ret = cdb_get_sense(op, &sense);
83 if (ret)
84 // Error - retry.
85 continue;
86
87 // Sense succeeded.
88 if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */
89 dprintf(1, "Device reports MEDIUM NOT PRESENT\n");
90 return -1;
91 }
92
93 if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) {
94 /* IN PROGRESS OF BECOMING READY */
95 printf("Waiting for device to detect medium... ");
96 /* Allow 30 seconds more */
Kevin O'Connor018bdd72013-07-20 18:22:57 -040097 end = timer_calc(30000);
Paolo Bonzini8c976e32011-11-16 13:02:51 +010098 in_progress = 1;
99 }
100 }
101 return 0;
102}
103
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500104// Validate drive, find block size / sector count, and register drive.
Paolo Bonzinided04a32011-11-17 10:23:02 +0100105int
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500106scsi_drive_setup(struct drive_s *drive, const char *s, int prio)
Paolo Bonzinided04a32011-11-17 10:23:02 +0100107{
Paolo Bonzinided04a32011-11-17 10:23:02 +0100108 struct disk_op_s dop;
109 memset(&dop, 0, sizeof(dop));
110 dop.drive_g = drive;
111 struct cdbres_inquiry data;
112 int ret = cdb_get_inquiry(&dop, &data);
113 if (ret)
114 return ret;
115 char vendor[sizeof(data.vendor)+1], product[sizeof(data.product)+1];
116 char rev[sizeof(data.rev)+1];
117 strtcpy(vendor, data.vendor, sizeof(vendor));
118 nullTrailingSpace(vendor);
119 strtcpy(product, data.product, sizeof(product));
120 nullTrailingSpace(product);
121 strtcpy(rev, data.rev, sizeof(rev));
122 nullTrailingSpace(rev);
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500123 int pdt = data.pdt & 0x1f;
Paolo Bonzinided04a32011-11-17 10:23:02 +0100124 int removable = !!(data.removable & 0x80);
125 dprintf(1, "%s vendor='%s' product='%s' rev='%s' type=%d removable=%d\n"
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500126 , s, vendor, product, rev, pdt, removable);
Paolo Bonzinided04a32011-11-17 10:23:02 +0100127 drive->removable = removable;
128
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500129 if (pdt == SCSI_TYPE_CDROM) {
Paolo Bonzinided04a32011-11-17 10:23:02 +0100130 drive->blksize = CDROM_SECTOR_SIZE;
131 drive->sectors = (u64)-1;
132
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500133 char *desc = znprintf(MAXDESCSIZE, "DVD/CD [%s Drive %s %s %s]"
Paolo Bonzinided04a32011-11-17 10:23:02 +0100134 , s, vendor, product, rev);
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500135 boot_add_cd(drive, desc, prio);
Paolo Bonzinided04a32011-11-17 10:23:02 +0100136 return 0;
137 }
138
139 ret = scsi_is_ready(&dop);
140 if (ret) {
141 dprintf(1, "scsi_is_ready returned %d\n", ret);
142 return ret;
143 }
144
145 struct cdbres_read_capacity capdata;
146 ret = cdb_read_capacity(&dop, &capdata);
147 if (ret)
148 return ret;
149
150 // READ CAPACITY returns the address of the last block.
151 // We do not bother with READ CAPACITY(16) because BIOS does not support
152 // 64-bit LBA anyway.
Kevin O'Connorb3064592012-08-14 21:20:10 -0400153 drive->blksize = be32_to_cpu(capdata.blksize);
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500154 if (drive->blksize != DISK_SECTOR_SIZE) {
155 dprintf(1, "%s: unsupported block size %d\n", s, drive->blksize);
156 return -1;
157 }
Kevin O'Connorb3064592012-08-14 21:20:10 -0400158 drive->sectors = (u64)be32_to_cpu(capdata.sectors) + 1;
Paolo Bonzinided04a32011-11-17 10:23:02 +0100159 dprintf(1, "%s blksize=%d sectors=%d\n"
160 , s, drive->blksize, (unsigned)drive->sectors);
161
Paolo Bonzinicb721712012-03-05 12:29:12 +0100162 // We do not recover from USB stalls, so try to be safe and avoid
163 // sending the command if the (obsolete, but still provided by QEMU)
164 // fixed disk geometry page may not be supported.
165 //
166 // We could also send the command only to small disks (e.g. <504MiB)
167 // but some old USB keys only support a very small subset of SCSI which
168 // does not even include the MODE SENSE command!
169 //
Kevin O'Connor897fb112013-02-07 23:32:48 -0500170 if (CONFIG_QEMU_HARDWARE && memcmp(vendor, "QEMU", 5) == 0) {
Paolo Bonzinicb721712012-03-05 12:29:12 +0100171 struct cdbres_mode_sense_geom geomdata;
172 ret = cdb_mode_sense_geom(&dop, &geomdata);
173 if (ret == 0) {
174 u32 cylinders;
175 cylinders = geomdata.cyl[0] << 16;
176 cylinders |= geomdata.cyl[1] << 8;
177 cylinders |= geomdata.cyl[2];
178 if (cylinders && geomdata.heads &&
179 drive->sectors <= 0xFFFFFFFFULL &&
180 ((u32)drive->sectors % (geomdata.heads * cylinders) == 0)) {
181 drive->pchs.cylinders = cylinders;
182 drive->pchs.heads = geomdata.heads;
183 drive->pchs.spt = (u32)drive->sectors / (geomdata.heads * cylinders);
184 }
Paolo Bonzini000e0842011-11-16 13:02:54 +0100185 }
186 }
187
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500188 char *desc = znprintf(MAXDESCSIZE, "%s Drive %s %s %s"
189 , s, vendor, product, rev);
190 boot_add_hd(drive, desc, prio);
Paolo Bonzinided04a32011-11-17 10:23:02 +0100191 return 0;
192}
193
Paolo Bonzini8c976e32011-11-16 13:02:51 +0100194int
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500195cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data)
196{
197 struct cdb_request_sense cmd;
198 memset(&cmd, 0, sizeof(cmd));
199 cmd.command = CDB_CMD_INQUIRY;
200 cmd.length = sizeof(*data);
201 op->count = 1;
202 op->buf_fl = data;
203 return cdb_cmd_data(op, &cmd, sizeof(*data));
204}
205
Kevin O'Connor76977b22010-02-17 01:01:32 -0500206// Request SENSE
207int
208cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data)
209{
210 struct cdb_request_sense cmd;
211 memset(&cmd, 0, sizeof(cmd));
212 cmd.command = CDB_CMD_REQUEST_SENSE;
213 cmd.length = sizeof(*data);
214 op->count = 1;
215 op->buf_fl = data;
216 return cdb_cmd_data(op, &cmd, sizeof(*data));
217}
218
Paolo Bonzini00823742011-11-16 13:02:42 +0100219// Test unit ready
220int
221cdb_test_unit_ready(struct disk_op_s *op)
222{
223 struct cdb_request_sense cmd;
224 memset(&cmd, 0, sizeof(cmd));
225 cmd.command = CDB_CMD_TEST_UNIT_READY;
226 op->count = 0;
227 op->buf_fl = NULL;
228 return cdb_cmd_data(op, &cmd, 0);
229}
230
Kevin O'Connor76977b22010-02-17 01:01:32 -0500231// Request capacity
232int
233cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data)
234{
235 struct cdb_read_capacity cmd;
236 memset(&cmd, 0, sizeof(cmd));
237 cmd.command = CDB_CMD_READ_CAPACITY;
238 op->count = 1;
239 op->buf_fl = data;
240 return cdb_cmd_data(op, &cmd, sizeof(*data));
241}
242
Paolo Bonzini000e0842011-11-16 13:02:54 +0100243// Mode sense, geometry page.
244int
245cdb_mode_sense_geom(struct disk_op_s *op, struct cdbres_mode_sense_geom *data)
246{
247 struct cdb_mode_sense cmd;
248 memset(&cmd, 0, sizeof(cmd));
249 cmd.command = CDB_CMD_MODE_SENSE;
250 cmd.flags = 8; /* DBD */
251 cmd.page = MODE_PAGE_HD_GEOMETRY;
Kevin O'Connorb3064592012-08-14 21:20:10 -0400252 cmd.count = cpu_to_be16(sizeof(*data));
Paolo Bonzini000e0842011-11-16 13:02:54 +0100253 op->count = 1;
254 op->buf_fl = data;
255 return cdb_cmd_data(op, &cmd, sizeof(*data));
256}
257
Kevin O'Connor76977b22010-02-17 01:01:32 -0500258// Read sectors.
259int
260cdb_read(struct disk_op_s *op)
261{
262 struct cdb_rwdata_10 cmd;
263 memset(&cmd, 0, sizeof(cmd));
264 cmd.command = CDB_CMD_READ_10;
Kevin O'Connorb3064592012-08-14 21:20:10 -0400265 cmd.lba = cpu_to_be32(op->lba);
266 cmd.count = cpu_to_be16(op->count);
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500267 return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize));
Kevin O'Connor76977b22010-02-17 01:01:32 -0500268}
Paolo Bonziniddb8ceb2011-11-16 13:02:47 +0100269
270// Write sectors.
271int
272cdb_write(struct disk_op_s *op)
273{
274 struct cdb_rwdata_10 cmd;
275 memset(&cmd, 0, sizeof(cmd));
276 cmd.command = CDB_CMD_WRITE_10;
Kevin O'Connorb3064592012-08-14 21:20:10 -0400277 cmd.lba = cpu_to_be32(op->lba);
278 cmd.count = cpu_to_be16(op->count);
Paolo Bonziniddb8ceb2011-11-16 13:02:47 +0100279 return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize));
280}