Revision 5dba48a8 hw/scsi-disk.c
b/hw/scsi-disk.c | ||
---|---|---|
41 | 41 |
#define SCSI_DMA_BUF_SIZE 131072 |
42 | 42 |
#define SCSI_MAX_INQUIRY_LEN 256 |
43 | 43 |
|
44 |
#define SCSI_REQ_STATUS_RETRY 0x01 |
|
44 |
#define SCSI_REQ_STATUS_RETRY 0x01 |
|
45 |
#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06 |
|
46 |
#define SCSI_REQ_STATUS_RETRY_READ 0x00 |
|
47 |
#define SCSI_REQ_STATUS_RETRY_WRITE 0x02 |
|
45 | 48 |
|
46 | 49 |
typedef struct SCSIDiskState SCSIDiskState; |
47 | 50 |
|
... | ... | |
70 | 73 |
char *serial; |
71 | 74 |
}; |
72 | 75 |
|
76 |
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); |
|
77 |
|
|
73 | 78 |
static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag, |
74 | 79 |
uint32_t lun) |
75 | 80 |
{ |
... | ... | |
127 | 132 |
static void scsi_read_complete(void * opaque, int ret) |
128 | 133 |
{ |
129 | 134 |
SCSIDiskReq *r = (SCSIDiskReq *)opaque; |
135 |
int n; |
|
130 | 136 |
|
131 | 137 |
r->req.aiocb = NULL; |
132 | 138 |
|
133 | 139 |
if (ret) { |
134 |
DPRINTF("IO error\n"); |
|
135 |
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0); |
|
136 |
scsi_command_complete(r, CHECK_CONDITION, NO_SENSE); |
|
137 |
return; |
|
140 |
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) { |
|
141 |
return; |
|
142 |
} |
|
138 | 143 |
} |
144 |
|
|
139 | 145 |
DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len); |
140 | 146 |
|
147 |
n = r->iov.iov_len / 512; |
|
148 |
r->sector += n; |
|
149 |
r->sector_count -= n; |
|
141 | 150 |
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len); |
142 | 151 |
} |
143 | 152 |
|
144 |
/* Read more data from scsi device into buffer. */ |
|
145 |
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
|
|
153 |
|
|
154 |
static void scsi_read_request(SCSIDiskReq *r)
|
|
146 | 155 |
{ |
147 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); |
|
148 |
SCSIDiskReq *r; |
|
156 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
|
149 | 157 |
uint32_t n; |
150 | 158 |
|
151 |
r = scsi_find_request(s, tag); |
|
152 |
if (!r) { |
|
153 |
BADF("Bad read tag 0x%x\n", tag); |
|
154 |
/* ??? This is the wrong error. */ |
|
155 |
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); |
|
156 |
return; |
|
157 |
} |
|
158 | 159 |
if (r->sector_count == (uint32_t)-1) { |
159 | 160 |
DPRINTF("Read buf_len=%zd\n", r->iov.iov_len); |
160 | 161 |
r->sector_count = 0; |
... | ... | |
177 | 178 |
scsi_read_complete, r); |
178 | 179 |
if (r->req.aiocb == NULL) |
179 | 180 |
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); |
180 |
r->sector += n; |
|
181 |
r->sector_count -= n; |
|
182 | 181 |
} |
183 | 182 |
|
184 |
static int scsi_handle_write_error(SCSIDiskReq *r, int error) |
|
183 |
/* Read more data from scsi device into buffer. */ |
|
184 |
static void scsi_read_data(SCSIDevice *d, uint32_t tag) |
|
185 | 185 |
{ |
186 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); |
|
187 |
SCSIDiskReq *r; |
|
188 |
|
|
189 |
r = scsi_find_request(s, tag); |
|
190 |
if (!r) { |
|
191 |
BADF("Bad read tag 0x%x\n", tag); |
|
192 |
/* ??? This is the wrong error. */ |
|
193 |
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); |
|
194 |
return; |
|
195 |
} |
|
196 |
|
|
197 |
/* No data transfer may already be in progress */ |
|
198 |
assert(r->req.aiocb == NULL); |
|
199 |
|
|
200 |
scsi_read_request(r); |
|
201 |
} |
|
202 |
|
|
203 |
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type) |
|
204 |
{ |
|
205 |
int is_read = (type == SCSI_REQ_STATUS_RETRY_READ); |
|
186 | 206 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
187 |
BlockErrorAction action = bdrv_get_on_error(s->bs, 0);
|
|
207 |
BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
|
|
188 | 208 |
|
189 | 209 |
if (action == BLOCK_ERR_IGNORE) { |
190 |
bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, 0);
|
|
210 |
bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
|
|
191 | 211 |
return 0; |
192 | 212 |
} |
193 | 213 |
|
194 | 214 |
if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) |
195 | 215 |
|| action == BLOCK_ERR_STOP_ANY) { |
196 |
r->status |= SCSI_REQ_STATUS_RETRY; |
|
197 |
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, 0); |
|
216 |
|
|
217 |
type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK; |
|
218 |
r->status |= SCSI_REQ_STATUS_RETRY | type; |
|
219 |
|
|
220 |
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); |
|
198 | 221 |
vm_stop(0); |
199 | 222 |
} else { |
223 |
if (type == SCSI_REQ_STATUS_RETRY_READ) { |
|
224 |
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0); |
|
225 |
} |
|
200 | 226 |
scsi_command_complete(r, CHECK_CONDITION, |
201 | 227 |
HARDWARE_ERROR); |
202 |
bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, 0);
|
|
228 |
bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
|
|
203 | 229 |
} |
204 | 230 |
|
205 | 231 |
return 1; |
... | ... | |
214 | 240 |
r->req.aiocb = NULL; |
215 | 241 |
|
216 | 242 |
if (ret) { |
217 |
if (scsi_handle_write_error(r, -ret))
|
|
243 |
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
|
|
218 | 244 |
return; |
245 |
} |
|
219 | 246 |
} |
220 | 247 |
|
221 | 248 |
n = r->iov.iov_len / 512; |
... | ... | |
268 | 295 |
return 1; |
269 | 296 |
} |
270 | 297 |
|
271 |
if (r->req.aiocb)
|
|
272 |
BADF("Data transfer already in progress\n");
|
|
298 |
/* No data transfer may already be in progress */
|
|
299 |
assert(r->req.aiocb == NULL);
|
|
273 | 300 |
|
274 | 301 |
scsi_write_request(r); |
275 | 302 |
|
... | ... | |
288 | 315 |
QTAILQ_FOREACH(req, &s->qdev.requests, next) { |
289 | 316 |
r = DO_UPCAST(SCSIDiskReq, req, req); |
290 | 317 |
if (r->status & SCSI_REQ_STATUS_RETRY) { |
291 |
r->status &= ~SCSI_REQ_STATUS_RETRY; |
|
292 |
scsi_write_request(r); |
|
318 |
int status = r->status; |
|
319 |
r->status &= |
|
320 |
~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK); |
|
321 |
|
|
322 |
switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) { |
|
323 |
case SCSI_REQ_STATUS_RETRY_READ: |
|
324 |
scsi_read_request(r); |
|
325 |
break; |
|
326 |
case SCSI_REQ_STATUS_RETRY_WRITE: |
|
327 |
scsi_write_request(r); |
|
328 |
break; |
|
329 |
} |
|
293 | 330 |
} |
294 | 331 |
} |
295 | 332 |
} |
... | ... | |
1152 | 1189 |
return -1; |
1153 | 1190 |
} |
1154 | 1191 |
|
1155 |
if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) { |
|
1156 |
error_report("Device doesn't support drive option rerror"); |
|
1157 |
return -1; |
|
1158 |
} |
|
1159 |
|
|
1160 | 1192 |
if (!s->serial) { |
1161 | 1193 |
/* try to fall back to value set with legacy -drive serial=... */ |
1162 | 1194 |
dinfo = drive_get_by_blockdev(s->bs); |
Also available in: Unified diff