Revision b45ef674
b/hw/scsi-bus.c | ||
---|---|---|
7 | 7 |
#include "trace.h" |
8 | 8 |
|
9 | 9 |
static char *scsibus_get_fw_dev_path(DeviceState *dev); |
10 |
static int scsi_build_sense(uint8_t *in_buf, int in_len, |
|
11 |
uint8_t *buf, int len, bool fixed); |
|
10 | 12 |
|
11 | 13 |
static struct BusInfo scsi_bus_info = { |
12 | 14 |
.name = "SCSI", |
... | ... | |
144 | 146 |
req->lun = lun; |
145 | 147 |
req->hba_private = hba_private; |
146 | 148 |
req->status = -1; |
149 |
req->sense_len = 0; |
|
147 | 150 |
trace_scsi_req_alloc(req->dev->id, req->lun, req->tag); |
148 | 151 |
return req; |
149 | 152 |
} |
... | ... | |
161 | 164 |
|
162 | 165 |
int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) |
163 | 166 |
{ |
164 |
if (req->dev->info->get_sense) { |
|
165 |
return req->dev->info->get_sense(req, buf, len); |
|
166 |
} else { |
|
167 |
assert(len >= 14); |
|
168 |
if (!req->sense_len) { |
|
167 | 169 |
return 0; |
168 | 170 |
} |
171 |
return scsi_build_sense(req->sense, req->sense_len, buf, len, true); |
|
172 |
} |
|
173 |
|
|
174 |
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed) |
|
175 |
{ |
|
176 |
return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed); |
|
177 |
} |
|
178 |
|
|
179 |
void scsi_req_build_sense(SCSIRequest *req, SCSISense sense) |
|
180 |
{ |
|
181 |
trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag, |
|
182 |
sense.key, sense.asc, sense.ascq); |
|
183 |
memset(req->sense, 0, 18); |
|
184 |
req->sense[0] = 0xf0; |
|
185 |
req->sense[2] = sense.key; |
|
186 |
req->sense[12] = sense.asc; |
|
187 |
req->sense[13] = sense.ascq; |
|
188 |
req->sense_len = 18; |
|
169 | 189 |
} |
170 | 190 |
|
171 | 191 |
int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf) |
... | ... | |
484 | 504 |
/* |
485 | 505 |
* scsi_build_sense |
486 | 506 |
* |
487 |
* Build a sense buffer
|
|
507 |
* Convert between fixed and descriptor sense buffers
|
|
488 | 508 |
*/ |
489 |
int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed) |
|
509 |
int scsi_build_sense(uint8_t *in_buf, int in_len, |
|
510 |
uint8_t *buf, int len, bool fixed) |
|
490 | 511 |
{ |
512 |
bool fixed_in; |
|
513 |
SCSISense sense; |
|
491 | 514 |
if (!fixed && len < 8) { |
492 | 515 |
return 0; |
493 | 516 |
} |
494 | 517 |
|
518 |
if (in_len == 0) { |
|
519 |
sense.key = NO_SENSE; |
|
520 |
sense.asc = 0; |
|
521 |
sense.ascq = 0; |
|
522 |
} else { |
|
523 |
fixed_in = (in_buf[0] & 2) == 0; |
|
524 |
|
|
525 |
if (fixed == fixed_in) { |
|
526 |
memcpy(buf, in_buf, MIN(len, in_len)); |
|
527 |
return MIN(len, in_len); |
|
528 |
} |
|
529 |
|
|
530 |
if (fixed_in) { |
|
531 |
sense.key = in_buf[2]; |
|
532 |
sense.asc = in_buf[12]; |
|
533 |
sense.ascq = in_buf[13]; |
|
534 |
} else { |
|
535 |
sense.key = in_buf[1]; |
|
536 |
sense.asc = in_buf[2]; |
|
537 |
sense.ascq = in_buf[3]; |
|
538 |
} |
|
539 |
} |
|
540 |
|
|
495 | 541 |
memset(buf, 0, len); |
496 | 542 |
if (fixed) { |
497 | 543 |
/* Return fixed format sense buffer */ |
... | ... | |
686 | 732 |
{ |
687 | 733 |
assert(req->status == -1); |
688 | 734 |
req->status = status; |
735 |
|
|
736 |
assert(req->sense_len < sizeof(req->sense)); |
|
737 |
if (status == GOOD) { |
|
738 |
req->sense_len = 0; |
|
739 |
} |
|
740 |
|
|
741 |
if (req->sense_len) { |
|
742 |
memcpy(req->dev->sense, req->sense, req->sense_len); |
|
743 |
} |
|
744 |
req->dev->sense_len = req->sense_len; |
|
745 |
|
|
689 | 746 |
scsi_req_ref(req); |
690 | 747 |
scsi_req_dequeue(req); |
691 | 748 |
req->bus->ops->complete(req, req->status); |
b/hw/scsi-disk.c | ||
---|---|---|
71 | 71 |
QEMUBH *bh; |
72 | 72 |
char *version; |
73 | 73 |
char *serial; |
74 |
SCSISense sense; |
|
75 | 74 |
}; |
76 | 75 |
|
77 | 76 |
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); |
... | ... | |
97 | 96 |
qemu_vfree(r->iov.iov_base); |
98 | 97 |
} |
99 | 98 |
|
100 |
static void scsi_disk_clear_sense(SCSIDiskState *s) |
|
99 |
/* Helper function for command completion with sense. */ |
|
100 |
static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense) |
|
101 | 101 |
{ |
102 |
memset(&s->sense, 0, sizeof(s->sense)); |
|
103 |
} |
|
104 |
|
|
105 |
/* Helper function for command completion. */ |
|
106 |
static void scsi_command_complete(SCSIDiskReq *r, int status, SCSISense sense) |
|
107 |
{ |
|
108 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
|
109 |
|
|
110 | 102 |
DPRINTF("Command complete tag=0x%x status=%d sense=%d/%d/%d\n", |
111 | 103 |
r->req.tag, status, sense.key, sense.asc, sense.ascq); |
112 |
s->sense = sense;
|
|
113 |
scsi_req_complete(&r->req, status);
|
|
104 |
scsi_req_build_sense(&r->req, sense);
|
|
105 |
scsi_req_complete(&r->req, CHECK_CONDITION);
|
|
114 | 106 |
} |
115 | 107 |
|
116 | 108 |
/* Cancel a pending data transfer. */ |
... | ... | |
162 | 154 |
} |
163 | 155 |
DPRINTF("Read sector_count=%d\n", r->sector_count); |
164 | 156 |
if (r->sector_count == 0) { |
165 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE)); |
|
157 |
/* This also clears the sense buffer for REQUEST SENSE. */ |
|
158 |
scsi_req_complete(&r->req, GOOD); |
|
166 | 159 |
return; |
167 | 160 |
} |
168 | 161 |
|
... | ... | |
210 | 203 |
} else { |
211 | 204 |
switch (error) { |
212 | 205 |
case ENOMEM: |
213 |
scsi_command_complete(r, CHECK_CONDITION, |
|
214 |
SENSE_CODE(TARGET_FAILURE)); |
|
206 |
scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE)); |
|
215 | 207 |
break; |
216 | 208 |
case EINVAL: |
217 |
scsi_command_complete(r, CHECK_CONDITION, |
|
218 |
SENSE_CODE(INVALID_FIELD)); |
|
209 |
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); |
|
219 | 210 |
break; |
220 | 211 |
default: |
221 |
scsi_command_complete(r, CHECK_CONDITION, |
|
222 |
SENSE_CODE(IO_ERROR)); |
|
212 |
scsi_check_condition(r, SENSE_CODE(IO_ERROR)); |
|
223 | 213 |
break; |
224 | 214 |
} |
225 | 215 |
bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read); |
... | ... | |
245 | 235 |
r->sector += n; |
246 | 236 |
r->sector_count -= n; |
247 | 237 |
if (r->sector_count == 0) { |
248 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
238 |
scsi_req_complete(&r->req, GOOD);
|
|
249 | 239 |
} else { |
250 | 240 |
len = r->sector_count * 512; |
251 | 241 |
if (len > SCSI_DMA_BUF_SIZE) { |
... | ... | |
314 | 304 |
case SCSI_REQ_STATUS_RETRY_FLUSH: |
315 | 305 |
ret = scsi_disk_emulate_command(r, r->iov.iov_base); |
316 | 306 |
if (ret == 0) { |
317 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
307 |
scsi_req_complete(&r->req, GOOD);
|
|
318 | 308 |
} |
319 | 309 |
} |
320 | 310 |
} |
... | ... | |
342 | 332 |
return (uint8_t *)r->iov.iov_base; |
343 | 333 |
} |
344 | 334 |
|
345 |
/* Copy sense information into the provided buffer */ |
|
346 |
static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len) |
|
347 |
{ |
|
348 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); |
|
349 |
|
|
350 |
return scsi_build_sense(s->sense, outbuf, len, len > 14); |
|
351 |
} |
|
352 |
|
|
353 | 335 |
static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) |
354 | 336 |
{ |
355 | 337 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); |
... | ... | |
827 | 809 |
case REQUEST_SENSE: |
828 | 810 |
if (req->cmd.xfer < 4) |
829 | 811 |
goto illegal_request; |
830 |
buflen = scsi_build_sense(s->sense, outbuf, req->cmd.xfer, |
|
831 |
req->cmd.xfer > 13); |
|
832 |
scsi_disk_clear_sense(s); |
|
812 |
buflen = scsi_device_get_sense(&s->qdev, outbuf, req->cmd.xfer, |
|
813 |
(req->cmd.buf[1] & 1) == 0); |
|
833 | 814 |
break; |
834 | 815 |
case INQUIRY: |
835 | 816 |
buflen = scsi_disk_emulate_inquiry(req, outbuf); |
... | ... | |
960 | 941 |
case VERIFY_10: |
961 | 942 |
break; |
962 | 943 |
default: |
963 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
|
|
944 |
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
|
964 | 945 |
return -1; |
965 | 946 |
} |
966 | 947 |
return buflen; |
967 | 948 |
|
968 | 949 |
not_ready: |
969 | 950 |
if (!bdrv_is_inserted(s->bs)) { |
970 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(NO_MEDIUM));
|
|
951 |
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
|
|
971 | 952 |
} else { |
972 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LUN_NOT_READY));
|
|
953 |
scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
|
|
973 | 954 |
} |
974 | 955 |
return -1; |
975 | 956 |
|
976 | 957 |
illegal_request: |
977 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
|
|
958 |
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
|
978 | 959 |
return -1; |
979 | 960 |
} |
980 | 961 |
|
... | ... | |
998 | 979 |
|
999 | 980 |
if (scsi_req_parse(&r->req, buf) != 0) { |
1000 | 981 |
BADF("Unsupported command length, command %x\n", command); |
1001 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
|
|
982 |
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
|
1002 | 983 |
return 0; |
1003 | 984 |
} |
1004 | 985 |
#ifdef DEBUG_SCSI |
... | ... | |
1015 | 996 |
/* Only LUN 0 supported. */ |
1016 | 997 |
DPRINTF("Unimplemented LUN %d\n", req->lun); |
1017 | 998 |
if (command != REQUEST_SENSE && command != INQUIRY) { |
1018 |
scsi_command_complete(r, CHECK_CONDITION, |
|
1019 |
SENSE_CODE(LUN_NOT_SUPPORTED)); |
|
999 |
scsi_check_condition(r, SENSE_CODE(LUN_NOT_SUPPORTED)); |
|
1020 | 1000 |
return 0; |
1021 | 1001 |
} |
1022 | 1002 |
} |
... | ... | |
1124 | 1104 |
break; |
1125 | 1105 |
default: |
1126 | 1106 |
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); |
1127 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
|
|
1107 |
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
|
1128 | 1108 |
return 0; |
1129 | 1109 |
fail: |
1130 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
|
|
1110 |
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
|
1131 | 1111 |
return 0; |
1132 | 1112 |
illegal_lba: |
1133 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE));
|
|
1113 |
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
|
1134 | 1114 |
return 0; |
1135 | 1115 |
} |
1136 | 1116 |
if (r->sector_count == 0 && r->iov.iov_len == 0) { |
1137 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
1117 |
scsi_req_complete(&r->req, GOOD);
|
|
1138 | 1118 |
} |
1139 | 1119 |
len = r->sector_count * 512 + r->iov.iov_len; |
1140 | 1120 |
if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { |
... | ... | |
1266 | 1246 |
.write_data = scsi_write_data, |
1267 | 1247 |
.cancel_io = scsi_cancel_io, |
1268 | 1248 |
.get_buf = scsi_get_buf, |
1269 |
.get_sense = scsi_get_sense, |
|
1270 | 1249 |
.qdev.props = (Property[]) { |
1271 | 1250 |
DEFINE_SCSI_DISK_PROPERTIES(), |
1272 | 1251 |
DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), |
... | ... | |
1287 | 1266 |
.write_data = scsi_write_data, |
1288 | 1267 |
.cancel_io = scsi_cancel_io, |
1289 | 1268 |
.get_buf = scsi_get_buf, |
1290 |
.get_sense = scsi_get_sense, |
|
1291 | 1269 |
.qdev.props = (Property[]) { |
1292 | 1270 |
DEFINE_SCSI_DISK_PROPERTIES(), |
1293 | 1271 |
DEFINE_PROP_END_OF_LIST(), |
... | ... | |
1307 | 1285 |
.write_data = scsi_write_data, |
1308 | 1286 |
.cancel_io = scsi_cancel_io, |
1309 | 1287 |
.get_buf = scsi_get_buf, |
1310 |
.get_sense = scsi_get_sense, |
|
1311 | 1288 |
.qdev.props = (Property[]) { |
1312 | 1289 |
DEFINE_SCSI_DISK_PROPERTIES(), |
1313 | 1290 |
DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), |
b/hw/scsi-generic.c | ||
---|---|---|
61 | 61 |
SCSIDevice qdev; |
62 | 62 |
BlockDriverState *bs; |
63 | 63 |
int lun; |
64 |
int driver_status; |
|
65 |
uint8_t sensebuf[SCSI_SENSE_BUF_SIZE]; |
|
66 |
uint8_t senselen; |
|
67 | 64 |
}; |
68 | 65 |
|
69 |
static void scsi_set_sense(SCSIGenericState *s, SCSISense sense) |
|
70 |
{ |
|
71 |
s->senselen = scsi_build_sense(sense, s->sensebuf, SCSI_SENSE_BUF_SIZE, 0); |
|
72 |
s->driver_status = SG_ERR_DRIVER_SENSE; |
|
73 |
} |
|
74 |
|
|
75 |
static void scsi_clear_sense(SCSIGenericState *s) |
|
76 |
{ |
|
77 |
memset(s->sensebuf, 0, SCSI_SENSE_BUF_SIZE); |
|
78 |
s->senselen = 0; |
|
79 |
s->driver_status = 0; |
|
80 |
} |
|
81 |
|
|
82 |
static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len) |
|
83 |
{ |
|
84 |
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev); |
|
85 |
int size = SCSI_SENSE_BUF_SIZE; |
|
86 |
|
|
87 |
if (!(s->driver_status & SG_ERR_DRIVER_SENSE)) { |
|
88 |
size = scsi_build_sense(SENSE_CODE(NO_SENSE), s->sensebuf, |
|
89 |
SCSI_SENSE_BUF_SIZE, 0); |
|
90 |
} |
|
91 |
if (size > len) { |
|
92 |
size = len; |
|
93 |
} |
|
94 |
memcpy(outbuf, s->sensebuf, size); |
|
95 |
|
|
96 |
return size; |
|
97 |
} |
|
98 |
|
|
99 | 66 |
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, |
100 | 67 |
void *hba_private) |
101 | 68 |
{ |
... | ... | |
117 | 84 |
{ |
118 | 85 |
int status; |
119 | 86 |
SCSIGenericReq *r = (SCSIGenericReq *)opaque; |
120 |
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); |
|
121 | 87 |
|
122 | 88 |
r->req.aiocb = NULL; |
123 |
s->driver_status = r->io_header.driver_status; |
|
124 |
if (s->driver_status & SG_ERR_DRIVER_SENSE) |
|
125 |
s->senselen = r->io_header.sb_len_wr; |
|
89 |
if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) |
|
90 |
r->req.sense_len = r->io_header.sb_len_wr; |
|
126 | 91 |
|
127 | 92 |
if (ret != 0) { |
128 | 93 |
switch (ret) { |
... | ... | |
131 | 96 |
break; |
132 | 97 |
case -EINVAL: |
133 | 98 |
status = CHECK_CONDITION; |
134 |
scsi_set_sense(s, SENSE_CODE(INVALID_FIELD));
|
|
99 |
scsi_req_build_sense(&r->req, SENSE_CODE(INVALID_FIELD));
|
|
135 | 100 |
break; |
136 | 101 |
case -ENOMEM: |
137 | 102 |
status = CHECK_CONDITION; |
138 |
scsi_set_sense(s, SENSE_CODE(TARGET_FAILURE));
|
|
103 |
scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
|
|
139 | 104 |
break; |
140 | 105 |
default: |
141 | 106 |
status = CHECK_CONDITION; |
142 |
scsi_set_sense(s, SENSE_CODE(IO_ERROR));
|
|
107 |
scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
|
|
143 | 108 |
break; |
144 | 109 |
} |
145 | 110 |
} else { |
146 |
if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
|
111 |
if (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
|
147 | 112 |
status = BUSY; |
148 | 113 |
BADF("Driver Timeout\n"); |
149 | 114 |
} else if (r->io_header.status) { |
150 | 115 |
status = r->io_header.status; |
151 |
} else if (s->driver_status & SG_ERR_DRIVER_SENSE) {
|
|
116 |
} else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
|
|
152 | 117 |
status = CHECK_CONDITION; |
153 | 118 |
} else { |
154 | 119 |
status = GOOD; |
... | ... | |
176 | 141 |
SCSIGenericReq *r, int direction, |
177 | 142 |
BlockDriverCompletionFunc *complete) |
178 | 143 |
{ |
179 |
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); |
|
180 |
|
|
181 | 144 |
r->io_header.interface_id = 'S'; |
182 | 145 |
r->io_header.dxfer_direction = direction; |
183 | 146 |
r->io_header.dxferp = r->buf; |
184 | 147 |
r->io_header.dxfer_len = r->buflen; |
185 | 148 |
r->io_header.cmdp = r->req.cmd.buf; |
186 | 149 |
r->io_header.cmd_len = r->req.cmd.len; |
187 |
r->io_header.mx_sb_len = sizeof(s->sensebuf);
|
|
188 |
r->io_header.sbp = s->sensebuf;
|
|
150 |
r->io_header.mx_sb_len = sizeof(r->req.sense);
|
|
151 |
r->io_header.sbp = r->req.sense;
|
|
189 | 152 |
r->io_header.timeout = MAX_UINT; |
190 | 153 |
r->io_header.usr_ptr = r; |
191 | 154 |
r->io_header.flags |= SG_FLAG_DIRECT_IO; |
... | ... | |
234 | 197 |
return; |
235 | 198 |
} |
236 | 199 |
|
237 |
if (r->req.cmd.buf[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE) |
|
238 |
{ |
|
239 |
s->senselen = MIN(r->len, s->senselen); |
|
240 |
memcpy(r->buf, s->sensebuf, s->senselen); |
|
200 |
if (r->req.cmd.buf[0] == REQUEST_SENSE) { |
|
241 | 201 |
r->io_header.driver_status = 0; |
242 | 202 |
r->io_header.status = 0; |
243 |
r->io_header.dxfer_len = s->senselen; |
|
203 |
r->io_header.dxfer_len = |
|
204 |
scsi_device_get_sense(&s->qdev, r->buf, r->req.cmd.xfer, |
|
205 |
(r->req.cmd.buf[1] & 1) == 0); |
|
244 | 206 |
r->len = -1; |
245 |
DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, s->senselen);
|
|
207 |
DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, r->io_header.dxfer_len);
|
|
246 | 208 |
DPRINTF("Sense: %d %d %d %d %d %d %d %d\n", |
247 | 209 |
r->buf[0], r->buf[1], r->buf[2], r->buf[3], |
248 | 210 |
r->buf[4], r->buf[5], r->buf[6], r->buf[7]); |
249 |
scsi_req_data(&r->req, s->senselen); |
|
250 |
/* Clear sensebuf after REQUEST_SENSE */ |
|
251 |
scsi_clear_sense(s); |
|
211 |
scsi_req_data(&r->req, r->io_header.dxfer_len); |
|
212 |
/* The sense buffer is cleared when we return GOOD */ |
|
252 | 213 |
return; |
253 | 214 |
} |
254 | 215 |
|
... | ... | |
342 | 303 |
|
343 | 304 |
if (cmd[0] != REQUEST_SENSE && req->lun != s->lun) { |
344 | 305 |
DPRINTF("Unimplemented LUN %d\n", req->lun); |
345 |
scsi_set_sense(s, SENSE_CODE(LUN_NOT_SUPPORTED));
|
|
306 |
scsi_req_build_sense(&r->req, SENSE_CODE(LUN_NOT_SUPPORTED));
|
|
346 | 307 |
scsi_req_complete(&r->req, CHECK_CONDITION); |
347 | 308 |
return 0; |
348 | 309 |
} |
... | ... | |
533 | 494 |
} |
534 | 495 |
} |
535 | 496 |
DPRINTF("block size %d\n", s->qdev.blocksize); |
536 |
s->driver_status = 0; |
|
537 |
memset(s->sensebuf, 0, sizeof(s->sensebuf)); |
|
538 | 497 |
bdrv_set_removable(s->bs, 0); |
539 | 498 |
return 0; |
540 | 499 |
} |
... | ... | |
553 | 512 |
.write_data = scsi_write_data, |
554 | 513 |
.cancel_io = scsi_cancel_io, |
555 | 514 |
.get_buf = scsi_get_buf, |
556 |
.get_sense = scsi_get_sense, |
|
557 | 515 |
.qdev.props = (Property[]) { |
558 | 516 |
DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf), |
559 | 517 |
DEFINE_PROP_END_OF_LIST(), |
b/hw/scsi.h | ||
---|---|---|
27 | 27 |
uint8_t ascq; |
28 | 28 |
} SCSISense; |
29 | 29 |
|
30 |
#define SCSI_SENSE_BUF_SIZE 96 |
|
31 |
|
|
30 | 32 |
struct SCSIRequest { |
31 | 33 |
SCSIBus *bus; |
32 | 34 |
SCSIDevice *dev; |
... | ... | |
42 | 44 |
enum SCSIXferMode mode; |
43 | 45 |
} cmd; |
44 | 46 |
BlockDriverAIOCB *aiocb; |
47 |
uint8_t sense[SCSI_SENSE_BUF_SIZE]; |
|
48 |
uint32_t sense_len; |
|
45 | 49 |
bool enqueued; |
46 | 50 |
void *hba_private; |
47 | 51 |
QTAILQ_ENTRY(SCSIRequest) next; |
... | ... | |
53 | 57 |
uint32_t id; |
54 | 58 |
BlockConf conf; |
55 | 59 |
SCSIDeviceInfo *info; |
60 |
uint8_t sense[SCSI_SENSE_BUF_SIZE]; |
|
61 |
uint32_t sense_len; |
|
56 | 62 |
QTAILQ_HEAD(, SCSIRequest) requests; |
57 | 63 |
int blocksize; |
58 | 64 |
int type; |
... | ... | |
76 | 82 |
void (*write_data)(SCSIRequest *req); |
77 | 83 |
void (*cancel_io)(SCSIRequest *req); |
78 | 84 |
uint8_t *(*get_buf)(SCSIRequest *req); |
79 |
int (*get_sense)(SCSIRequest *req, uint8_t *buf, int len); |
|
80 | 85 |
}; |
81 | 86 |
|
82 | 87 |
struct SCSIBusOps { |
... | ... | |
137 | 142 |
|
138 | 143 |
#define SENSE_CODE(x) sense_code_ ## x |
139 | 144 |
|
140 |
int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed); |
|
141 | 145 |
int scsi_sense_valid(SCSISense sense); |
142 | 146 |
|
143 | 147 |
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, |
... | ... | |
149 | 153 |
SCSIRequest *scsi_req_ref(SCSIRequest *req); |
150 | 154 |
void scsi_req_unref(SCSIRequest *req); |
151 | 155 |
|
156 |
void scsi_req_build_sense(SCSIRequest *req, SCSISense sense); |
|
152 | 157 |
int scsi_req_parse(SCSIRequest *req, uint8_t *buf); |
153 | 158 |
void scsi_req_print(SCSIRequest *req); |
154 | 159 |
void scsi_req_continue(SCSIRequest *req); |
... | ... | |
159 | 164 |
void scsi_req_abort(SCSIRequest *req, int status); |
160 | 165 |
void scsi_req_cancel(SCSIRequest *req); |
161 | 166 |
void scsi_device_purge_requests(SCSIDevice *sdev); |
167 |
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed); |
|
162 | 168 |
|
163 | 169 |
#endif |
b/trace-events | ||
---|---|---|
251 | 251 |
disable scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d" |
252 | 252 |
disable scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64"" |
253 | 253 |
disable scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d" |
254 |
disable scsi_req_build_sense(int target, int lun, int tag, int key, int asc, int ascq) "target %d lun %d tag %d key %#02x asc %#02x ascq %#02x" |
|
254 | 255 |
|
255 | 256 |
# vl.c |
256 | 257 |
disable vm_state_notify(int running, int reason) "running %d reason %d" |
Also available in: Unified diff