Bug Summary

File:src/usr.sbin/vmd/vioscsi.c
Warning:line 494, column 2
Value stored to 'mode_sense_len' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name vioscsi.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/vmd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/vmd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/vmd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/vmd/vioscsi.c
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
37extern char *__progname;
38
39static void
40vioscsi_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
70static struct vring_desc*
71vioscsi_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
78static void
79vioscsi_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
90static const char *
91vioscsi_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
154static const char *
155vioscsi_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
180static void
181vioscsi_free_info(struct ioinfo *info)
182{
183 if (!info)
184 return;
185 free(info->buf);
186 free(info);
187}
188
189static struct ioinfo *
190vioscsi_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
212nomem:
213 free(info);
214 log_warn("malloc error vioscsi read");
215 return (NULL((void *)0));
216}
217
218static const uint8_t *
219vioscsi_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
233static int
234vioscsi_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
261static int
262vioscsi_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);
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
333free_inq:
334 free(inq_data);
335inq_out:
336 return (ret);
337}
338
339static int
340vioscsi_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 {
451mode_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 }
473mode_sense_out:
474 return (ret);
475}
476
477static int
478vioscsi_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);
Value stored to 'mode_sense_len' is never read
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 {
591mode_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 }
613mode_sense_big_out:
614 return (ret);
615}
616
617static int
618vioscsi_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
700free_read_capacity:
701 free(r_cap_data);
702read_capacity_out:
703 return (ret);
704}
705
706static int
707vioscsi_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
775free_read_capacity_16:
776 free(r_cap_data_16);
777read_capacity_16_out:
778 return (ret);
779}
780
781static int
782vioscsi_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
874free_rpl:
875 free(reply_rpl);
876rpl_out:
877 return (ret);
878}
879
880static int
881vioscsi_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
999free_read_6:
1000 vioscsi_free_info(info);
1001read_6_out:
1002 return (ret);
1003}
1004
1005static int
1006vioscsi_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
1146free_read_10:
1147 vioscsi_free_info(info);
1148read_10_out:
1149 return (ret);
1150}
1151
1152static int
1153vioscsi_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
1188static int
1189vioscsi_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
1241free_mech:
1242 free(mech_status_header);
1243mech_out:
1244 return (ret);
1245}
1246
1247static int
1248vioscsi_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
1383read_toc_out:
1384 return (ret);
1385}
1386
1387static int
1388vioscsi_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
1423static int
1424vioscsi_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
1514gesn_out:
1515 return (ret);
1516}
1517
1518static int
1519vioscsi_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
1659free_get_config:
1660 free(get_conf_reply);
1661get_config_out:
1662 return (ret);
1663}
1664
1665int
1666vioscsi_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
2047void
2048vioscsi_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
2061void
2062vioscsi_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 */
2081int
2082vioscsi_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 }
2360next_msg:
2361 /* Increment to the next queue slot */
2362 acct.idx = (acct.idx + 1) & VIOSCSI_QUEUE_MASK(128 - 1);
2363 }
2364out:
2365 free(vr);
2366 return (ret);
2367}