Revision a1f0cce2 hw/scsi-disk.c
b/hw/scsi-disk.c | ||
---|---|---|
49 | 49 |
|
50 | 50 |
typedef struct SCSIDiskState SCSIDiskState; |
51 | 51 |
|
52 |
typedef struct SCSISense { |
|
53 |
uint8_t key; |
|
54 |
} SCSISense; |
|
55 |
|
|
56 | 52 |
typedef struct SCSIDiskReq { |
57 | 53 |
SCSIRequest req; |
58 | 54 |
/* ??? We should probably keep track of whether the data transfer is |
... | ... | |
111 | 107 |
memset(&s->sense, 0, sizeof(s->sense)); |
112 | 108 |
} |
113 | 109 |
|
114 |
static void scsi_disk_set_sense(SCSIDiskState *s, uint8_t key) |
|
115 |
{ |
|
116 |
s->sense.key = key; |
|
117 |
} |
|
118 |
|
|
119 |
static void scsi_req_set_status(SCSIDiskReq *r, int status, int sense_code) |
|
110 |
static void scsi_req_set_status(SCSIDiskReq *r, int status, SCSISense sense) |
|
120 | 111 |
{ |
121 | 112 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
122 | 113 |
|
123 | 114 |
r->req.status = status; |
124 |
scsi_disk_set_sense(s, sense_code);
|
|
115 |
s->sense = sense;
|
|
125 | 116 |
} |
126 | 117 |
|
127 | 118 |
/* Helper function for command completion. */ |
128 |
static void scsi_command_complete(SCSIDiskReq *r, int status, int sense)
|
|
119 |
static void scsi_command_complete(SCSIDiskReq *r, int status, SCSISense sense)
|
|
129 | 120 |
{ |
130 |
DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", |
|
131 |
r->req.tag, status, sense); |
|
121 |
DPRINTF("Command complete tag=0x%x status=%d sense=%d/%d/%d\n",
|
|
122 |
r->req.tag, status, sense.key, sense.asc, sense.ascq);
|
|
132 | 123 |
scsi_req_set_status(r, status, sense); |
133 | 124 |
scsi_req_complete(&r->req); |
134 | 125 |
} |
... | ... | |
182 | 173 |
} |
183 | 174 |
DPRINTF("Read sector_count=%d\n", r->sector_count); |
184 | 175 |
if (r->sector_count == 0) { |
185 |
scsi_command_complete(r, GOOD, NO_SENSE);
|
|
176 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
186 | 177 |
return; |
187 | 178 |
} |
188 | 179 |
|
... | ... | |
225 | 216 |
if (type == SCSI_REQ_STATUS_RETRY_READ) { |
226 | 217 |
scsi_req_data(&r->req, 0); |
227 | 218 |
} |
228 |
scsi_command_complete(r, CHECK_CONDITION, |
|
229 |
HARDWARE_ERROR); |
|
219 |
if (error == ENOMEM) { |
|
220 |
scsi_command_complete(r, CHECK_CONDITION, |
|
221 |
SENSE_CODE(TARGET_FAILURE)); |
|
222 |
} else { |
|
223 |
scsi_command_complete(r, CHECK_CONDITION, |
|
224 |
SENSE_CODE(IO_ERROR)); |
|
225 |
} |
|
230 | 226 |
bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read); |
231 | 227 |
} |
232 | 228 |
|
... | ... | |
251 | 247 |
r->sector += n; |
252 | 248 |
r->sector_count -= n; |
253 | 249 |
if (r->sector_count == 0) { |
254 |
scsi_command_complete(r, GOOD, NO_SENSE);
|
|
250 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
255 | 251 |
} else { |
256 | 252 |
len = r->sector_count * 512; |
257 | 253 |
if (len > SCSI_DMA_BUF_SIZE) { |
... | ... | |
278 | 274 |
r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n, |
279 | 275 |
scsi_write_complete, r); |
280 | 276 |
if (r->req.aiocb == NULL) { |
281 |
scsi_write_complete(r, -EIO);
|
|
277 |
scsi_write_complete(r, -ENOMEM);
|
|
282 | 278 |
} |
283 | 279 |
} else { |
284 | 280 |
/* Invoke completion routine to fetch data from host. */ |
... | ... | |
316 | 312 |
case SCSI_REQ_STATUS_RETRY_FLUSH: |
317 | 313 |
ret = scsi_disk_emulate_command(r, r->iov.iov_base); |
318 | 314 |
if (ret == 0) { |
319 |
scsi_command_complete(r, GOOD, NO_SENSE);
|
|
315 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
320 | 316 |
} |
321 | 317 |
} |
322 | 318 |
} |
... | ... | |
815 | 811 |
case REQUEST_SENSE: |
816 | 812 |
if (req->cmd.xfer < 4) |
817 | 813 |
goto illegal_request; |
818 |
memset(outbuf, 0, 4); |
|
819 |
buflen = 4; |
|
820 |
if (s->sense.key == NOT_READY && req->cmd.xfer >= 18) { |
|
821 |
memset(outbuf, 0, 18); |
|
822 |
buflen = 18; |
|
823 |
outbuf[7] = 10; |
|
824 |
/* asc 0x3a, ascq 0: Medium not present */ |
|
825 |
outbuf[12] = 0x3a; |
|
826 |
outbuf[13] = 0; |
|
827 |
} |
|
828 |
outbuf[0] = 0xf0; |
|
829 |
outbuf[1] = 0; |
|
830 |
outbuf[2] = s->sense.key; |
|
814 |
buflen = scsi_build_sense(s->sense, outbuf, req->cmd.xfer, |
|
815 |
req->cmd.xfer > 13); |
|
831 | 816 |
scsi_disk_clear_sense(s); |
832 | 817 |
break; |
833 | 818 |
case INQUIRY: |
... | ... | |
965 | 950 |
} |
966 | 951 |
break; |
967 | 952 |
default: |
968 |
goto illegal_request; |
|
953 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE)); |
|
954 |
return -1; |
|
969 | 955 |
} |
970 |
scsi_req_set_status(r, GOOD, NO_SENSE);
|
|
956 |
scsi_req_set_status(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
971 | 957 |
return buflen; |
972 | 958 |
|
973 | 959 |
not_ready: |
974 |
scsi_command_complete(r, CHECK_CONDITION, NOT_READY); |
|
960 |
if (!bdrv_is_inserted(s->bs)) { |
|
961 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(NO_MEDIUM)); |
|
962 |
} else { |
|
963 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LUN_NOT_READY)); |
|
964 |
} |
|
975 | 965 |
return -1; |
976 | 966 |
|
977 | 967 |
illegal_request: |
978 |
scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
|
|
968 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
|
|
979 | 969 |
return -1; |
980 | 970 |
} |
981 | 971 |
|
... | ... | |
1002 | 992 |
|
1003 | 993 |
if (scsi_req_parse(&r->req, buf) != 0) { |
1004 | 994 |
BADF("Unsupported command length, command %x\n", command); |
1005 |
goto fail; |
|
995 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE)); |
|
996 |
return 0; |
|
1006 | 997 |
} |
1007 | 998 |
#ifdef DEBUG_SCSI |
1008 | 999 |
{ |
... | ... | |
1017 | 1008 |
if (req->lun || buf[1] >> 5) { |
1018 | 1009 |
/* Only LUN 0 supported. */ |
1019 | 1010 |
DPRINTF("Unimplemented LUN %d\n", req->lun ? req->lun : buf[1] >> 5); |
1020 |
if (command != REQUEST_SENSE && command != INQUIRY) |
|
1021 |
goto fail; |
|
1011 |
if (command != REQUEST_SENSE && command != INQUIRY) { |
|
1012 |
scsi_command_complete(r, CHECK_CONDITION, |
|
1013 |
SENSE_CODE(LUN_NOT_SUPPORTED)); |
|
1014 |
return 0; |
|
1015 |
} |
|
1022 | 1016 |
} |
1023 | 1017 |
switch (command) { |
1024 | 1018 |
case TEST_UNIT_READY: |
... | ... | |
1126 | 1120 |
break; |
1127 | 1121 |
default: |
1128 | 1122 |
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); |
1123 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE)); |
|
1124 |
return 0; |
|
1129 | 1125 |
fail: |
1130 |
scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
|
|
1126 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
|
|
1131 | 1127 |
return 0; |
1132 | 1128 |
illegal_lba: |
1133 |
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
|
|
1129 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE));
|
|
1134 | 1130 |
return 0; |
1135 | 1131 |
} |
1136 | 1132 |
if (r->sector_count == 0 && r->iov.iov_len == 0) { |
1137 |
scsi_command_complete(r, GOOD, NO_SENSE);
|
|
1133 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
1138 | 1134 |
} |
1139 | 1135 |
len = r->sector_count * 512 + r->iov.iov_len; |
1140 | 1136 |
if (is_write) { |
Also available in: Unified diff