File: | src/usr.sbin/vmd/vioscsi.c |
Warning: | line 273, column 2 Value stored to 'inq_len' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: vioscsi.c,v 1.19 2021/06/16 16:55:02 dv Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2017 Carlos Cardenas <ccardenas@openbsd.org> |
5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. |
9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ |
18 | |
19 | #include <sys/types.h> |
20 | |
21 | #include <dev/pci/virtio_pcireg.h> |
22 | #include <dev/pv/vioscsireg.h> |
23 | #include <scsi/scsi_all.h> |
24 | #include <scsi/scsi_disk.h> |
25 | #include <scsi/scsiconf.h> |
26 | #include <scsi/cd.h> |
27 | |
28 | #include <errno(*__errno()).h> |
29 | #include <stdlib.h> |
30 | #include <string.h> |
31 | #include <unistd.h> |
32 | |
33 | #include "vmd.h" |
34 | #include "vioscsi.h" |
35 | #include "virtio.h" |
36 | |
37 | extern char *__progname; |
38 | |
39 | static void |
40 | vioscsi_prepare_resp(struct virtio_scsi_res_hdr *resp, uint8_t vio_status, |
41 | uint8_t scsi_status, uint8_t err_flags, uint8_t add_sense_code, |
42 | uint8_t add_sense_code_qual) |
43 | { |
44 | /* Set lower 8 bits of status and response fields */ |
45 | resp->response &= 0xFFFFFF00; |
46 | resp->response |= vio_status; |
47 | resp->status &= 0xFFFFFF00; |
48 | resp->status |= scsi_status; |
49 | |
50 | resp->sense_len = 0; |
51 | |
52 | /* determine if we need to populate the sense field */ |
53 | if (scsi_status == SCSI_CHECK0x02) { |
54 | /* |
55 | * sense data is a 96 byte field. |
56 | * We only need to use the first 14 bytes |
57 | * - set the sense_len accordingly |
58 | * - set error_code to Current Command |
59 | * ref scsi/scsi_all.h:struct scsi_sense_data |
60 | */ |
61 | memset(resp->sense, 0, VIOSCSI_SENSE_LEN96); |
62 | resp->sense_len = RESP_SENSE_LEN14; |
63 | resp->sense[0] = SSD_ERRCODE_CURRENT0x70; |
64 | resp->sense[2] = err_flags; |
65 | resp->sense[12] = add_sense_code; |
66 | resp->sense[13] = add_sense_code_qual; |
67 | } |
68 | } |
69 | |
70 | static struct vring_desc* |
71 | vioscsi_next_ring_desc(struct vring_desc* desc, struct vring_desc* cur, |
72 | uint16_t *idx) |
73 | { |
74 | *idx = cur->next & VIOSCSI_QUEUE_MASK(128 - 1); |
75 | return &desc[*idx]; |
76 | } |
77 | |
78 | static void |
79 | vioscsi_next_ring_item(struct vioscsi_dev *dev, struct vring_avail *avail, |
80 | struct vring_used *used, struct vring_desc *desc, uint16_t idx) |
81 | { |
82 | used->ring[used->idx & VIOSCSI_QUEUE_MASK(128 - 1)].id = idx; |
83 | used->ring[used->idx & VIOSCSI_QUEUE_MASK(128 - 1)].len = desc->len; |
84 | used->idx++; |
85 | |
86 | dev->vq[dev->cfg.queue_notify].last_avail = |
87 | avail->idx & VIOSCSI_QUEUE_MASK(128 - 1); |
88 | } |
89 | |
90 | static const char * |
91 | vioscsi_op_names(uint8_t type) |
92 | { |
93 | switch (type) { |
94 | /* defined in scsi_all.h */ |
95 | case TEST_UNIT_READY0x00: return "TEST_UNIT_READY"; |
96 | case REQUEST_SENSE0x03: return "REQUEST_SENSE"; |
97 | case INQUIRY0x12: return "INQUIRY"; |
98 | case MODE_SELECT0x15: return "MODE_SELECT"; |
99 | case RESERVE0x16: return "RESERVE"; |
100 | case RELEASE0x17: return "RELEASE"; |
101 | case MODE_SENSE0x1a: return "MODE_SENSE"; |
102 | case START_STOP0x1b: return "START_STOP"; |
103 | case RECEIVE_DIAGNOSTIC0x1c: return "RECEIVE_DIAGNOSTIC"; |
104 | case SEND_DIAGNOSTIC0x1d: return "SEND_DIAGNOSTIC"; |
105 | case PREVENT_ALLOW0x1e: return "PREVENT_ALLOW"; |
106 | case POSITION_TO_ELEMENT0x2b: return "POSITION_TO_ELEMENT"; |
107 | case WRITE_BUFFER0x3b: return "WRITE_BUFFER"; |
108 | case READ_BUFFER0x3c: return "READ_BUFFER"; |
109 | case CHANGE_DEFINITION0x40: return "CHANGE_DEFINITION"; |
110 | case MODE_SELECT_BIG0x55: return "MODE_SELECT_BIG"; |
111 | case MODE_SENSE_BIG0x5a: return "MODE_SENSE_BIG"; |
112 | case REPORT_LUNS0xa0: return "REPORT_LUNS"; |
113 | /* defined in scsi_disk.h */ |
114 | case REASSIGN_BLOCKS0x07: return "REASSIGN_BLOCKS"; |
115 | case READ_COMMAND0x08: return "READ_COMMAND"; |
116 | case WRITE_COMMAND0x0a: return "WRITE_COMMAND"; |
117 | case READ_CAPACITY0x25: return "READ_CAPACITY"; |
118 | case READ_CAPACITY_160x9e: return "READ_CAPACITY_16"; |
119 | case READ_100x28: return "READ_10"; |
120 | case WRITE_100x2a: return "WRITE_10"; |
121 | case READ_120xa8: return "READ_12"; |
122 | case WRITE_120xaa: return "WRITE_12"; |
123 | case READ_160x88: return "READ_16"; |
124 | case WRITE_160x8a: return "WRITE_16"; |
125 | case SYNCHRONIZE_CACHE0x35: return "SYNCHRONIZE_CACHE"; |
126 | case WRITE_SAME_100x41: return "WRITE_SAME_10"; |
127 | case WRITE_SAME_160x93: return "WRITE_SAME_16"; |
128 | /* defined in cd.h */ |
129 | case READ_SUBCHANNEL0x42: return "READ_SUBCHANNEL"; |
130 | case READ_TOC0x43: return "READ_TOC"; |
131 | case READ_HEADER0x44: return "READ_HEADER"; |
132 | case PLAY0x45: return "PLAY"; |
133 | case PLAY_MSF0x47: return "PLAY_MSF"; |
134 | case PLAY_TRACK0x48: return "PLAY_TRACK"; |
135 | case PLAY_TRACK_REL0x49: return "PLAY_TRACK_REL"; |
136 | case PAUSE0x4b: return "PAUSE"; |
137 | case READ_TRACK_INFO0x52: return "READ_TRACK_INFO"; |
138 | case CLOSE_TRACK0x5b: return "CLOSE_TRACK"; |
139 | case BLANK0xa1: return "BLANK"; |
140 | case PLAY_BIG0xa5: return "PLAY_BIG"; |
141 | case LOAD_UNLOAD0xa6: return "LOAD_UNLOAD"; |
142 | case PLAY_TRACK_REL_BIG0xa9: return "PLAY_TRACK_REL_BIG"; |
143 | case SET_CD_SPEED0xbb: return "SET_CD_SPEED"; |
144 | /* defined locally */ |
145 | case READ_DISC_INFORMATION0x51: return "READ_DISC_INFORMATION"; |
146 | case GET_CONFIGURATION0x46: return "GET_CONFIGURATION"; |
147 | case MECHANISM_STATUS0xbd: return "MECHANISM_STATUS"; |
148 | case GET_EVENT_STATUS_NOTIFICATION0x4a: |
149 | return "GET_EVENT_STATUS_NOTIFICATION"; |
150 | default: return "UNKNOWN"; |
151 | } |
152 | } |
153 | |
154 | static const char * |
155 | vioscsi_reg_name(uint8_t reg) |
156 | { |
157 | switch (reg) { |
158 | case VIRTIO_CONFIG_DEVICE_FEATURES0: return "device feature"; |
159 | case VIRTIO_CONFIG_GUEST_FEATURES4: return "guest feature"; |
160 | case VIRTIO_CONFIG_QUEUE_ADDRESS8: return "queue address"; |
161 | case VIRTIO_CONFIG_QUEUE_SIZE12: return "queue size"; |
162 | case VIRTIO_CONFIG_QUEUE_SELECT14: return "queue select"; |
163 | case VIRTIO_CONFIG_QUEUE_NOTIFY16: return "queue notify"; |
164 | case VIRTIO_CONFIG_DEVICE_STATUS18: return "device status"; |
165 | case VIRTIO_CONFIG_ISR_STATUS19: return "isr status"; |
166 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20: return "num_queues"; |
167 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 4: return "seg_max"; |
168 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 8: return "max_sectors"; |
169 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 12: return "cmd_per_lun"; |
170 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 16: return "event_info_size"; |
171 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 20: return "sense_size"; |
172 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 24: return "cdb_size"; |
173 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 28: return "max_channel"; |
174 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 30: return "max_target"; |
175 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 32: return "max_lun"; |
176 | default: return "unknown"; |
177 | } |
178 | } |
179 | |
180 | static void |
181 | vioscsi_free_info(struct ioinfo *info) |
182 | { |
183 | if (!info) |
184 | return; |
185 | free(info->buf); |
186 | free(info); |
187 | } |
188 | |
189 | static struct ioinfo * |
190 | vioscsi_start_read(struct vioscsi_dev *dev, off_t block, size_t n_blocks) |
191 | { |
192 | struct ioinfo *info; |
193 | |
194 | /* Limit to 64M for now */ |
195 | if (n_blocks * VIOSCSI_BLOCK_SIZE_CDROM2048 > (1 << 26)) { |
196 | log_warnx("%s: read size exceeded 64M", __func__); |
197 | return (NULL((void *)0)); |
198 | } |
199 | |
200 | info = calloc(1, sizeof(*info)); |
201 | if (!info) |
202 | goto nomem; |
203 | info->buf = malloc(n_blocks * VIOSCSI_BLOCK_SIZE_CDROM2048); |
204 | if (info->buf == NULL((void *)0)) |
205 | goto nomem; |
206 | info->len = n_blocks * VIOSCSI_BLOCK_SIZE_CDROM2048; |
207 | info->offset = block * VIOSCSI_BLOCK_SIZE_CDROM2048; |
208 | info->file = &dev->file; |
209 | |
210 | return info; |
211 | |
212 | nomem: |
213 | free(info); |
214 | log_warn("malloc error vioscsi read"); |
215 | return (NULL((void *)0)); |
216 | } |
217 | |
218 | static const uint8_t * |
219 | vioscsi_finish_read(struct ioinfo *info) |
220 | { |
221 | struct virtio_backing *f; |
222 | |
223 | f = info->file; |
224 | if (f->pread(f->p, info->buf, info->len, info->offset) != info->len) { |
225 | info->error = errno(*__errno()); |
226 | log_warn("vioscsi read error"); |
227 | return NULL((void *)0); |
228 | } |
229 | |
230 | return info->buf; |
231 | } |
232 | |
233 | static int |
234 | vioscsi_handle_tur(struct vioscsi_dev *dev, struct virtio_scsi_req_hdr *req, |
235 | struct virtio_vq_acct *acct) |
236 | { |
237 | int ret = 0; |
238 | struct virtio_scsi_res_hdr resp; |
239 | |
240 | memset(&resp, 0, sizeof(resp)); |
241 | /* Move index for response */ |
242 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->req_desc, |
243 | &(acct->resp_idx)); |
244 | |
245 | vioscsi_prepare_resp(&resp, VIRTIO_SCSI_S_OK0, SCSI_OK0x00, 0, 0, 0); |
246 | |
247 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
248 | log_warnx("%s: unable to write OK resp status data @ 0x%llx", |
249 | __func__, acct->resp_desc->addr); |
250 | } else { |
251 | ret = 1; |
252 | dev->cfg.isr_status = 1; |
253 | /* Move ring indexes */ |
254 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
255 | acct->req_desc, acct->req_idx); |
256 | } |
257 | |
258 | return (ret); |
259 | } |
260 | |
261 | static int |
262 | vioscsi_handle_inquiry(struct vioscsi_dev *dev, |
263 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
264 | { |
265 | int ret = 0; |
266 | struct virtio_scsi_res_hdr resp; |
267 | uint16_t inq_len; |
268 | struct scsi_inquiry *inq; |
269 | struct scsi_inquiry_data *inq_data; |
270 | |
271 | memset(&resp, 0, sizeof(resp)); |
272 | inq = (struct scsi_inquiry *)(req->cdb); |
273 | inq_len = (uint16_t)_2btol(inq->length); |
Value stored to 'inq_len' is never read | |
274 | |
275 | DPRINTF("%s: INQ - EVPD %d PAGE_CODE 0x%08x LEN %d", __func__,do {} while(0) |
276 | inq->flags & SI_EVPD, inq->pagecode, inq_len)do {} while(0); |
277 | |
278 | vioscsi_prepare_resp(&resp, |
279 | VIRTIO_SCSI_S_OK0, SCSI_OK0x00, 0, 0, 0); |
280 | |
281 | inq_data = calloc(1, sizeof(struct scsi_inquiry_data)); |
282 | |
283 | if (inq_data == NULL((void *)0)) { |
284 | log_warnx("%s: cannot alloc inq_data", __func__); |
285 | goto inq_out; |
286 | } |
287 | |
288 | inq_data->device = T_CDROM0x05; |
289 | inq_data->dev_qual2 = SID_REMOVABLE0x80; |
290 | /* Leave version zero to say we don't comply */ |
291 | inq_data->response_format = SID_SCSI2_RESPONSE0x02; |
292 | inq_data->additional_length = SID_SCSI2_ALEN31; |
293 | memcpy(inq_data->vendor, INQUIRY_VENDOR"OpenBSD ", INQUIRY_VENDOR_LEN8); |
294 | memcpy(inq_data->product, INQUIRY_PRODUCT"VMM CD-ROM ", INQUIRY_PRODUCT_LEN16); |
295 | memcpy(inq_data->revision, INQUIRY_REVISION"001 ", INQUIRY_REVISION_LEN4); |
296 | |
297 | /* Move index for response */ |
298 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->req_desc, |
299 | &(acct->resp_idx)); |
300 | |
301 | DPRINTF("%s: writing resp to 0x%llx size %d at local "do {} while(0) |
302 | "idx %d req_idx %d global_idx %d", __func__, acct->resp_desc->addr,do {} while(0) |
303 | acct->resp_desc->len, acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
304 | |
305 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
306 | log_warnx("%s: unable to write OK resp status data @ 0x%llx", |
307 | __func__, acct->resp_desc->addr); |
308 | goto free_inq; |
309 | } |
310 | |
311 | /* Move index for inquiry_data */ |
312 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->resp_desc, |
313 | &(acct->resp_idx)); |
314 | |
315 | DPRINTF("%s: writing inq_data to 0x%llx size %d at "do {} while(0) |
316 | "local idx %d req_idx %d global_idx %d",do {} while(0) |
317 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
318 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
319 | |
320 | if (write_mem(acct->resp_desc->addr, inq_data, |
321 | sizeof(struct scsi_inquiry_data))) { |
322 | log_warnx("%s: unable to write inquiry" |
323 | " response to gpa @ 0x%llx", |
324 | __func__, acct->resp_desc->addr); |
325 | } else { |
326 | ret = 1; |
327 | dev->cfg.isr_status = 1; |
328 | /* Move ring indexes */ |
329 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
330 | acct->req_desc, acct->req_idx); |
331 | } |
332 | |
333 | free_inq: |
334 | free(inq_data); |
335 | inq_out: |
336 | return (ret); |
337 | } |
338 | |
339 | static int |
340 | vioscsi_handle_mode_sense(struct vioscsi_dev *dev, |
341 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
342 | { |
343 | int ret = 0; |
344 | struct virtio_scsi_res_hdr resp; |
345 | uint8_t mode_page_ctl; |
346 | uint8_t mode_page_code; |
347 | uint8_t *mode_reply; |
348 | uint8_t mode_reply_len = 0; |
349 | struct scsi_mode_sense *mode_sense; |
350 | |
351 | memset(&resp, 0, sizeof(resp)); |
352 | mode_sense = (struct scsi_mode_sense *)(req->cdb); |
353 | mode_page_ctl = mode_sense->page & SMS_PAGE_CTRL0xC0; |
354 | mode_page_code = mode_sense->page & SMS_PAGE_CODE0x3F; |
355 | |
356 | DPRINTF("%s: M_SENSE - DBD %d Page Ctrl 0x%x Code 0x%x Len %u",do {} while(0) |
357 | __func__, mode_sense->byte2 & SMS_DBD, mode_page_ctl,do {} while(0) |
358 | mode_page_code, mode_sense->length)do {} while(0); |
359 | |
360 | if (mode_page_ctl == SMS_PAGE_CTRL_CURRENT0x00 && |
361 | (mode_page_code == ERR_RECOVERY_PAGE0x01 || |
362 | mode_page_code == CDVD_CAPABILITIES_PAGE0x2a)) { |
363 | /* |
364 | * mode sense header is 4 bytes followed |
365 | * by a variable page |
366 | * ERR_RECOVERY_PAGE is 12 bytes |
367 | * CDVD_CAPABILITIES_PAGE is 32 bytes |
368 | */ |
369 | switch (mode_page_code) { |
370 | case ERR_RECOVERY_PAGE0x01: |
371 | mode_reply_len = 16; |
372 | mode_reply = |
373 | (uint8_t*)calloc(mode_reply_len, sizeof(uint8_t)); |
374 | if (mode_reply == NULL((void *)0)) |
375 | goto mode_sense_out; |
376 | |
377 | /* set the page header */ |
378 | *mode_reply = mode_reply_len - 1; |
379 | *(mode_reply + 1) = MODE_MEDIUM_TYPE_CODE0x70; |
380 | |
381 | /* set the page data, 7.3.2.1 mmc-5 */ |
382 | *(mode_reply + 4) = MODE_ERR_RECOVERY_PAGE_CODE0x01; |
383 | *(mode_reply + 5) = MODE_ERR_RECOVERY_PAGE_LEN0x0a; |
384 | *(mode_reply + 7) = MODE_READ_RETRY_COUNT0x05; |
385 | break; |
386 | case CDVD_CAPABILITIES_PAGE0x2a: |
387 | mode_reply_len = 36; |
388 | mode_reply = |
389 | (uint8_t*)calloc(mode_reply_len, sizeof(uint8_t)); |
390 | if (mode_reply == NULL((void *)0)) |
391 | goto mode_sense_out; |
392 | |
393 | /* set the page header */ |
394 | *mode_reply = mode_reply_len - 1; |
395 | *(mode_reply + 1) = MODE_MEDIUM_TYPE_CODE0x70; |
396 | |
397 | /* set the page data, 6.3.11 mmc-3 */ |
398 | *(mode_reply + 4) = MODE_CDVD_CAP_PAGE_CODE0x2a; |
399 | *(mode_reply + 5) = mode_reply_len - 6; |
400 | *(mode_reply + 6) = MODE_CDVD_CAP_READ_CODE0x08; |
401 | _lto2b(MODE_CDVD_CAP_NUM_LEVELS0x02, mode_reply + 14); |
402 | break; |
403 | default: |
404 | goto mode_sense_error; |
405 | break; |
406 | } |
407 | |
408 | /* Move index for response */ |
409 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
410 | acct->req_desc, &(acct->resp_idx)); |
411 | |
412 | DPRINTF("%s: writing resp to 0x%llx size %d "do {} while(0) |
413 | "at local idx %d req_idx %d global_idx %d",do {} while(0) |
414 | __func__, acct->resp_desc->addr, mode_reply_len,do {} while(0) |
415 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
416 | |
417 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
418 | log_warnx("%s: unable to write OK" |
419 | " resp status data @ 0x%llx", |
420 | __func__, acct->resp_desc->addr); |
421 | free(mode_reply); |
422 | goto mode_sense_out; |
423 | } |
424 | |
425 | /* Move index for mode_reply */ |
426 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
427 | acct->resp_desc, &(acct->resp_idx)); |
428 | |
429 | DPRINTF("%s: writing mode_reply to 0x%llx "do {} while(0) |
430 | "size %d at local idx %d req_idx %d "do {} while(0) |
431 | "global_idx %d", __func__, acct->resp_desc->addr,do {} while(0) |
432 | mode_reply_len, acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
433 | |
434 | if (write_mem(acct->resp_desc->addr, mode_reply, |
435 | mode_reply_len)) { |
436 | log_warnx("%s: unable to write " |
437 | "mode_reply to gpa @ 0x%llx", |
438 | __func__, acct->resp_desc->addr); |
439 | free(mode_reply); |
440 | goto mode_sense_out; |
441 | } |
442 | |
443 | free(mode_reply); |
444 | |
445 | ret = 1; |
446 | dev->cfg.isr_status = 1; |
447 | /* Move ring indexes */ |
448 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
449 | acct->req_desc, acct->req_idx); |
450 | } else { |
451 | mode_sense_error: |
452 | /* send back un-supported */ |
453 | vioscsi_prepare_resp(&resp, |
454 | VIRTIO_SCSI_S_OK0, SCSI_CHECK0x02, SKEY_ILLEGAL_REQUEST0x05, |
455 | SENSE_ILLEGAL_CDB_FIELD0x24, SENSE_DEFAULT_ASCQ0x00); |
456 | |
457 | /* Move index for response */ |
458 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
459 | acct->req_desc, &(acct->resp_idx)); |
460 | |
461 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
462 | log_warnx("%s: unable to set ERR status data @ 0x%llx", |
463 | __func__, acct->resp_desc->addr); |
464 | goto mode_sense_out; |
465 | } |
466 | |
467 | ret = 1; |
468 | dev->cfg.isr_status = 1; |
469 | /* Move ring indexes */ |
470 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
471 | acct->req_desc, acct->req_idx); |
472 | } |
473 | mode_sense_out: |
474 | return (ret); |
475 | } |
476 | |
477 | static int |
478 | vioscsi_handle_mode_sense_big(struct vioscsi_dev *dev, |
479 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
480 | { |
481 | int ret = 0; |
482 | struct virtio_scsi_res_hdr resp; |
483 | uint8_t mode_page_ctl; |
484 | uint8_t mode_page_code; |
485 | uint8_t *mode_reply; |
486 | uint8_t mode_reply_len = 0; |
487 | uint16_t mode_sense_len; |
488 | struct scsi_mode_sense_big *mode_sense_10; |
489 | |
490 | memset(&resp, 0, sizeof(resp)); |
491 | mode_sense_10 = (struct scsi_mode_sense_big *)(req->cdb); |
492 | mode_page_ctl = mode_sense_10->page & SMS_PAGE_CTRL0xC0; |
493 | mode_page_code = mode_sense_10->page & SMS_PAGE_CODE0x3F; |
494 | mode_sense_len = (uint16_t)_2btol(mode_sense_10->length); |
495 | |
496 | DPRINTF("%s: M_SENSE_10 - DBD %d Page Ctrl 0x%x Code 0x%x Len %u",do {} while(0) |
497 | __func__, mode_sense_10->byte2 & SMS_DBD, mode_page_ctl,do {} while(0) |
498 | mode_page_code, mode_sense_len)do {} while(0); |
499 | |
500 | if (mode_page_ctl == SMS_PAGE_CTRL_CURRENT0x00 && |
501 | (mode_page_code == ERR_RECOVERY_PAGE0x01 || |
502 | mode_page_code == CDVD_CAPABILITIES_PAGE0x2a)) { |
503 | /* |
504 | * mode sense header is 8 bytes followed |
505 | * by a variable page |
506 | * ERR_RECOVERY_PAGE is 12 bytes |
507 | * CDVD_CAPABILITIES_PAGE is 32 bytes |
508 | */ |
509 | switch (mode_page_code) { |
510 | case ERR_RECOVERY_PAGE0x01: |
511 | mode_reply_len = 20; |
512 | mode_reply = |
513 | (uint8_t*)calloc(mode_reply_len, sizeof(uint8_t)); |
514 | if (mode_reply == NULL((void *)0)) |
515 | goto mode_sense_big_out; |
516 | |
517 | /* set the page header */ |
518 | _lto2b(mode_reply_len - 2, mode_reply); |
519 | *(mode_reply + 2) = MODE_MEDIUM_TYPE_CODE0x70; |
520 | |
521 | /* set the page data, 7.3.2.1 mmc-5 */ |
522 | *(mode_reply + 8) = MODE_ERR_RECOVERY_PAGE_CODE0x01; |
523 | *(mode_reply + 9) = MODE_ERR_RECOVERY_PAGE_LEN0x0a; |
524 | *(mode_reply + 11) = MODE_READ_RETRY_COUNT0x05; |
525 | break; |
526 | case CDVD_CAPABILITIES_PAGE0x2a: |
527 | mode_reply_len = 40; |
528 | mode_reply = |
529 | (uint8_t*)calloc(mode_reply_len, sizeof(uint8_t)); |
530 | if (mode_reply == NULL((void *)0)) |
531 | goto mode_sense_big_out; |
532 | |
533 | /* set the page header */ |
534 | _lto2b(mode_reply_len - 2, mode_reply); |
535 | *(mode_reply + 2) = MODE_MEDIUM_TYPE_CODE0x70; |
536 | |
537 | /* set the page data, 6.3.11 mmc-3 */ |
538 | *(mode_reply + 8) = MODE_CDVD_CAP_PAGE_CODE0x2a; |
539 | *(mode_reply + 9) = mode_reply_len - 6; |
540 | *(mode_reply + 10) = MODE_CDVD_CAP_READ_CODE0x08; |
541 | _lto2b(MODE_CDVD_CAP_NUM_LEVELS0x02, mode_reply + 18); |
542 | break; |
543 | default: |
544 | goto mode_sense_big_error; |
545 | break; |
546 | } |
547 | |
548 | /* Move index for response */ |
549 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
550 | acct->req_desc, &(acct->resp_idx)); |
551 | |
552 | DPRINTF("%s: writing resp to 0x%llx size %d "do {} while(0) |
553 | "at local idx %d req_idx %d global_idx %d",do {} while(0) |
554 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
555 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
556 | |
557 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
558 | log_warnx("%s: unable to write OK" |
559 | " resp status data @ 0x%llx", |
560 | __func__, acct->resp_desc->addr); |
561 | free(mode_reply); |
562 | goto mode_sense_big_out; |
563 | } |
564 | |
565 | /* Move index for mode_reply */ |
566 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
567 | acct->resp_desc, &(acct->resp_idx)); |
568 | |
569 | DPRINTF("%s: writing mode_reply to 0x%llx "do {} while(0) |
570 | "size %d at local idx %d req_idx %d global_idx %d",do {} while(0) |
571 | __func__, acct->resp_desc->addr, mode_reply_len,do {} while(0) |
572 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
573 | |
574 | if (write_mem(acct->resp_desc->addr, mode_reply, |
575 | mode_reply_len)) { |
576 | log_warnx("%s: unable to write " |
577 | "mode_reply to gpa @ 0x%llx", |
578 | __func__, acct->resp_desc->addr); |
579 | free(mode_reply); |
580 | goto mode_sense_big_out; |
581 | } |
582 | |
583 | free(mode_reply); |
584 | |
585 | ret = 1; |
586 | dev->cfg.isr_status = 1; |
587 | /* Move ring indexes */ |
588 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
589 | acct->req_desc, acct->req_idx); |
590 | } else { |
591 | mode_sense_big_error: |
592 | /* send back un-supported */ |
593 | vioscsi_prepare_resp(&resp, |
594 | VIRTIO_SCSI_S_OK0, SCSI_CHECK0x02, SKEY_ILLEGAL_REQUEST0x05, |
595 | SENSE_ILLEGAL_CDB_FIELD0x24, SENSE_DEFAULT_ASCQ0x00); |
596 | |
597 | /* Move index for response */ |
598 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
599 | acct->req_desc, &(acct->resp_idx)); |
600 | |
601 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
602 | log_warnx("%s: unable to set ERR status data @ 0x%llx", |
603 | __func__, acct->resp_desc->addr); |
604 | goto mode_sense_big_out; |
605 | } |
606 | |
607 | ret = 1; |
608 | dev->cfg.isr_status = 1; |
609 | /* Move ring indexes */ |
610 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
611 | acct->req_desc, acct->req_idx); |
612 | } |
613 | mode_sense_big_out: |
614 | return (ret); |
615 | } |
616 | |
617 | static int |
618 | vioscsi_handle_read_capacity(struct vioscsi_dev *dev, |
619 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
620 | { |
621 | int ret = 0; |
622 | struct virtio_scsi_res_hdr resp; |
623 | uint32_t r_cap_addr; |
624 | struct scsi_read_capacity *r_cap; |
625 | struct scsi_read_cap_data *r_cap_data; |
626 | |
627 | memset(&resp, 0, sizeof(resp)); |
628 | r_cap = (struct scsi_read_capacity *)(req->cdb); |
629 | r_cap_addr = _4btol(r_cap->addr); |
630 | DPRINTF("%s: %s - Addr 0x%08x", __func__,do {} while(0) |
631 | vioscsi_op_names(r_cap->opcode), r_cap_addr)do {} while(0); |
632 | |
633 | vioscsi_prepare_resp(&resp, |
634 | VIRTIO_SCSI_S_OK0, SCSI_OK0x00, 0, 0, 0); |
635 | |
636 | r_cap_data = calloc(1, sizeof(struct scsi_read_cap_data)); |
637 | |
638 | if (r_cap_data == NULL((void *)0)) { |
639 | log_warnx("%s: cannot alloc r_cap_data", __func__); |
640 | goto read_capacity_out; |
641 | } |
642 | |
643 | DPRINTF("%s: ISO has %lld bytes and %lld blocks",do {} while(0) |
644 | __func__, dev->sz, dev->n_blocks)do {} while(0); |
645 | |
646 | /* |
647 | * determine if num blocks of iso image > UINT32_MAX |
648 | * if it is, set addr to UINT32_MAX (0xffffffff) |
649 | * indicating to hosts that READ_CAPACITY_16 should |
650 | * be called to retrieve the full size |
651 | */ |
652 | if (dev->n_blocks >= UINT32_MAX0xffffffffU) { |
653 | _lto4b(UINT32_MAX0xffffffffU, r_cap_data->addr); |
654 | _lto4b(VIOSCSI_BLOCK_SIZE_CDROM2048, r_cap_data->length); |
655 | log_warnx("%s: ISO sz %lld is bigger than " |
656 | "UINT32_MAX %u, all data may not be read", |
657 | __func__, dev->sz, UINT32_MAX0xffffffffU); |
658 | } else { |
659 | _lto4b(dev->n_blocks - 1, r_cap_data->addr); |
660 | _lto4b(VIOSCSI_BLOCK_SIZE_CDROM2048, r_cap_data->length); |
661 | } |
662 | |
663 | /* Move index for response */ |
664 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->req_desc, |
665 | &(acct->resp_idx)); |
666 | |
667 | DPRINTF("%s: writing resp to 0x%llx size %d at local "do {} while(0) |
668 | "idx %d req_idx %d global_idx %d",do {} while(0) |
669 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
670 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
671 | |
672 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
673 | log_warnx("%s: unable to write OK resp status data @ 0x%llx", |
674 | __func__, acct->resp_desc->addr); |
675 | goto free_read_capacity; |
676 | } |
677 | |
678 | /* Move index for r_cap_data */ |
679 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->resp_desc, |
680 | &(acct->resp_idx)); |
681 | |
682 | DPRINTF("%s: writing r_cap_data to 0x%llx size %d at "do {} while(0) |
683 | "local idx %d req_idx %d global_idx %d",do {} while(0) |
684 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
685 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
686 | |
687 | if (write_mem(acct->resp_desc->addr, r_cap_data, |
688 | sizeof(struct scsi_read_cap_data))) { |
689 | log_warnx("%s: unable to write read_cap_data" |
690 | " response to gpa @ 0x%llx", |
691 | __func__, acct->resp_desc->addr); |
692 | } else { |
693 | ret = 1; |
694 | dev->cfg.isr_status = 1; |
695 | /* Move ring indexes */ |
696 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
697 | acct->req_desc, acct->req_idx); |
698 | } |
699 | |
700 | free_read_capacity: |
701 | free(r_cap_data); |
702 | read_capacity_out: |
703 | return (ret); |
704 | } |
705 | |
706 | static int |
707 | vioscsi_handle_read_capacity_16(struct vioscsi_dev *dev, |
708 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
709 | { |
710 | int ret = 0; |
711 | struct virtio_scsi_res_hdr resp; |
712 | uint64_t r_cap_addr_16; |
713 | struct scsi_read_capacity_16 *r_cap_16; |
714 | struct scsi_read_cap_data_16 *r_cap_data_16; |
715 | |
716 | memset(&resp, 0, sizeof(resp)); |
717 | r_cap_16 = (struct scsi_read_capacity_16 *)(req->cdb); |
718 | r_cap_addr_16 = _8btol(r_cap_16->addr); |
719 | DPRINTF("%s: %s - Addr 0x%016llx", __func__,do {} while(0) |
720 | vioscsi_op_names(r_cap_16->opcode), r_cap_addr_16)do {} while(0); |
721 | |
722 | vioscsi_prepare_resp(&resp, VIRTIO_SCSI_S_OK0, SCSI_OK0x00, 0, 0, 0); |
723 | |
724 | r_cap_data_16 = calloc(1, sizeof(struct scsi_read_cap_data_16)); |
725 | |
726 | if (r_cap_data_16 == NULL((void *)0)) { |
727 | log_warnx("%s: cannot alloc r_cap_data_16", |
728 | __func__); |
729 | goto read_capacity_16_out; |
730 | } |
731 | |
732 | DPRINTF("%s: ISO has %lld bytes and %lld blocks", __func__,do {} while(0) |
733 | dev->sz, dev->n_blocks)do {} while(0); |
734 | |
735 | _lto8b(dev->n_blocks - 1, r_cap_data_16->addr); |
736 | _lto4b(VIOSCSI_BLOCK_SIZE_CDROM2048, r_cap_data_16->length); |
737 | |
738 | /* Move index for response */ |
739 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->req_desc, |
740 | &(acct->resp_idx)); |
741 | |
742 | DPRINTF("%s: writing resp to 0x%llx size %d at local "do {} while(0) |
743 | "idx %d req_idx %d global_idx %d",do {} while(0) |
744 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
745 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
746 | |
747 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
748 | log_warnx("%s: unable to write OK resp status " |
749 | "data @ 0x%llx", __func__, acct->resp_desc->addr); |
750 | goto free_read_capacity_16; |
751 | } |
752 | |
753 | /* Move index for r_cap_data_16 */ |
754 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->resp_desc, |
755 | &(acct->resp_idx)); |
756 | |
757 | DPRINTF("%s: writing r_cap_data_16 to 0x%llx size %d "do {} while(0) |
758 | "at local idx %d req_idx %d global_idx %d",do {} while(0) |
759 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
760 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
761 | |
762 | if (write_mem(acct->resp_desc->addr, r_cap_data_16, |
763 | sizeof(struct scsi_read_cap_data_16))) { |
764 | log_warnx("%s: unable to write read_cap_data_16" |
765 | " response to gpa @ 0x%llx", |
766 | __func__, acct->resp_desc->addr); |
767 | } else { |
768 | ret = 1; |
769 | dev->cfg.isr_status = 1; |
770 | /* Move ring indexes */ |
771 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
772 | acct->req_desc, acct->req_idx); |
773 | } |
774 | |
775 | free_read_capacity_16: |
776 | free(r_cap_data_16); |
777 | read_capacity_16_out: |
778 | return (ret); |
779 | } |
780 | |
781 | static int |
782 | vioscsi_handle_report_luns(struct vioscsi_dev *dev, |
783 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
784 | { |
785 | int ret = 0; |
786 | struct virtio_scsi_res_hdr resp; |
787 | uint32_t rpl_length; |
788 | struct scsi_report_luns *rpl; |
789 | struct vioscsi_report_luns_data *reply_rpl; |
790 | |
791 | memset(&resp, 0, sizeof(resp)); |
792 | rpl = (struct scsi_report_luns *)(req->cdb); |
793 | rpl_length = _4btol(rpl->length); |
794 | |
795 | DPRINTF("%s: REPORT_LUNS Report 0x%x Length %d", __func__,do {} while(0) |
796 | rpl->selectreport, rpl_length)do {} while(0); |
797 | |
798 | if (rpl_length < RPL_MIN_SIZE16) { |
799 | DPRINTF("%s: RPL_Length %d < %d (RPL_MIN_SIZE)", __func__,do {} while(0) |
800 | rpl_length, RPL_MIN_SIZE)do {} while(0); |
801 | |
802 | vioscsi_prepare_resp(&resp, |
803 | VIRTIO_SCSI_S_OK0, SCSI_CHECK0x02, SKEY_ILLEGAL_REQUEST0x05, |
804 | SENSE_ILLEGAL_CDB_FIELD0x24, SENSE_DEFAULT_ASCQ0x00); |
805 | |
806 | /* Move index for response */ |
807 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
808 | acct->req_desc, &(acct->resp_idx)); |
809 | |
810 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
811 | log_warnx("%s: unable to set ERR " |
812 | "status data @ 0x%llx", __func__, |
813 | acct->resp_desc->addr); |
814 | } else { |
815 | ret = 1; |
816 | dev->cfg.isr_status = 1; |
817 | /* Move ring indexes */ |
818 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
819 | acct->req_desc, acct->req_idx); |
820 | } |
821 | goto rpl_out; |
822 | |
823 | } |
824 | |
825 | reply_rpl = calloc(1, sizeof(struct vioscsi_report_luns_data)); |
826 | |
827 | if (reply_rpl == NULL((void *)0)) { |
828 | log_warnx("%s: cannot alloc reply_rpl", __func__); |
829 | goto rpl_out; |
830 | } |
831 | |
832 | _lto4b(RPL_SINGLE_LUN8, reply_rpl->length); |
833 | memcpy(reply_rpl->lun, req->lun, RPL_SINGLE_LUN8); |
834 | |
835 | vioscsi_prepare_resp(&resp, |
836 | VIRTIO_SCSI_S_OK0, SCSI_OK0x00, 0, 0, 0); |
837 | |
838 | /* Move index for response */ |
839 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->req_desc, |
840 | &(acct->resp_idx)); |
841 | |
842 | DPRINTF("%s: writing resp to 0x%llx size %d at local "do {} while(0) |
843 | "idx %d req_idx %d global_idx %d", __func__, acct->resp_desc->addr,do {} while(0) |
844 | acct->resp_desc->len, acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
845 | |
846 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
847 | log_warnx("%s: unable to write OK resp status data @ 0x%llx", |
848 | __func__, acct->resp_desc->addr); |
849 | goto free_rpl; |
850 | } |
851 | |
852 | /* Move index for reply_rpl */ |
853 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->resp_desc, |
854 | &(acct->resp_idx)); |
855 | |
856 | DPRINTF("%s: writing reply_rpl to 0x%llx size %d at "do {} while(0) |
857 | "local idx %d req_idx %d global_idx %d",do {} while(0) |
858 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
859 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
860 | |
861 | if (write_mem(acct->resp_desc->addr, reply_rpl, |
862 | sizeof(struct vioscsi_report_luns_data))) { |
863 | log_warnx("%s: unable to write reply_rpl" |
864 | " response to gpa @ 0x%llx", |
865 | __func__, acct->resp_desc->addr); |
866 | } else { |
867 | ret = 1; |
868 | dev->cfg.isr_status = 1; |
869 | /* Move ring indexes */ |
870 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
871 | acct->req_desc, acct->req_idx); |
872 | } |
873 | |
874 | free_rpl: |
875 | free(reply_rpl); |
876 | rpl_out: |
877 | return (ret); |
878 | } |
879 | |
880 | static int |
881 | vioscsi_handle_read_6(struct vioscsi_dev *dev, |
882 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
883 | { |
884 | int ret = 0; |
885 | struct virtio_scsi_res_hdr resp; |
886 | const uint8_t *read_buf; |
887 | uint32_t read_lba; |
888 | struct ioinfo *info; |
889 | struct scsi_rw *read_6; |
890 | |
891 | memset(&resp, 0, sizeof(resp)); |
892 | read_6 = (struct scsi_rw *)(req->cdb); |
893 | read_lba = ((read_6->addr[0] & SRW_TOPADDR0x1F) << 16 ) | |
894 | (read_6->addr[1] << 8) | read_6->addr[2]; |
895 | |
896 | DPRINTF("%s: READ Addr 0x%08x Len %d (%d)",do {} while(0) |
897 | __func__, read_lba, read_6->length, read_6->length * dev->max_xfer)do {} while(0); |
898 | |
899 | /* check if lba is in range */ |
900 | if (read_lba > dev->n_blocks - 1) { |
901 | DPRINTF("%s: requested block out of range req: %ud max: %lld",do {} while(0) |
902 | __func__, read_lba, dev->n_blocks)do {} while(0); |
903 | |
904 | vioscsi_prepare_resp(&resp, |
905 | VIRTIO_SCSI_S_OK0, SCSI_CHECK0x02, SKEY_ILLEGAL_REQUEST0x05, |
906 | SENSE_LBA_OUT_OF_RANGE0x21, SENSE_DEFAULT_ASCQ0x00); |
907 | |
908 | /* Move index for response */ |
909 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
910 | acct->req_desc, &(acct->resp_idx)); |
911 | |
912 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
913 | log_warnx("%s: unable to set ERR " |
914 | "status data @ 0x%llx", __func__, |
915 | acct->resp_desc->addr); |
916 | } else { |
917 | ret = 1; |
918 | dev->cfg.isr_status = 1; |
919 | /* Move ring indexes */ |
920 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
921 | acct->req_desc, acct->req_idx); |
922 | } |
923 | goto read_6_out; |
924 | } |
925 | |
926 | info = vioscsi_start_read(dev, read_lba, read_6->length); |
927 | |
928 | if (info == NULL((void *)0)) { |
929 | log_warnx("%s: cannot alloc for read", __func__); |
930 | goto read_6_out; |
931 | } |
932 | |
933 | /* read block */ |
934 | read_buf = vioscsi_finish_read(info); |
935 | |
936 | if (read_buf == NULL((void *)0)) { |
937 | log_warnx("%s: error reading position %ud", |
938 | __func__, read_lba); |
939 | vioscsi_prepare_resp(&resp, |
940 | VIRTIO_SCSI_S_OK0, SCSI_CHECK0x02, SKEY_MEDIUM_ERROR0x03, |
941 | SENSE_MEDIUM_NOT_PRESENT0x3a, SENSE_DEFAULT_ASCQ0x00); |
942 | |
943 | /* Move index for response */ |
944 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
945 | acct->req_desc, &(acct->resp_idx)); |
946 | |
947 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
948 | log_warnx("%s: unable to set ERR " |
949 | "status data @ 0x%llx", __func__, |
950 | acct->resp_desc->addr); |
951 | } else { |
952 | ret = 1; |
953 | dev->cfg.isr_status = 1; |
954 | /* Move ring indexes */ |
955 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
956 | acct->req_desc, acct->req_idx); |
957 | } |
958 | |
959 | goto free_read_6; |
960 | } |
961 | |
962 | vioscsi_prepare_resp(&resp, VIRTIO_SCSI_S_OK0, SCSI_OK0x00, 0, 0, 0); |
963 | |
964 | /* Move index for response */ |
965 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->req_desc, |
966 | &(acct->resp_idx)); |
967 | |
968 | DPRINTF("%s: writing resp to 0x%llx size %d at local "do {} while(0) |
969 | "idx %d req_idx %d global_idx %d",do {} while(0) |
970 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
971 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
972 | |
973 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
974 | log_warnx("%s: unable to write OK resp status " |
975 | "data @ 0x%llx", __func__, acct->resp_desc->addr); |
976 | goto free_read_6; |
977 | } |
978 | |
979 | /* Move index for read_buf */ |
980 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->resp_desc, |
981 | &(acct->resp_idx)); |
982 | |
983 | DPRINTF("%s: writing read_buf to 0x%llx size %d at "do {} while(0) |
984 | "local idx %d req_idx %d global_idx %d",do {} while(0) |
985 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
986 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
987 | |
988 | if (write_mem(acct->resp_desc->addr, read_buf, info->len)) { |
989 | log_warnx("%s: unable to write read_buf to gpa @ 0x%llx", |
990 | __func__, acct->resp_desc->addr); |
991 | } else { |
992 | ret = 1; |
993 | dev->cfg.isr_status = 1; |
994 | /* Move ring indexes */ |
995 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
996 | acct->req_desc, acct->req_idx); |
997 | } |
998 | |
999 | free_read_6: |
1000 | vioscsi_free_info(info); |
1001 | read_6_out: |
1002 | return (ret); |
1003 | } |
1004 | |
1005 | static int |
1006 | vioscsi_handle_read_10(struct vioscsi_dev *dev, |
1007 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
1008 | { |
1009 | int ret = 0; |
1010 | struct virtio_scsi_res_hdr resp; |
1011 | const uint8_t *read_buf; |
1012 | uint32_t read_lba; |
1013 | uint16_t read_10_len; |
1014 | off_t chunk_offset; |
1015 | struct ioinfo *info; |
1016 | struct scsi_rw_10 *read_10; |
1017 | size_t chunk_len = 0; |
1018 | |
1019 | memset(&resp, 0, sizeof(resp)); |
1020 | read_10 = (struct scsi_rw_10 *)(req->cdb); |
1021 | read_lba = _4btol(read_10->addr); |
1022 | read_10_len = _2btol(read_10->length); |
1023 | chunk_offset = 0; |
1024 | |
1025 | DPRINTF("%s: READ_10 Addr 0x%08x Len %d (%d)",do {} while(0) |
1026 | __func__, read_lba, read_10_len, read_10_len * dev->max_xfer)do {} while(0); |
1027 | |
1028 | /* check if lba is in range */ |
1029 | if (read_lba > dev->n_blocks - 1) { |
1030 | DPRINTF("%s: requested block out of range req: %ud max: %lld",do {} while(0) |
1031 | __func__, read_lba, dev->n_blocks)do {} while(0); |
1032 | |
1033 | vioscsi_prepare_resp(&resp, |
1034 | VIRTIO_SCSI_S_OK0, SCSI_CHECK0x02, SKEY_ILLEGAL_REQUEST0x05, |
1035 | SENSE_LBA_OUT_OF_RANGE0x21, SENSE_DEFAULT_ASCQ0x00); |
1036 | |
1037 | /* Move index for response */ |
1038 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
1039 | acct->req_desc, &(acct->resp_idx)); |
1040 | |
1041 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
1042 | log_warnx("%s: unable to set ERR status data @ 0x%llx", |
1043 | __func__, acct->resp_desc->addr); |
1044 | } else { |
1045 | ret = 1; |
1046 | dev->cfg.isr_status = 1; |
1047 | /* Move ring indexes */ |
1048 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
1049 | acct->req_desc, acct->req_idx); |
1050 | } |
1051 | |
1052 | goto read_10_out; |
1053 | } |
1054 | |
1055 | info = vioscsi_start_read(dev, read_lba, read_10_len); |
1056 | |
1057 | if (info == NULL((void *)0)) { |
1058 | log_warnx("%s: cannot alloc for read", __func__); |
1059 | goto read_10_out; |
1060 | } |
1061 | |
1062 | /* read block */ |
1063 | read_buf = vioscsi_finish_read(info); |
1064 | |
1065 | if (read_buf == NULL((void *)0)) { |
1066 | log_warnx("%s: error reading position %ud", __func__, read_lba); |
1067 | vioscsi_prepare_resp(&resp, |
1068 | VIRTIO_SCSI_S_OK0, SCSI_CHECK0x02, SKEY_MEDIUM_ERROR0x03, |
1069 | SENSE_MEDIUM_NOT_PRESENT0x3a, SENSE_DEFAULT_ASCQ0x00); |
1070 | |
1071 | /* Move index for response */ |
1072 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
1073 | acct->req_desc, &(acct->resp_idx)); |
1074 | |
1075 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
1076 | log_warnx("%s: unable to set ERR status data @ 0x%llx", |
1077 | __func__, acct->resp_desc->addr); |
1078 | } else { |
1079 | ret = 1; |
1080 | dev->cfg.isr_status = 1; |
1081 | /* Move ring indexes */ |
1082 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
1083 | acct->req_desc, acct->req_idx); |
1084 | } |
1085 | |
1086 | goto free_read_10; |
1087 | } |
1088 | |
1089 | vioscsi_prepare_resp(&resp, VIRTIO_SCSI_S_OK0, SCSI_OK0x00, 0, 0, 0); |
1090 | |
1091 | /* Move index for response */ |
1092 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->req_desc, |
1093 | &(acct->resp_idx)); |
1094 | |
1095 | DPRINTF("%s: writing resp to 0x%llx size %d at local "do {} while(0) |
1096 | "idx %d req_idx %d global_idx %d",do {} while(0) |
1097 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
1098 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
1099 | |
1100 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
1101 | log_warnx("%s: unable to write OK resp status " |
1102 | "data @ 0x%llx", __func__, acct->resp_desc->addr); |
1103 | goto free_read_10; |
1104 | } |
1105 | |
1106 | /* |
1107 | * Perform possible chunking of writes of read_buf |
1108 | * based on the segment length allocated by the host. |
1109 | * At least one write will be performed. |
1110 | * If chunk_offset == info->len, no more writes |
1111 | */ |
1112 | do { |
1113 | /* Move index for read_buf */ |
1114 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
1115 | acct->resp_desc, &(acct->resp_idx)); |
1116 | |
1117 | DPRINTF("%s: writing read_buf to 0x%llx size "do {} while(0) |
1118 | "%d at local idx %d req_idx %d global_idx %d",do {} while(0) |
1119 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
1120 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
1121 | |
1122 | /* Check we don't read beyond read_buf boundaries. */ |
1123 | if (acct->resp_desc->len > info->len - chunk_offset) { |
1124 | log_warnx("%s: descriptor length beyond read_buf len", |
1125 | __func__); |
1126 | chunk_len = info->len - chunk_offset; |
1127 | } else |
1128 | chunk_len = acct->resp_desc->len; |
1129 | |
1130 | if (write_mem(acct->resp_desc->addr, read_buf + chunk_offset, |
1131 | chunk_len)) { |
1132 | log_warnx("%s: unable to write read_buf" |
1133 | " to gpa @ 0x%llx", __func__, |
1134 | acct->resp_desc->addr); |
1135 | goto free_read_10; |
1136 | } |
1137 | chunk_offset += acct->resp_desc->len; |
1138 | } while (chunk_offset < info->len); |
1139 | |
1140 | ret = 1; |
1141 | dev->cfg.isr_status = 1; |
1142 | /* Move ring indexes */ |
1143 | vioscsi_next_ring_item(dev, acct->avail, acct->used, acct->req_desc, |
1144 | acct->req_idx); |
1145 | |
1146 | free_read_10: |
1147 | vioscsi_free_info(info); |
1148 | read_10_out: |
1149 | return (ret); |
1150 | } |
1151 | |
1152 | static int |
1153 | vioscsi_handle_prevent_allow(struct vioscsi_dev *dev, |
1154 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
1155 | { |
1156 | int ret = 0; |
1157 | struct virtio_scsi_res_hdr resp; |
1158 | |
1159 | memset(&resp, 0, sizeof(resp)); |
1160 | /* Move index for response */ |
1161 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->req_desc, |
1162 | &(acct->resp_idx)); |
1163 | |
1164 | vioscsi_prepare_resp(&resp, VIRTIO_SCSI_S_OK0, SCSI_OK0x00, 0, 0, 0); |
1165 | |
1166 | if (dev->locked) { |
1167 | DPRINTF("%s: unlocking medium", __func__)do {} while(0); |
1168 | } else { |
1169 | DPRINTF("%s: locking medium", __func__)do {} while(0); |
1170 | } |
1171 | |
1172 | dev->locked = dev->locked ? 0 : 1; |
1173 | |
1174 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
1175 | log_warnx("%s: unable to write OK resp status data @ 0x%llx", |
1176 | __func__, acct->resp_desc->addr); |
1177 | } else { |
1178 | ret = 1; |
1179 | dev->cfg.isr_status = 1; |
1180 | /* Move ring indexes */ |
1181 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
1182 | acct->req_desc, acct->req_idx); |
1183 | } |
1184 | |
1185 | return (ret); |
1186 | } |
1187 | |
1188 | static int |
1189 | vioscsi_handle_mechanism_status(struct vioscsi_dev *dev, |
1190 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
1191 | { |
1192 | int ret = 0; |
1193 | struct virtio_scsi_res_hdr resp; |
1194 | uint16_t mech_status_len; |
1195 | struct scsi_mechanism_status *mech_status; |
1196 | struct scsi_mechanism_status_header *mech_status_header; |
1197 | |
1198 | memset(&resp, 0, sizeof(resp)); |
1199 | mech_status = (struct scsi_mechanism_status *)(req->cdb); |
1200 | mech_status_len = (uint16_t)_2btol(mech_status->length); |
1201 | DPRINTF("%s: MECH_STATUS Len %u", __func__, mech_status_len)do {} while(0); |
1202 | |
1203 | mech_status_header = calloc(1, |
1204 | sizeof(struct scsi_mechanism_status_header)); |
1205 | |
1206 | if (mech_status_header == NULL((void *)0)) |
1207 | goto mech_out; |
1208 | |
1209 | /* return a 0 header since we are not a changer */ |
1210 | vioscsi_prepare_resp(&resp, |
1211 | VIRTIO_SCSI_S_OK0, SCSI_OK0x00, 0, 0, 0); |
1212 | |
1213 | /* Move index for response */ |
1214 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
1215 | acct->req_desc, &(acct->resp_idx)); |
1216 | |
1217 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
1218 | log_warnx("%s: unable to set ERR status data @ 0x%llx", |
1219 | __func__, acct->resp_desc->addr); |
1220 | goto free_mech; |
1221 | } |
1222 | |
1223 | /* Move index for mech_status_header */ |
1224 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->resp_desc, |
1225 | &(acct->resp_idx)); |
1226 | |
1227 | if (write_mem(acct->resp_desc->addr, mech_status_header, |
1228 | sizeof(struct scsi_mechanism_status_header))) { |
1229 | log_warnx("%s: unable to write " |
1230 | "mech_status_header response to " |
1231 | "gpa @ 0x%llx", |
1232 | __func__, acct->resp_desc->addr); |
1233 | } else { |
1234 | ret = 1; |
1235 | dev->cfg.isr_status = 1; |
1236 | /* Move ring indexes */ |
1237 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
1238 | acct->req_desc, acct->req_idx); |
1239 | } |
1240 | |
1241 | free_mech: |
1242 | free(mech_status_header); |
1243 | mech_out: |
1244 | return (ret); |
1245 | } |
1246 | |
1247 | static int |
1248 | vioscsi_handle_read_toc(struct vioscsi_dev *dev, |
1249 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
1250 | { |
1251 | int ret = 0; |
1252 | struct virtio_scsi_res_hdr resp; |
1253 | uint16_t toc_len; |
1254 | uint16_t toc_data_len; |
1255 | uint8_t toc_data[TOC_DATA_SIZE20]; |
1256 | uint8_t *toc_data_p; |
1257 | struct scsi_read_toc *toc; |
1258 | |
1259 | memset(&resp, 0, sizeof(resp)); |
1260 | toc = (struct scsi_read_toc *)(req->cdb); |
1261 | toc_len = (uint16_t)_2btol(toc->data_len); |
1262 | DPRINTF("%s: %s - MSF %d Track 0x%02x Addr 0x%04x",do {} while(0) |
1263 | __func__, vioscsi_op_names(toc->opcode),do {} while(0) |
1264 | ((toc->byte2 >> 1) & 1), toc->from_track, toc_len)do {} while(0); |
1265 | |
1266 | memset(toc_data, 0, sizeof(toc_data)); |
1267 | |
1268 | /* Tracks should be 0, 1, or LEAD_OUT_TRACK, 0xaa */ |
1269 | if (toc->from_track > 1 && |
1270 | toc->from_track != READ_TOC_LEAD_OUT_TRACK0xaa) { |
1271 | /* illegal request */ |
1272 | log_warnx("%s: illegal request Track 0x%02x", |
1273 | __func__, toc->from_track); |
1274 | |
1275 | vioscsi_prepare_resp(&resp, |
1276 | VIRTIO_SCSI_S_OK0, SCSI_CHECK0x02, SKEY_ILLEGAL_REQUEST0x05, |
1277 | SENSE_ILLEGAL_CDB_FIELD0x24, SENSE_DEFAULT_ASCQ0x00); |
1278 | |
1279 | /* Move index for response */ |
1280 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
1281 | acct->req_desc, &(acct->resp_idx)); |
1282 | |
1283 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
1284 | log_warnx("%s: unable to set ERR status data @ 0x%llx", |
1285 | __func__, acct->resp_desc->addr); |
1286 | goto read_toc_out; |
1287 | } |
1288 | |
1289 | ret = 1; |
1290 | dev->cfg.isr_status = 1; |
1291 | /* Move ring indexes */ |
1292 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
1293 | acct->req_desc, acct->req_idx); |
1294 | |
1295 | goto read_toc_out; |
1296 | } |
1297 | |
1298 | /* |
1299 | * toc_data is defined as: |
1300 | * [0-1]: TOC Data Length, typically 0x1a |
1301 | * [2]: First Track, 1 |
1302 | * [3]: Last Track, 1 |
1303 | * |
1304 | * Track 1 Descriptor |
1305 | * [0]: Reserved, 0 |
1306 | * [1]: ADR,Control, 0x14 |
1307 | * [2]: Track #, 1 |
1308 | * [3]: Reserved, 0 |
1309 | * [4-7]: Track Start Address, LBA |
1310 | * |
1311 | * Track 0xaa (Lead Out) Descriptor |
1312 | * [0]: Reserved, 0 |
1313 | * [1]: ADR,Control, 0x14 |
1314 | * [2]: Track #, 0xaa |
1315 | * [3]: Reserved, 0 |
1316 | * [4-7]: Track Start Address, LBA |
1317 | */ |
1318 | toc_data_p = toc_data + 2; |
1319 | *toc_data_p++ = READ_TOC_START_TRACK0x01; |
1320 | *toc_data_p++ = READ_TOC_LAST_TRACK0x01; |
1321 | if (toc->from_track <= 1) { |
1322 | /* first track descriptor */ |
1323 | *toc_data_p++ = 0x0; |
1324 | *toc_data_p++ = READ_TOC_ADR_CTL0x14; |
1325 | *toc_data_p++ = READ_TOC_START_TRACK0x01; |
1326 | *toc_data_p++ = 0x0; |
1327 | /* start addr for first track is 0 */ |
1328 | *toc_data_p++ = 0x0; |
1329 | *toc_data_p++ = 0x0; |
1330 | *toc_data_p++ = 0x0; |
1331 | *toc_data_p++ = 0x0; |
1332 | } |
1333 | |
1334 | /* last track descriptor */ |
1335 | *toc_data_p++ = 0x0; |
1336 | *toc_data_p++ = READ_TOC_ADR_CTL0x14; |
1337 | *toc_data_p++ = READ_TOC_LEAD_OUT_TRACK0xaa; |
1338 | *toc_data_p++ = 0x0; |
1339 | |
1340 | _lto4b((uint32_t)dev->n_blocks, toc_data_p); |
1341 | toc_data_p += 4; |
1342 | |
1343 | toc_data_len = toc_data_p - toc_data; |
1344 | _lto2b((uint32_t)toc_data_len - 2, toc_data); |
1345 | |
1346 | vioscsi_prepare_resp(&resp, VIRTIO_SCSI_S_OK0, SCSI_OK0x00, 0, 0, 0); |
1347 | |
1348 | /* Move index for response */ |
1349 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->req_desc, |
1350 | &(acct->resp_idx)); |
1351 | |
1352 | DPRINTF("%s: writing resp to 0x%llx size %d at local "do {} while(0) |
1353 | "idx %d req_idx %d global_idx %d",do {} while(0) |
1354 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
1355 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
1356 | |
1357 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
1358 | log_warnx("%s: unable to write OK resp status data @ 0x%llx", |
1359 | __func__, acct->resp_desc->addr); |
1360 | goto read_toc_out; |
1361 | } |
1362 | |
1363 | /* Move index for toc descriptor */ |
1364 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->resp_desc, |
1365 | &(acct->resp_idx)); |
1366 | |
1367 | DPRINTF("%s: writing toc_data to 0x%llx size %d at "do {} while(0) |
1368 | "local idx %d req_idx %d global_idx %d",do {} while(0) |
1369 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
1370 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
1371 | |
1372 | if (write_mem(acct->resp_desc->addr, toc_data, sizeof(toc_data))) { |
1373 | log_warnx("%s: unable to write toc descriptor data @ 0x%llx", |
1374 | __func__, acct->resp_desc->addr); |
1375 | } else { |
1376 | ret = 1; |
1377 | dev->cfg.isr_status = 1; |
1378 | /* Move ring indexes */ |
1379 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
1380 | acct->req_desc, acct->req_idx); |
1381 | } |
1382 | |
1383 | read_toc_out: |
1384 | return (ret); |
1385 | } |
1386 | |
1387 | static int |
1388 | vioscsi_handle_read_disc_info(struct vioscsi_dev *dev, |
1389 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
1390 | { |
1391 | int ret = 0; |
1392 | struct virtio_scsi_res_hdr resp; |
1393 | struct scsi_read_disc_information *read_disc; |
1394 | |
1395 | memset(&resp, 0, sizeof(resp)); |
1396 | read_disc = |
1397 | (struct scsi_read_disc_information *)(req->cdb); |
1398 | DPRINTF("%s: Disc Info %x", __func__, read_disc->byte2)do {} while(0); |
1399 | |
1400 | /* send back unsupported */ |
1401 | vioscsi_prepare_resp(&resp, |
1402 | VIRTIO_SCSI_S_OK0, SCSI_CHECK0x02, SKEY_ILLEGAL_REQUEST0x05, |
1403 | SENSE_ILLEGAL_CDB_FIELD0x24, SENSE_DEFAULT_ASCQ0x00); |
1404 | |
1405 | /* Move index for response */ |
1406 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
1407 | acct->req_desc, &(acct->resp_idx)); |
1408 | |
1409 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
1410 | log_warnx("%s: unable to set ERR status data @ 0x%llx", |
1411 | __func__, acct->resp_desc->addr); |
1412 | } else { |
1413 | ret = 1; |
1414 | dev->cfg.isr_status = 1; |
1415 | /* Move ring indexes */ |
1416 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
1417 | acct->req_desc, acct->req_idx); |
1418 | } |
1419 | |
1420 | return (ret); |
1421 | } |
1422 | |
1423 | static int |
1424 | vioscsi_handle_gesn(struct vioscsi_dev *dev, |
1425 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
1426 | { |
1427 | int ret = 0; |
1428 | struct virtio_scsi_res_hdr resp; |
1429 | uint8_t gesn_reply[GESN_SIZE8]; |
1430 | struct scsi_gesn *gesn; |
1431 | struct scsi_gesn_event_header *gesn_event_header; |
1432 | struct scsi_gesn_power_event *gesn_power_event; |
1433 | |
1434 | memset(&resp, 0, sizeof(resp)); |
1435 | gesn = (struct scsi_gesn *)(req->cdb); |
1436 | DPRINTF("%s: GESN Method %s", __func__,do {} while(0) |
1437 | gesn->byte2 ? "Polling" : "Asynchronous")do {} while(0); |
1438 | |
1439 | if (gesn->byte2 == 0) { |
1440 | /* we don't support asynchronous */ |
1441 | vioscsi_prepare_resp(&resp, |
1442 | VIRTIO_SCSI_S_OK0, SCSI_CHECK0x02, SKEY_ILLEGAL_REQUEST0x05, |
1443 | SENSE_ILLEGAL_CDB_FIELD0x24, SENSE_DEFAULT_ASCQ0x00); |
1444 | |
1445 | /* Move index for response */ |
1446 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
1447 | acct->req_desc, &(acct->resp_idx)); |
1448 | |
1449 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
1450 | log_warnx("%s: unable to set ERR status data @ 0x%llx", |
1451 | __func__, acct->resp_desc->addr); |
1452 | goto gesn_out; |
1453 | } |
1454 | |
1455 | ret = 1; |
1456 | dev->cfg.isr_status = 1; |
1457 | /* Move ring indexes */ |
1458 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
1459 | acct->req_desc, acct->req_idx); |
1460 | |
1461 | goto gesn_out; |
1462 | } |
1463 | memset(gesn_reply, 0, sizeof(gesn_reply)); |
1464 | gesn_event_header = (struct scsi_gesn_event_header *)(gesn_reply); |
1465 | gesn_power_event = (struct scsi_gesn_power_event *)(gesn_reply + 4); |
1466 | /* set event header length and notification */ |
1467 | _lto2b(GESN_HEADER_LEN0x06, gesn_event_header->length); |
1468 | gesn_event_header->notification = GESN_NOTIFY_POWER_MGMT0x2; |
1469 | gesn_event_header->supported_event = GESN_EVENT_POWER_MGMT0x4; |
1470 | |
1471 | /* set event descriptor */ |
1472 | gesn_power_event->event_code = GESN_CODE_NOCHG0x0; |
1473 | if (dev->locked) |
1474 | gesn_power_event->status = GESN_STATUS_ACTIVE0x1; |
1475 | else |
1476 | gesn_power_event->status = GESN_STATUS_IDLE0x2; |
1477 | |
1478 | /* Move index for response */ |
1479 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->req_desc, |
1480 | &(acct->resp_idx)); |
1481 | |
1482 | DPRINTF("%s: writing resp to 0x%llx size %d at local "do {} while(0) |
1483 | "idx %d req_idx %d global_idx %d",do {} while(0) |
1484 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
1485 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
1486 | |
1487 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
1488 | log_warnx("%s: unable to write OK resp status " |
1489 | "data @ 0x%llx", __func__, acct->resp_desc->addr); |
1490 | goto gesn_out; |
1491 | } |
1492 | |
1493 | /* Move index for gesn_reply */ |
1494 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->resp_desc, |
1495 | &(acct->resp_idx)); |
1496 | |
1497 | DPRINTF("%s: writing gesn_reply to 0x%llx size %d at "do {} while(0) |
1498 | "local idx %d req_idx %d global_idx %d",do {} while(0) |
1499 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
1500 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
1501 | |
1502 | if (write_mem(acct->resp_desc->addr, gesn_reply, sizeof(gesn_reply))) { |
1503 | log_warnx("%s: unable to write gesn_reply" |
1504 | " response to gpa @ 0x%llx", |
1505 | __func__, acct->resp_desc->addr); |
1506 | } else { |
1507 | ret = 1; |
1508 | dev->cfg.isr_status = 1; |
1509 | /* Move ring indexes */ |
1510 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
1511 | acct->req_desc, acct->req_idx); |
1512 | } |
1513 | |
1514 | gesn_out: |
1515 | return (ret); |
1516 | } |
1517 | |
1518 | static int |
1519 | vioscsi_handle_get_config(struct vioscsi_dev *dev, |
1520 | struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) |
1521 | { |
1522 | int ret = 0; |
1523 | struct virtio_scsi_res_hdr resp; |
1524 | uint16_t get_conf_feature; |
1525 | uint16_t get_conf_len; |
1526 | uint8_t *get_conf_reply; |
1527 | struct scsi_get_configuration *get_configuration; |
1528 | struct scsi_config_feature_header *config_feature_header; |
1529 | struct scsi_config_generic_descriptor *config_generic_desc; |
1530 | struct scsi_config_profile_descriptor *config_profile_desc; |
1531 | struct scsi_config_core_descriptor *config_core_desc; |
1532 | struct scsi_config_morphing_descriptor *config_morphing_desc; |
1533 | struct scsi_config_remove_media_descriptor *config_remove_media_desc; |
1534 | struct scsi_config_random_read_descriptor *config_random_read_desc; |
1535 | |
1536 | memset(&resp, 0, sizeof(resp)); |
1537 | get_configuration = (struct scsi_get_configuration *)(req->cdb); |
1538 | get_conf_feature = (uint16_t)_2btol(get_configuration->feature); |
1539 | get_conf_len = (uint16_t)_2btol(get_configuration->length); |
1540 | DPRINTF("%s: Conf RT %x Feature %d Len %d", __func__,do {} while(0) |
1541 | get_configuration->byte2, get_conf_feature, get_conf_len)do {} while(0); |
1542 | |
1543 | get_conf_reply = (uint8_t*)calloc(G_CONFIG_REPLY_SIZE56, sizeof(uint8_t)); |
1544 | |
1545 | if (get_conf_reply == NULL((void *)0)) |
1546 | goto get_config_out; |
1547 | |
1548 | /* |
1549 | * Use MMC-5 6.6 for structure and |
1550 | * MMC-5 5.2 to send back: |
1551 | * feature header - 8 bytes |
1552 | * feature descriptor for profile list - 8 bytes |
1553 | * feature descriptor for core feature - 12 bytes |
1554 | * feature descriptor for morphing feature - 8 bytes |
1555 | * feature descriptor for removable media - 8 bytes |
1556 | * feature descriptor for random read feature - 12 bytes |
1557 | */ |
1558 | |
1559 | config_feature_header = |
1560 | (struct scsi_config_feature_header *)(get_conf_reply); |
1561 | config_generic_desc = |
1562 | (struct scsi_config_generic_descriptor *)(get_conf_reply + 8); |
1563 | config_profile_desc = |
1564 | (struct scsi_config_profile_descriptor *)(get_conf_reply + 12); |
1565 | config_core_desc = |
1566 | (struct scsi_config_core_descriptor *)(get_conf_reply + 16); |
1567 | config_morphing_desc = |
1568 | (struct scsi_config_morphing_descriptor *)(get_conf_reply + 28); |
1569 | config_remove_media_desc = |
1570 | (struct scsi_config_remove_media_descriptor *)(get_conf_reply + 36); |
1571 | config_random_read_desc = |
1572 | (struct scsi_config_random_read_descriptor *)(get_conf_reply + 44); |
1573 | |
1574 | /* set size to be get_conf_reply - size field */ |
1575 | _lto4b(G_CONFIG_REPLY_SIZE_HEX0x0034, config_feature_header->length); |
1576 | /* set current profile to be non-conforming */ |
1577 | _lto2b(CONFIG_PROFILE_NON_CONFORM0xffff, |
1578 | config_feature_header->current_profile); |
1579 | |
1580 | /* fill out profile list feature */ |
1581 | _lto2b(CONFIG_FEATURE_CODE_PROFILE0x0000, config_generic_desc->feature_code); |
1582 | config_generic_desc->byte3 = CONFIG_PROFILELIST_BYTE30x03; |
1583 | config_generic_desc->length = CONFIG_PROFILELIST_LENGTH0x04; |
1584 | /* fill out profile descriptor for NON_COFORM */ |
1585 | _lto2b(CONFIG_PROFILE_NON_CONFORM0xffff, config_profile_desc->profile_number); |
1586 | config_profile_desc->byte3 = CONFIG_PROFILE_BYTE30x01; |
1587 | |
1588 | /* fill out core feature */ |
1589 | _lto2b(CONFIG_FEATURE_CODE_CORE0x0001, config_core_desc->feature_code); |
1590 | config_core_desc->byte3 = CONFIG_CORE_BYTE30x11; |
1591 | config_core_desc->length = CONFIG_CORE_LENGTH0x08; |
1592 | _lto4b(CONFIG_CORE_PHY_SCSI0x00000001, config_core_desc->phy_std); |
1593 | |
1594 | /* fill out morphing feature */ |
1595 | _lto2b(CONFIG_FEATURE_CODE_MORPHING0x0002, |
1596 | config_morphing_desc->feature_code); |
1597 | config_morphing_desc->byte3 = CONFIG_MORPHING_BYTE30x07; |
1598 | config_morphing_desc->length = CONFIG_MORPHING_LENGTH0x04; |
1599 | config_morphing_desc->byte5 = CONFIG_MORPHING_BYTE50x2; |
1600 | |
1601 | /* fill out removable media feature */ |
1602 | _lto2b(CONFIG_FEATURE_CODE_REMOVE_MEDIA0x0004, |
1603 | config_remove_media_desc->feature_code); |
1604 | config_remove_media_desc->byte3 = CONFIG_REMOVE_MEDIA_BYTE30x03; |
1605 | config_remove_media_desc->length = CONFIG_REMOVE_MEDIA_LENGTH0x04; |
1606 | config_remove_media_desc->byte5 = CONFIG_REMOVE_MEDIA_BYTE50x09; |
1607 | |
1608 | /* fill out random read feature */ |
1609 | _lto2b(CONFIG_FEATURE_CODE_RANDOM_READ0x0010, |
1610 | config_random_read_desc->feature_code); |
1611 | config_random_read_desc->byte3 = CONFIG_RANDOM_READ_BYTE30x03; |
1612 | config_random_read_desc->length = CONFIG_RANDOM_READ_LENGTH0x08; |
1613 | if (dev->n_blocks >= UINT32_MAX0xffffffffU) |
1614 | _lto4b(UINT32_MAX0xffffffffU, config_random_read_desc->block_size); |
1615 | else |
1616 | _lto4b(dev->n_blocks - 1, config_random_read_desc->block_size); |
1617 | _lto2b(CONFIG_RANDOM_READ_BLOCKING_TYPE0x0010, |
1618 | config_random_read_desc->blocking_type); |
1619 | |
1620 | vioscsi_prepare_resp(&resp, VIRTIO_SCSI_S_OK0, SCSI_OK0x00, 0, 0, 0); |
1621 | |
1622 | /* Move index for response */ |
1623 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, |
1624 | acct->req_desc, &(acct->resp_idx)); |
1625 | |
1626 | DPRINTF("%s: writing resp to 0x%llx size %d at local "do {} while(0) |
1627 | "idx %d req_idx %d global_idx %d",do {} while(0) |
1628 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
1629 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
1630 | |
1631 | if (write_mem(acct->resp_desc->addr, &resp, sizeof(resp))) { |
1632 | log_warnx("%s: unable to set Ok status data @ 0x%llx", |
1633 | __func__, acct->resp_desc->addr); |
1634 | goto free_get_config; |
1635 | } |
1636 | |
1637 | /* Move index for get_conf_reply */ |
1638 | acct->resp_desc = vioscsi_next_ring_desc(acct->desc, acct->resp_desc, |
1639 | &(acct->resp_idx)); |
1640 | |
1641 | DPRINTF("%s: writing get_conf_reply to 0x%llx size %d "do {} while(0) |
1642 | "at local idx %d req_idx %d global_idx %d",do {} while(0) |
1643 | __func__, acct->resp_desc->addr, acct->resp_desc->len,do {} while(0) |
1644 | acct->resp_idx, acct->req_idx, acct->idx)do {} while(0); |
1645 | |
1646 | if (write_mem(acct->resp_desc->addr, get_conf_reply, |
1647 | G_CONFIG_REPLY_SIZE56)) { |
1648 | log_warnx("%s: unable to write get_conf_reply" |
1649 | " response to gpa @ 0x%llx", |
1650 | __func__, acct->resp_desc->addr); |
1651 | } else { |
1652 | ret = 1; |
1653 | dev->cfg.isr_status = 1; |
1654 | /* Move ring indexes */ |
1655 | vioscsi_next_ring_item(dev, acct->avail, acct->used, |
1656 | acct->req_desc, acct->req_idx); |
1657 | } |
1658 | |
1659 | free_get_config: |
1660 | free(get_conf_reply); |
1661 | get_config_out: |
1662 | return (ret); |
1663 | } |
1664 | |
1665 | int |
1666 | vioscsi_io(int dir, uint16_t reg, uint32_t *data, uint8_t *intr, |
1667 | void *cookie, uint8_t sz) |
1668 | { |
1669 | struct vioscsi_dev *dev = (struct vioscsi_dev *)cookie; |
1670 | |
1671 | *intr = 0xFF; |
1672 | |
1673 | DPRINTF("%s: request %s reg %u,%s sz %u", __func__,do {} while(0) |
1674 | dir ? "READ" : "WRITE", reg, vioscsi_reg_name(reg), sz)do {} while(0); |
1675 | |
1676 | if (dir == 0) { |
1677 | switch (reg) { |
1678 | case VIRTIO_CONFIG_DEVICE_FEATURES0: |
1679 | case VIRTIO_CONFIG_QUEUE_SIZE12: |
1680 | case VIRTIO_CONFIG_ISR_STATUS19: |
1681 | log_warnx("%s: illegal write %x to %s", |
1682 | __progname, *data, vioscsi_reg_name(reg)); |
1683 | break; |
1684 | case VIRTIO_CONFIG_GUEST_FEATURES4: |
1685 | dev->cfg.guest_feature = *data; |
1686 | DPRINTF("%s: guest feature set to %u",do {} while(0) |
1687 | __func__, dev->cfg.guest_feature)do {} while(0); |
1688 | break; |
1689 | case VIRTIO_CONFIG_QUEUE_ADDRESS8: |
1690 | dev->cfg.queue_address = *data; |
1691 | vioscsi_update_qa(dev); |
1692 | break; |
1693 | case VIRTIO_CONFIG_QUEUE_SELECT14: |
1694 | dev->cfg.queue_select = *data; |
1695 | vioscsi_update_qs(dev); |
1696 | break; |
1697 | case VIRTIO_CONFIG_QUEUE_NOTIFY16: |
1698 | dev->cfg.queue_notify = *data; |
1699 | if (vioscsi_notifyq(dev)) |
1700 | *intr = 1; |
1701 | break; |
1702 | case VIRTIO_CONFIG_DEVICE_STATUS18: |
1703 | dev->cfg.device_status = *data; |
1704 | DPRINTF("%s: device status set to %u",do {} while(0) |
1705 | __func__, dev->cfg.device_status)do {} while(0); |
1706 | if (dev->cfg.device_status == 0) { |
1707 | log_debug("%s: device reset", __func__); |
1708 | dev->cfg.guest_feature = 0; |
1709 | dev->cfg.queue_address = 0; |
1710 | vioscsi_update_qa(dev); |
1711 | dev->cfg.queue_size = 0; |
1712 | vioscsi_update_qs(dev); |
1713 | dev->cfg.queue_select = 0; |
1714 | dev->cfg.queue_notify = 0; |
1715 | dev->cfg.isr_status = 0; |
1716 | dev->vq[0].last_avail = 0; |
1717 | dev->vq[1].last_avail = 0; |
1718 | dev->vq[2].last_avail = 0; |
1719 | } |
1720 | break; |
1721 | default: |
1722 | break; |
1723 | } |
1724 | } else { |
1725 | switch (reg) { |
1726 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20: |
1727 | /* VIRTIO_SCSI_CONFIG_NUM_QUEUES, 32bit */ |
1728 | if (sz == 4) |
1729 | *data = (uint32_t)VIOSCSI_NUM_QUEUES1; |
1730 | else if (sz == 1) { |
1731 | /* read first byte of num_queues */ |
1732 | *data &= 0xFFFFFF00; |
1733 | *data |= (uint32_t)(VIOSCSI_NUM_QUEUES1) & 0xFF; |
1734 | } |
1735 | break; |
1736 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 1: |
1737 | if (sz == 1) { |
1738 | /* read second byte of num_queues */ |
1739 | *data &= 0xFFFFFF00; |
1740 | *data |= |
1741 | (uint32_t)(VIOSCSI_NUM_QUEUES1 >> 8) & 0xFF; |
1742 | } |
1743 | break; |
1744 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 2: |
1745 | if (sz == 1) { |
1746 | /* read third byte of num_queues */ |
1747 | *data &= 0xFFFFFF00; |
1748 | *data |= |
1749 | (uint32_t)(VIOSCSI_NUM_QUEUES1 >> 16) & 0xFF; |
1750 | } |
1751 | break; |
1752 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 3: |
1753 | if (sz == 1) { |
1754 | /* read fourth byte of num_queues */ |
1755 | *data &= 0xFFFFFF00; |
1756 | *data |= |
1757 | (uint32_t)(VIOSCSI_NUM_QUEUES1 >> 24) & 0xFF; |
1758 | } |
1759 | break; |
1760 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 4: |
1761 | /* VIRTIO_SCSI_CONFIG_SEG_MAX, 32bit */ |
1762 | if (sz == 4) |
1763 | *data = (uint32_t)(VIOSCSI_SEG_MAX17); |
1764 | else if (sz == 1) { |
1765 | /* read first byte of seg_max */ |
1766 | *data &= 0xFFFFFF00; |
1767 | *data |= (uint32_t)(VIOSCSI_SEG_MAX17) & 0xFF; |
1768 | } |
1769 | break; |
1770 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 5: |
1771 | if (sz == 1) { |
1772 | /* read second byte of seg_max */ |
1773 | *data &= 0xFFFFFF00; |
1774 | *data |= |
1775 | (uint32_t)(VIOSCSI_SEG_MAX17 >> 8) & 0xFF; |
1776 | } |
1777 | break; |
1778 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 6: |
1779 | if (sz == 1) { |
1780 | /* read third byte of seg_max */ |
1781 | *data &= 0xFFFFFF00; |
1782 | *data |= |
1783 | (uint32_t)(VIOSCSI_SEG_MAX17 >> 16) & 0xFF; |
1784 | } |
1785 | break; |
1786 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 7: |
1787 | if (sz == 1) { |
1788 | /* read fourth byte of seg_max */ |
1789 | *data &= 0xFFFFFF00; |
1790 | *data |= |
1791 | (uint32_t)(VIOSCSI_SEG_MAX17 >> 24) & 0xFF; |
1792 | } |
1793 | break; |
1794 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 8: |
1795 | /* VIRTIO_SCSI_CONFIG_MAX_SECTORS, 32bit */ |
1796 | if (sz == 4) |
1797 | *data = (uint32_t)(dev->max_xfer); |
1798 | else if (sz == 1) { |
1799 | /* read first byte of max_xfer */ |
1800 | *data &= 0xFFFFFF00; |
1801 | *data |= (uint32_t)(dev->max_xfer) & 0xFF; |
1802 | } |
1803 | break; |
1804 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 9: |
1805 | if (sz == 1) { |
1806 | /* read second byte of max_xfer */ |
1807 | *data &= 0xFFFFFF00; |
1808 | *data |= |
1809 | (uint32_t)(dev->max_xfer >> 8) & 0xFF; |
1810 | } |
1811 | break; |
1812 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 10: |
1813 | if (sz == 1) { |
1814 | /* read third byte of max_xfer */ |
1815 | *data &= 0xFFFFFF00; |
1816 | *data |= |
1817 | (uint32_t)(dev->max_xfer >> 16) & 0xFF; |
1818 | } |
1819 | break; |
1820 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 11: |
1821 | if (sz == 1) { |
1822 | /* read fourth byte of max_xfer */ |
1823 | *data &= 0xFFFFFF00; |
1824 | *data |= |
1825 | (uint32_t)(dev->max_xfer >> 24) & 0xFF; |
1826 | } |
1827 | break; |
1828 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 12: |
1829 | /* VIRTIO_SCSI_CONFIG_CMD_PER_LUN, 32bit */ |
1830 | if (sz == 4) |
1831 | *data = (uint32_t)(VIOSCSI_CMD_PER_LUN1); |
1832 | else if (sz == 1) { |
1833 | /* read first byte of cmd_per_lun */ |
1834 | *data &= 0xFFFFFF00; |
1835 | *data |= (uint32_t)(VIOSCSI_CMD_PER_LUN1) & 0xFF; |
1836 | } |
1837 | break; |
1838 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 13: |
1839 | if (sz == 1) { |
1840 | /* read second byte of cmd_per_lun */ |
1841 | *data &= 0xFFFFFF00; |
1842 | *data |= |
1843 | (uint32_t)(VIOSCSI_CMD_PER_LUN1 >> 8) & 0xFF; |
1844 | } |
1845 | break; |
1846 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 14: |
1847 | if (sz == 1) { |
1848 | /* read third byte of cmd_per_lun */ |
1849 | *data &= 0xFFFFFF00; |
1850 | *data |= (uint32_t)(VIOSCSI_CMD_PER_LUN1 >> 16) |
1851 | & 0xFF; |
1852 | } |
1853 | break; |
1854 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 15: |
1855 | if (sz == 1) { |
1856 | /* read fourth byte of cmd_per_lun */ |
1857 | *data &= 0xFFFFFF00; |
1858 | *data |= (uint32_t)(VIOSCSI_CMD_PER_LUN1 >> 24) |
1859 | & 0xFF; |
1860 | } |
1861 | break; |
1862 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 16: |
1863 | /* VIRTIO_SCSI_CONFIG_EVENT_INFO_SIZE, 32bit */ |
1864 | *data = 0x00; |
1865 | break; |
1866 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 20: |
1867 | /* VIRTIO_SCSI_CONFIG_SENSE_SIZE, 32bit */ |
1868 | if (sz == 4) |
1869 | *data = (uint32_t)(VIOSCSI_SENSE_LEN96); |
1870 | else if (sz == 1) { |
1871 | /* read first byte of sense_size */ |
1872 | *data &= 0xFFFFFF00; |
1873 | *data |= (uint32_t)(VIOSCSI_SENSE_LEN96) & 0xFF; |
1874 | } |
1875 | break; |
1876 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 21: |
1877 | if (sz == 1) { |
1878 | /* read second byte of sense_size */ |
1879 | *data &= 0xFFFFFF00; |
1880 | *data |= |
1881 | (uint32_t)(VIOSCSI_SENSE_LEN96 >> 8) & 0xFF; |
1882 | } |
1883 | break; |
1884 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 22: |
1885 | if (sz == 1) { |
1886 | /* read third byte of sense_size */ |
1887 | *data &= 0xFFFFFF00; |
1888 | *data |= |
1889 | (uint32_t)(VIOSCSI_SENSE_LEN96 >> 16) & 0xFF; |
1890 | } |
1891 | break; |
1892 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 23: |
1893 | if (sz == 1) { |
1894 | /* read fourth byte of sense_size */ |
1895 | *data &= 0xFFFFFF00; |
1896 | *data |= |
1897 | (uint32_t)(VIOSCSI_SENSE_LEN96 >> 24) & 0xFF; |
1898 | } |
1899 | break; |
1900 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 24: |
1901 | /* VIRTIO_SCSI_CONFIG_CDB_SIZE, 32bit */ |
1902 | if (sz == 4) |
1903 | *data = (uint32_t)(VIOSCSI_CDB_LEN32); |
1904 | else if (sz == 1) { |
1905 | /* read first byte of cdb_len */ |
1906 | *data &= 0xFFFFFF00; |
1907 | *data |= (uint32_t)(VIOSCSI_CDB_LEN32) & 0xFF; |
1908 | } |
1909 | break; |
1910 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 25: |
1911 | if (sz == 1) { |
1912 | /* read second byte of cdb_len */ |
1913 | *data &= 0xFFFFFF00; |
1914 | *data |= |
1915 | (uint32_t)(VIOSCSI_CDB_LEN32 >> 8) & 0xFF; |
1916 | } |
1917 | break; |
1918 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 26: |
1919 | if (sz == 1) { |
1920 | /* read third byte of cdb_len */ |
1921 | *data &= 0xFFFFFF00; |
1922 | *data |= |
1923 | (uint32_t)(VIOSCSI_CDB_LEN32 >> 16) & 0xFF; |
1924 | } |
1925 | break; |
1926 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 27: |
1927 | if (sz == 1) { |
1928 | /* read fourth byte of cdb_len */ |
1929 | *data &= 0xFFFFFF00; |
1930 | *data |= |
1931 | (uint32_t)(VIOSCSI_CDB_LEN32 >> 24) & 0xFF; |
1932 | } |
1933 | break; |
1934 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 28: |
1935 | /* VIRTIO_SCSI_CONFIG_MAX_CHANNEL, 16bit */ |
1936 | |
1937 | /* defined by standard to be zero */ |
1938 | *data &= 0xFFFF0000; |
1939 | break; |
1940 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 29: |
1941 | /* defined by standard to be zero */ |
1942 | *data &= 0xFFFF0000; |
1943 | break; |
1944 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 30: |
1945 | /* VIRTIO_SCSI_CONFIG_MAX_TARGET, 16bit */ |
1946 | if (sz == 2) { |
1947 | *data &= 0xFFFF0000; |
1948 | *data |= |
1949 | (uint32_t)(VIOSCSI_MAX_TARGET1) & 0xFFFF; |
1950 | } else if (sz == 1) { |
1951 | /* read first byte of max_target */ |
1952 | *data &= 0xFFFFFF00; |
1953 | *data |= |
1954 | (uint32_t)(VIOSCSI_MAX_TARGET1) & 0xFF; |
1955 | } |
1956 | break; |
1957 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 31: |
1958 | if (sz == 1) { |
1959 | /* read second byte of max_target */ |
1960 | *data &= 0xFFFFFF00; |
1961 | *data |= |
1962 | (uint32_t)(VIOSCSI_MAX_TARGET1 >> 8) & 0xFF; |
1963 | } |
1964 | break; |
1965 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 32: |
1966 | /* VIRTIO_SCSI_CONFIG_MAX_LUN, 32bit */ |
1967 | if (sz == 4) |
1968 | *data = (uint32_t)(VIOSCSI_MAX_LUN1); |
1969 | else if (sz == 1) { |
1970 | /* read first byte of max_lun */ |
1971 | *data &= 0xFFFFFF00; |
1972 | *data |= (uint32_t)(VIOSCSI_MAX_LUN1) & 0xFF; |
1973 | } |
1974 | break; |
1975 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 33: |
1976 | if (sz == 1) { |
1977 | /* read second byte of max_lun */ |
1978 | *data &= 0xFFFFFF00; |
1979 | *data |= |
1980 | (uint32_t)(VIOSCSI_MAX_LUN1 >> 8) & 0xFF; |
1981 | } |
1982 | break; |
1983 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 34: |
1984 | if (sz == 1) { |
1985 | /* read third byte of max_lun */ |
1986 | *data &= 0xFFFFFF00; |
1987 | *data |= |
1988 | (uint32_t)(VIOSCSI_MAX_LUN1 >> 16) & 0xFF; |
1989 | } |
1990 | break; |
1991 | case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI20 + 35: |
1992 | if (sz == 1) { |
1993 | /* read fourth byte of max_lun */ |
1994 | *data &= 0xFFFFFF00; |
1995 | *data |= |
1996 | (uint32_t)(VIOSCSI_MAX_LUN1 >> 24) & 0xFF; |
1997 | } |
1998 | break; |
1999 | case VIRTIO_CONFIG_DEVICE_FEATURES0: |
2000 | *data = dev->cfg.device_feature; |
2001 | break; |
2002 | case VIRTIO_CONFIG_GUEST_FEATURES4: |
2003 | *data = dev->cfg.guest_feature; |
2004 | break; |
2005 | case VIRTIO_CONFIG_QUEUE_ADDRESS8: |
2006 | *data = dev->cfg.queue_address; |
2007 | break; |
2008 | case VIRTIO_CONFIG_QUEUE_SIZE12: |
2009 | if (sz == 4) |
2010 | *data = dev->cfg.queue_size; |
2011 | else if (sz == 2) { |
2012 | *data &= 0xFFFF0000; |
2013 | *data |= (uint16_t)dev->cfg.queue_size; |
2014 | } else if (sz == 1) { |
2015 | *data &= 0xFFFFFF00; |
2016 | *data |= (uint8_t)dev->cfg.queue_size; |
2017 | } |
2018 | break; |
2019 | case VIRTIO_CONFIG_QUEUE_SELECT14: |
2020 | *data = dev->cfg.queue_select; |
2021 | break; |
2022 | case VIRTIO_CONFIG_QUEUE_NOTIFY16: |
2023 | *data = dev->cfg.queue_notify; |
2024 | break; |
2025 | case VIRTIO_CONFIG_DEVICE_STATUS18: |
2026 | if (sz == 4) |
2027 | *data = dev->cfg.device_status; |
2028 | else if (sz == 2) { |
2029 | *data &= 0xFFFF0000; |
2030 | *data |= (uint16_t)dev->cfg.device_status; |
2031 | } else if (sz == 1) { |
2032 | *data &= 0xFFFFFF00; |
2033 | *data |= (uint8_t)dev->cfg.device_status; |
2034 | } |
2035 | break; |
2036 | case VIRTIO_CONFIG_ISR_STATUS19: |
2037 | *data = dev->cfg.isr_status; |
2038 | dev->cfg.isr_status = 0; |
2039 | break; |
2040 | } |
2041 | } |
2042 | |
2043 | |
2044 | return (0); |
2045 | } |
2046 | |
2047 | void |
2048 | vioscsi_update_qs(struct vioscsi_dev *dev) |
2049 | { |
2050 | /* Invalid queue? */ |
2051 | if (dev->cfg.queue_select >= VIRTIO_MAX_QUEUES3) { |
2052 | dev->cfg.queue_size = 0; |
2053 | return; |
2054 | } |
2055 | |
2056 | /* Update queue address/size based on queue select */ |
2057 | dev->cfg.queue_address = dev->vq[dev->cfg.queue_select].qa; |
2058 | dev->cfg.queue_size = dev->vq[dev->cfg.queue_select].qs; |
2059 | } |
2060 | |
2061 | void |
2062 | vioscsi_update_qa(struct vioscsi_dev *dev) |
2063 | { |
2064 | /* Invalid queue? */ |
2065 | if (dev->cfg.queue_select >= VIRTIO_MAX_QUEUES3) |
2066 | return; |
2067 | |
2068 | dev->vq[dev->cfg.queue_select].qa = dev->cfg.queue_address; |
2069 | } |
2070 | |
2071 | /* |
2072 | * Process message(s) in the queue(s) |
2073 | * vioscsi driver will be placing the following in the queue for each iteration |
2074 | * virtio_scsi_req_hdr with a possible SCSI_DATA_OUT buffer |
2075 | * along with a virtio_scsi_res_hdr with a possible SCSI_DATA_IN buffer |
2076 | * for consumption. |
2077 | * |
2078 | * Return 1 if an interrupt should be generated (response written) |
2079 | * 0 otherwise |
2080 | */ |
2081 | int |
2082 | vioscsi_notifyq(struct vioscsi_dev *dev) |
2083 | { |
2084 | uint64_t q_gpa; |
2085 | uint32_t vr_sz; |
2086 | int cnt, ret; |
2087 | char *vr; |
2088 | struct virtio_scsi_req_hdr req; |
2089 | struct virtio_scsi_res_hdr resp; |
2090 | struct virtio_vq_acct acct; |
2091 | |
2092 | ret = 0; |
2093 | |
2094 | /* Invalid queue? */ |
2095 | if (dev->cfg.queue_notify >= VIRTIO_MAX_QUEUES3) |
2096 | return (ret); |
2097 | |
2098 | vr_sz = vring_size(VIOSCSI_QUEUE_SIZE128); |
2099 | q_gpa = dev->vq[dev->cfg.queue_notify].qa; |
2100 | q_gpa = q_gpa * VIRTIO_PAGE_SIZE(4096); |
2101 | |
2102 | vr = calloc(1, vr_sz); |
2103 | if (vr == NULL((void *)0)) { |
2104 | log_warn("%s: calloc error getting vioscsi ring", __func__); |
2105 | return (ret); |
2106 | } |
2107 | |
2108 | if (read_mem(q_gpa, vr, vr_sz)) { |
2109 | log_warnx("%s: error reading gpa 0x%llx", __func__, q_gpa); |
2110 | goto out; |
2111 | } |
2112 | |
2113 | /* Compute offsets in ring of descriptors, avail ring, and used ring */ |
2114 | acct.desc = (struct vring_desc *)(vr); |
2115 | acct.avail = (struct vring_avail *)(vr + |
2116 | dev->vq[dev->cfg.queue_notify].vq_availoffset); |
2117 | acct.used = (struct vring_used *)(vr + |
2118 | dev->vq[dev->cfg.queue_notify].vq_usedoffset); |
2119 | |
2120 | acct.idx = |
2121 | dev->vq[dev->cfg.queue_notify].last_avail & VIOSCSI_QUEUE_MASK(128 - 1); |
2122 | |
2123 | if ((acct.avail->idx & VIOSCSI_QUEUE_MASK(128 - 1)) == acct.idx) { |
2124 | log_warnx("%s:nothing to do?", __func__); |
2125 | goto out; |
2126 | } |
2127 | |
2128 | cnt = 0; |
2129 | while (acct.idx != (acct.avail->idx & VIOSCSI_QUEUE_MASK(128 - 1))) { |
2130 | |
2131 | /* Guard against infinite descriptor chains */ |
2132 | if (++cnt >= VIOSCSI_QUEUE_SIZE128) { |
2133 | log_warnx("%s: invalid descriptor table", __func__); |
2134 | goto out; |
2135 | } |
2136 | |
2137 | acct.req_idx = acct.avail->ring[acct.idx] & VIOSCSI_QUEUE_MASK(128 - 1); |
2138 | acct.req_desc = &(acct.desc[acct.req_idx]); |
2139 | |
2140 | /* Clear resp for next message */ |
2141 | memset(&resp, 0, sizeof(resp)); |
2142 | |
2143 | if ((acct.req_desc->flags & VRING_DESC_F_NEXT1) == 0) { |
2144 | log_warnx("%s: unchained req descriptor received " |
2145 | "(idx %d)", __func__, acct.req_idx); |
2146 | goto out; |
2147 | } |
2148 | |
2149 | /* Read command from descriptor ring */ |
2150 | if (read_mem(acct.req_desc->addr, &req, sizeof(req))) { |
2151 | log_warnx("%s: command read_mem error @ 0x%llx", |
2152 | __func__, acct.req_desc->addr); |
2153 | goto out; |
2154 | } |
2155 | |
2156 | /* |
2157 | * req.lun is defined by virtio as |
2158 | * lun[0] - Always set to 1 |
2159 | * lun[1] - Target, negotiated as VIOSCSI_MAX_TARGET |
2160 | * lun[2-3] - represent single level LUN structure |
2161 | * lun[4-7] - Zero |
2162 | * At this current time, we are only servicing one device per |
2163 | * bus (1:0:X:0). |
2164 | * |
2165 | * Various implementations will attempt to scan all possible |
2166 | * targets (256) looking for devices or scan for all possible |
2167 | * LUNs in a single level. When Target is greater than |
2168 | * VIOSCSI_MAX_TARGET or when lun[3] is greater than zero, |
2169 | * respond with a BAD_TARGET response. |
2170 | */ |
2171 | if (req.lun[1] >= VIOSCSI_MAX_TARGET1 || req.lun[3] > 0) { |
2172 | DPRINTF("%s: Ignore CMD 0x%02x,%s on lun %u:%u:%u:%u",do {} while(0) |
2173 | __func__, req.cdb[0], vioscsi_op_names(req.cdb[0]),do {} while(0) |
2174 | req.lun[0], req.lun[1], req.lun[2], req.lun[3])do {} while(0); |
2175 | /* Move index for response */ |
2176 | acct.resp_desc = vioscsi_next_ring_desc(acct.desc, |
2177 | acct.req_desc, &(acct.resp_idx)); |
2178 | |
2179 | vioscsi_prepare_resp(&resp, |
2180 | VIRTIO_SCSI_S_BAD_TARGET3, SCSI_OK0x00, 0, 0, 0); |
2181 | |
2182 | if (acct.resp_desc->len > sizeof(resp)) { |
2183 | log_warnx("%s: invalid descriptor length", |
2184 | __func__); |
2185 | goto out; |
2186 | } |
2187 | if (write_mem(acct.resp_desc->addr, &resp, |
2188 | sizeof(resp))) { |
2189 | log_warnx("%s: unable to write BAD_TARGET" |
2190 | " resp status data @ 0x%llx", |
2191 | __func__, acct.resp_desc->addr); |
2192 | goto out; |
2193 | } |
2194 | |
2195 | ret = 1; |
2196 | dev->cfg.isr_status = 1; |
2197 | /* Move ring indexes */ |
2198 | vioscsi_next_ring_item(dev, acct.avail, acct.used, |
2199 | acct.req_desc, acct.req_idx); |
2200 | |
2201 | if (write_mem(q_gpa, vr, vr_sz)) { |
2202 | log_warnx("%s: error writing vioring", |
2203 | __func__); |
2204 | } |
2205 | goto next_msg; |
2206 | } |
2207 | |
2208 | DPRINTF("%s: Queue %d id 0x%llx lun %u:%u:%u:%u"do {} while(0) |
2209 | " cdb OP 0x%02x,%s",do {} while(0) |
2210 | __func__, dev->cfg.queue_notify, req.id,do {} while(0) |
2211 | req.lun[0], req.lun[1], req.lun[2], req.lun[3],do {} while(0) |
2212 | req.cdb[0], vioscsi_op_names(req.cdb[0]))do {} while(0); |
2213 | |
2214 | /* opcode is first byte */ |
2215 | switch (req.cdb[0]) { |
2216 | case TEST_UNIT_READY0x00: |
2217 | case START_STOP0x1b: |
2218 | ret = vioscsi_handle_tur(dev, &req, &acct); |
2219 | if (ret) { |
2220 | if (write_mem(q_gpa, vr, vr_sz)) { |
2221 | log_warnx("%s: error writing vioring", |
2222 | __func__); |
2223 | } |
2224 | } |
2225 | break; |
2226 | case PREVENT_ALLOW0x1e: |
2227 | ret = vioscsi_handle_prevent_allow(dev, &req, &acct); |
2228 | if (ret) { |
2229 | if (write_mem(q_gpa, vr, vr_sz)) { |
2230 | log_warnx("%s: error writing vioring", |
2231 | __func__); |
2232 | } |
2233 | } |
2234 | break; |
2235 | case READ_TOC0x43: |
2236 | ret = vioscsi_handle_read_toc(dev, &req, &acct); |
2237 | if (ret) { |
2238 | if (write_mem(q_gpa, vr, vr_sz)) { |
2239 | log_warnx("%s: error writing vioring", |
2240 | __func__); |
2241 | } |
2242 | } |
2243 | break; |
2244 | case READ_CAPACITY0x25: |
2245 | ret = vioscsi_handle_read_capacity(dev, &req, &acct); |
2246 | if (ret) { |
2247 | if (write_mem(q_gpa, vr, vr_sz)) { |
2248 | log_warnx("%s: error writing vioring", |
2249 | __func__); |
2250 | } |
2251 | } |
2252 | break; |
2253 | case READ_CAPACITY_160x9e: |
2254 | ret = vioscsi_handle_read_capacity_16(dev, &req, &acct); |
2255 | if (ret) { |
2256 | if (write_mem(q_gpa, vr, vr_sz)) { |
2257 | log_warnx("%s: error writing vioring", |
2258 | __func__); |
2259 | } |
2260 | } |
2261 | break; |
2262 | case READ_COMMAND0x08: |
2263 | ret = vioscsi_handle_read_6(dev, &req, &acct); |
2264 | if (ret) { |
2265 | if (write_mem(q_gpa, vr, vr_sz)) { |
2266 | log_warnx("%s: error writing vioring", |
2267 | __func__); |
2268 | } |
2269 | } |
2270 | break; |
2271 | case READ_100x28: |
2272 | ret = vioscsi_handle_read_10(dev, &req, &acct); |
2273 | if (ret) { |
2274 | if (write_mem(q_gpa, vr, vr_sz)) { |
2275 | log_warnx("%s: error writing vioring", |
2276 | __func__); |
2277 | } |
2278 | } |
2279 | break; |
2280 | case INQUIRY0x12: |
2281 | ret = vioscsi_handle_inquiry(dev, &req, &acct); |
2282 | if (ret) { |
2283 | if (write_mem(q_gpa, vr, vr_sz)) { |
2284 | log_warnx("%s: error writing vioring", |
2285 | __func__); |
2286 | } |
2287 | } |
2288 | break; |
2289 | case MODE_SENSE0x1a: |
2290 | ret = vioscsi_handle_mode_sense(dev, &req, &acct); |
2291 | if (ret) { |
2292 | if (write_mem(q_gpa, vr, vr_sz)) { |
2293 | log_warnx("%s: error writing vioring", |
2294 | __func__); |
2295 | } |
2296 | } |
2297 | break; |
2298 | case MODE_SENSE_BIG0x5a: |
2299 | ret = vioscsi_handle_mode_sense_big(dev, &req, &acct); |
2300 | if (ret) { |
2301 | if (write_mem(q_gpa, vr, vr_sz)) { |
2302 | log_warnx("%s: error writing vioring", |
2303 | __func__); |
2304 | } |
2305 | } |
2306 | break; |
2307 | case GET_EVENT_STATUS_NOTIFICATION0x4a: |
2308 | ret = vioscsi_handle_gesn(dev, &req, &acct); |
2309 | if (ret) { |
2310 | if (write_mem(q_gpa, vr, vr_sz)) { |
2311 | log_warnx("%s: error writing vioring", |
2312 | __func__); |
2313 | } |
2314 | } |
2315 | break; |
2316 | case READ_DISC_INFORMATION0x51: |
2317 | ret = vioscsi_handle_read_disc_info(dev, &req, &acct); |
2318 | if (ret) { |
2319 | if (write_mem(q_gpa, vr, vr_sz)) { |
2320 | log_warnx("%s: error writing vioring", |
2321 | __func__); |
2322 | } |
2323 | } |
2324 | break; |
2325 | case GET_CONFIGURATION0x46: |
2326 | ret = vioscsi_handle_get_config(dev, &req, &acct); |
2327 | if (ret) { |
2328 | if (write_mem(q_gpa, vr, vr_sz)) { |
2329 | log_warnx("%s: error writing vioring", |
2330 | __func__); |
2331 | } |
2332 | } |
2333 | break; |
2334 | case MECHANISM_STATUS0xbd: |
2335 | ret = vioscsi_handle_mechanism_status(dev, &req, &acct); |
2336 | if (ret) { |
2337 | if (write_mem(q_gpa, vr, vr_sz)) { |
2338 | log_warnx("%s: error writing vioring", |
2339 | __func__); |
2340 | } |
2341 | } |
2342 | break; |
2343 | case REPORT_LUNS0xa0: |
2344 | ret = vioscsi_handle_report_luns(dev, &req, &acct); |
2345 | if (ret) { |
2346 | if (write_mem(q_gpa, vr, vr_sz)) { |
2347 | log_warnx("%s: error writing vioring", |
2348 | __func__); |
2349 | } |
2350 | } |
2351 | break; |
2352 | default: |
2353 | log_warnx("%s: unsupported opcode 0x%02x,%s", |
2354 | __func__, req.cdb[0], vioscsi_op_names(req.cdb[0])); |
2355 | /* Move ring indexes */ |
2356 | vioscsi_next_ring_item(dev, acct.avail, acct.used, |
2357 | acct.req_desc, acct.req_idx); |
2358 | break; |
2359 | } |
2360 | next_msg: |
2361 | /* Increment to the next queue slot */ |
2362 | acct.idx = (acct.idx + 1) & VIOSCSI_QUEUE_MASK(128 - 1); |
2363 | } |
2364 | out: |
2365 | free(vr); |
2366 | return (ret); |
2367 | } |