blob: 6f79cc59c30735aa3be40f85332dfab12c3621c7 [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
8#include "biosvar.h" // GET_GLOBAL
Kevin O'Connorb3064592012-08-14 21:20:10 -04009#include "util.h" // dprintf
10#include "byteorder.h" // be32_to_cpu
Kevin O'Connor76977b22010-02-17 01:01:32 -050011#include "disk.h" // struct disk_op_s
12#include "blockcmd.h" // struct cdb_request_sense
13#include "ata.h" // atapi_cmd_data
Gerd Hoffmannd52fdf62010-11-29 09:42:13 +010014#include "ahci.h" // atapi_cmd_data
Kevin O'Connor7149fc82010-02-17 23:24:42 -050015#include "usb-msc.h" // usb_cmd_data
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +020016#include "usb-uas.h" // usb_cmd_data
Paolo Bonzinic5c488f2012-02-27 17:22:23 +010017#include "virtio-scsi.h" // virtio_scsi_cmd_data
Gerd Hoffmann9d6bac12012-07-20 10:59:25 +020018#include "lsi-scsi.h" // lsi_scsi_cmd_data
Paolo Bonzini7a39e722012-08-06 13:15:06 +020019#include "esp-scsi.h" // esp_scsi_cmd_data
Hannes Reinecke2df70bf2012-11-13 15:03:31 +010020#include "megasas.h" // megasas_cmd_data
Kevin O'Connor0fedfab2012-03-06 07:18:07 -050021#include "boot.h" // boot_add_hd
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040022#include "string.h" // memset
Kevin O'Connor76977b22010-02-17 01:01:32 -050023
Kevin O'Connor7149fc82010-02-17 23:24:42 -050024// Route command to low-level handler.
Kevin O'Connor76977b22010-02-17 01:01:32 -050025static int
26cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
27{
28 u8 type = GET_GLOBAL(op->drive_g->type);
29 switch (type) {
Kevin O'Connorbd6afe52012-07-21 12:01:12 -040030 case DTYPE_ATA_ATAPI:
Kevin O'Connor76977b22010-02-17 01:01:32 -050031 return atapi_cmd_data(op, cdbcmd, blocksize);
Kevin O'Connor7149fc82010-02-17 23:24:42 -050032 case DTYPE_USB:
33 return usb_cmd_data(op, cdbcmd, blocksize);
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +020034 case DTYPE_UAS:
35 return uas_cmd_data(op, cdbcmd, blocksize);
Kevin O'Connorbd6afe52012-07-21 12:01:12 -040036 case DTYPE_AHCI_ATAPI:
Gerd Hoffmannd52fdf62010-11-29 09:42:13 +010037 return ahci_cmd_data(op, cdbcmd, blocksize);
Paolo Bonzinic5c488f2012-02-27 17:22:23 +010038 case DTYPE_VIRTIO_SCSI:
39 return virtio_scsi_cmd_data(op, cdbcmd, blocksize);
Gerd Hoffmann9d6bac12012-07-20 10:59:25 +020040 case DTYPE_LSI_SCSI:
41 return lsi_scsi_cmd_data(op, cdbcmd, blocksize);
Paolo Bonzini7a39e722012-08-06 13:15:06 +020042 case DTYPE_ESP_SCSI:
43 return esp_scsi_cmd_data(op, cdbcmd, blocksize);
Hannes Reinecke2df70bf2012-11-13 15:03:31 +010044 case DTYPE_MEGASAS:
45 return megasas_cmd_data(op, cdbcmd, blocksize);
Kevin O'Connor76977b22010-02-17 01:01:32 -050046 default:
47 op->count = 0;
48 return DISK_RET_EPARAM;
49 }
50}
51
Kevin O'Connor1fd9a892012-03-14 21:27:45 -040052// Determine if the command is a request to pull data from the device
53int
54cdb_is_read(u8 *cdbcmd, u16 blocksize)
55{
56 return blocksize && cdbcmd[0] != CDB_CMD_WRITE_10;
57}
58
Kevin O'Connor7149fc82010-02-17 23:24:42 -050059int
Paolo Bonzini8c976e32011-11-16 13:02:51 +010060scsi_is_ready(struct disk_op_s *op)
61{
62 dprintf(6, "scsi_is_ready (drive=%p)\n", op->drive_g);
63
64 /* Retry TEST UNIT READY for 5 seconds unless MEDIUM NOT PRESENT is
65 * reported by the device. If the device reports "IN PROGRESS",
66 * 30 seconds is added. */
67 int in_progress = 0;
Kevin O'Connor018bdd72013-07-20 18:22:57 -040068 u32 end = timer_calc(5000);
Paolo Bonzini8c976e32011-11-16 13:02:51 +010069 for (;;) {
Kevin O'Connor018bdd72013-07-20 18:22:57 -040070 if (timer_check(end)) {
Paolo Bonzini8c976e32011-11-16 13:02:51 +010071 dprintf(1, "test unit ready failed\n");
72 return -1;
73 }
74
75 int ret = cdb_test_unit_ready(op);
76 if (!ret)
77 // Success
78 break;
79
80 struct cdbres_request_sense sense;
81 ret = cdb_get_sense(op, &sense);
82 if (ret)
83 // Error - retry.
84 continue;
85
86 // Sense succeeded.
87 if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */
88 dprintf(1, "Device reports MEDIUM NOT PRESENT\n");
89 return -1;
90 }
91
92 if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) {
93 /* IN PROGRESS OF BECOMING READY */
94 printf("Waiting for device to detect medium... ");
95 /* Allow 30 seconds more */
Kevin O'Connor018bdd72013-07-20 18:22:57 -040096 end = timer_calc(30000);
Paolo Bonzini8c976e32011-11-16 13:02:51 +010097 in_progress = 1;
98 }
99 }
100 return 0;
101}
102
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500103// Validate drive, find block size / sector count, and register drive.
Paolo Bonzinided04a32011-11-17 10:23:02 +0100104int
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500105scsi_drive_setup(struct drive_s *drive, const char *s, int prio)
Paolo Bonzinided04a32011-11-17 10:23:02 +0100106{
Paolo Bonzinided04a32011-11-17 10:23:02 +0100107 struct disk_op_s dop;
108 memset(&dop, 0, sizeof(dop));
109 dop.drive_g = drive;
110 struct cdbres_inquiry data;
111 int ret = cdb_get_inquiry(&dop, &data);
112 if (ret)
113 return ret;
114 char vendor[sizeof(data.vendor)+1], product[sizeof(data.product)+1];
115 char rev[sizeof(data.rev)+1];
116 strtcpy(vendor, data.vendor, sizeof(vendor));
117 nullTrailingSpace(vendor);
118 strtcpy(product, data.product, sizeof(product));
119 nullTrailingSpace(product);
120 strtcpy(rev, data.rev, sizeof(rev));
121 nullTrailingSpace(rev);
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500122 int pdt = data.pdt & 0x1f;
Paolo Bonzinided04a32011-11-17 10:23:02 +0100123 int removable = !!(data.removable & 0x80);
124 dprintf(1, "%s vendor='%s' product='%s' rev='%s' type=%d removable=%d\n"
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500125 , s, vendor, product, rev, pdt, removable);
Paolo Bonzinided04a32011-11-17 10:23:02 +0100126 drive->removable = removable;
127
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500128 if (pdt == SCSI_TYPE_CDROM) {
Paolo Bonzinided04a32011-11-17 10:23:02 +0100129 drive->blksize = CDROM_SECTOR_SIZE;
130 drive->sectors = (u64)-1;
131
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500132 char *desc = znprintf(MAXDESCSIZE, "DVD/CD [%s Drive %s %s %s]"
Paolo Bonzinided04a32011-11-17 10:23:02 +0100133 , s, vendor, product, rev);
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500134 boot_add_cd(drive, desc, prio);
Paolo Bonzinided04a32011-11-17 10:23:02 +0100135 return 0;
136 }
137
138 ret = scsi_is_ready(&dop);
139 if (ret) {
140 dprintf(1, "scsi_is_ready returned %d\n", ret);
141 return ret;
142 }
143
144 struct cdbres_read_capacity capdata;
145 ret = cdb_read_capacity(&dop, &capdata);
146 if (ret)
147 return ret;
148
149 // READ CAPACITY returns the address of the last block.
150 // We do not bother with READ CAPACITY(16) because BIOS does not support
151 // 64-bit LBA anyway.
Kevin O'Connorb3064592012-08-14 21:20:10 -0400152 drive->blksize = be32_to_cpu(capdata.blksize);
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500153 if (drive->blksize != DISK_SECTOR_SIZE) {
154 dprintf(1, "%s: unsupported block size %d\n", s, drive->blksize);
155 return -1;
156 }
Kevin O'Connorb3064592012-08-14 21:20:10 -0400157 drive->sectors = (u64)be32_to_cpu(capdata.sectors) + 1;
Paolo Bonzinided04a32011-11-17 10:23:02 +0100158 dprintf(1, "%s blksize=%d sectors=%d\n"
159 , s, drive->blksize, (unsigned)drive->sectors);
160
Paolo Bonzinicb721712012-03-05 12:29:12 +0100161 // We do not recover from USB stalls, so try to be safe and avoid
162 // sending the command if the (obsolete, but still provided by QEMU)
163 // fixed disk geometry page may not be supported.
164 //
165 // We could also send the command only to small disks (e.g. <504MiB)
166 // but some old USB keys only support a very small subset of SCSI which
167 // does not even include the MODE SENSE command!
168 //
Kevin O'Connor897fb112013-02-07 23:32:48 -0500169 if (CONFIG_QEMU_HARDWARE && memcmp(vendor, "QEMU", 5) == 0) {
Paolo Bonzinicb721712012-03-05 12:29:12 +0100170 struct cdbres_mode_sense_geom geomdata;
171 ret = cdb_mode_sense_geom(&dop, &geomdata);
172 if (ret == 0) {
173 u32 cylinders;
174 cylinders = geomdata.cyl[0] << 16;
175 cylinders |= geomdata.cyl[1] << 8;
176 cylinders |= geomdata.cyl[2];
177 if (cylinders && geomdata.heads &&
178 drive->sectors <= 0xFFFFFFFFULL &&
179 ((u32)drive->sectors % (geomdata.heads * cylinders) == 0)) {
180 drive->pchs.cylinders = cylinders;
181 drive->pchs.heads = geomdata.heads;
182 drive->pchs.spt = (u32)drive->sectors / (geomdata.heads * cylinders);
183 }
Paolo Bonzini000e0842011-11-16 13:02:54 +0100184 }
185 }
186
Kevin O'Connor279dcb12012-02-18 11:02:27 -0500187 char *desc = znprintf(MAXDESCSIZE, "%s Drive %s %s %s"
188 , s, vendor, product, rev);
189 boot_add_hd(drive, desc, prio);
Paolo Bonzinided04a32011-11-17 10:23:02 +0100190 return 0;
191}
192
Paolo Bonzini8c976e32011-11-16 13:02:51 +0100193int
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500194cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data)
195{
196 struct cdb_request_sense cmd;
197 memset(&cmd, 0, sizeof(cmd));
198 cmd.command = CDB_CMD_INQUIRY;
199 cmd.length = sizeof(*data);
200 op->count = 1;
201 op->buf_fl = data;
202 return cdb_cmd_data(op, &cmd, sizeof(*data));
203}
204
Kevin O'Connor76977b22010-02-17 01:01:32 -0500205// Request SENSE
206int
207cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data)
208{
209 struct cdb_request_sense cmd;
210 memset(&cmd, 0, sizeof(cmd));
211 cmd.command = CDB_CMD_REQUEST_SENSE;
212 cmd.length = sizeof(*data);
213 op->count = 1;
214 op->buf_fl = data;
215 return cdb_cmd_data(op, &cmd, sizeof(*data));
216}
217
Paolo Bonzini00823742011-11-16 13:02:42 +0100218// Test unit ready
219int
220cdb_test_unit_ready(struct disk_op_s *op)
221{
222 struct cdb_request_sense cmd;
223 memset(&cmd, 0, sizeof(cmd));
224 cmd.command = CDB_CMD_TEST_UNIT_READY;
225 op->count = 0;
226 op->buf_fl = NULL;
227 return cdb_cmd_data(op, &cmd, 0);
228}
229
Kevin O'Connor76977b22010-02-17 01:01:32 -0500230// Request capacity
231int
232cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data)
233{
234 struct cdb_read_capacity cmd;
235 memset(&cmd, 0, sizeof(cmd));
236 cmd.command = CDB_CMD_READ_CAPACITY;
237 op->count = 1;
238 op->buf_fl = data;
239 return cdb_cmd_data(op, &cmd, sizeof(*data));
240}
241
Paolo Bonzini000e0842011-11-16 13:02:54 +0100242// Mode sense, geometry page.
243int
244cdb_mode_sense_geom(struct disk_op_s *op, struct cdbres_mode_sense_geom *data)
245{
246 struct cdb_mode_sense cmd;
247 memset(&cmd, 0, sizeof(cmd));
248 cmd.command = CDB_CMD_MODE_SENSE;
249 cmd.flags = 8; /* DBD */
250 cmd.page = MODE_PAGE_HD_GEOMETRY;
Kevin O'Connorb3064592012-08-14 21:20:10 -0400251 cmd.count = cpu_to_be16(sizeof(*data));
Paolo Bonzini000e0842011-11-16 13:02:54 +0100252 op->count = 1;
253 op->buf_fl = data;
254 return cdb_cmd_data(op, &cmd, sizeof(*data));
255}
256
Kevin O'Connor76977b22010-02-17 01:01:32 -0500257// Read sectors.
258int
259cdb_read(struct disk_op_s *op)
260{
261 struct cdb_rwdata_10 cmd;
262 memset(&cmd, 0, sizeof(cmd));
263 cmd.command = CDB_CMD_READ_10;
Kevin O'Connorb3064592012-08-14 21:20:10 -0400264 cmd.lba = cpu_to_be32(op->lba);
265 cmd.count = cpu_to_be16(op->count);
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500266 return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize));
Kevin O'Connor76977b22010-02-17 01:01:32 -0500267}
Paolo Bonziniddb8ceb2011-11-16 13:02:47 +0100268
269// Write sectors.
270int
271cdb_write(struct disk_op_s *op)
272{
273 struct cdb_rwdata_10 cmd;
274 memset(&cmd, 0, sizeof(cmd));
275 cmd.command = CDB_CMD_WRITE_10;
Kevin O'Connorb3064592012-08-14 21:20:10 -0400276 cmd.lba = cpu_to_be32(op->lba);
277 cmd.count = cpu_to_be16(op->count);
Paolo Bonziniddb8ceb2011-11-16 13:02:47 +0100278 return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize));
279}