Revision 6dc06f08 hw/scsi-bus.c
b/hw/scsi-bus.c | ||
---|---|---|
149 | 149 |
.send_command = scsi_invalid_command |
150 | 150 |
}; |
151 | 151 |
|
152 |
/* SCSIReqOps implementation for unit attention conditions. */ |
|
153 |
|
|
154 |
static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf) |
|
155 |
{ |
|
156 |
if (req->dev && req->dev->unit_attention.key == UNIT_ATTENTION) { |
|
157 |
scsi_req_build_sense(req, req->dev->unit_attention); |
|
158 |
} else if (req->bus->unit_attention.key == UNIT_ATTENTION) { |
|
159 |
scsi_req_build_sense(req, req->bus->unit_attention); |
|
160 |
} |
|
161 |
scsi_req_complete(req, CHECK_CONDITION); |
|
162 |
return 0; |
|
163 |
} |
|
164 |
|
|
165 |
struct SCSIReqOps reqops_unit_attention = { |
|
166 |
.size = sizeof(SCSIRequest), |
|
167 |
.send_command = scsi_unit_attention |
|
168 |
}; |
|
169 |
|
|
152 | 170 |
/* SCSIReqOps implementation for REPORT LUNS and for commands sent to |
153 | 171 |
an invalid LUN. */ |
154 | 172 |
|
... | ... | |
344 | 362 |
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, |
345 | 363 |
uint8_t *buf, void *hba_private) |
346 | 364 |
{ |
365 |
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus); |
|
347 | 366 |
SCSIRequest *req; |
348 | 367 |
SCSICommand cmd; |
349 | 368 |
|
... | ... | |
358 | 377 |
cmd.lba); |
359 | 378 |
} |
360 | 379 |
|
361 |
if (lun != d->lun || |
|
380 |
if ((d->unit_attention.key == UNIT_ATTENTION || |
|
381 |
bus->unit_attention.key == UNIT_ATTENTION) && |
|
382 |
(buf[0] != INQUIRY && |
|
383 |
buf[0] != REPORT_LUNS && |
|
384 |
buf[0] != GET_CONFIGURATION && |
|
385 |
buf[0] != GET_EVENT_STATUS_NOTIFICATION)) { |
|
386 |
req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun, |
|
387 |
hba_private); |
|
388 |
} else if (lun != d->lun || |
|
362 | 389 |
buf[0] == REPORT_LUNS || |
363 | 390 |
buf[0] == REQUEST_SENSE) { |
364 | 391 |
req = scsi_req_alloc(&reqops_target_command, d, tag, lun, |
... | ... | |
377 | 404 |
return req->ops->get_buf(req); |
378 | 405 |
} |
379 | 406 |
|
407 |
static void scsi_clear_unit_attention(SCSIRequest *req) |
|
408 |
{ |
|
409 |
SCSISense *ua; |
|
410 |
if (req->dev->unit_attention.key != UNIT_ATTENTION && |
|
411 |
req->bus->unit_attention.key != UNIT_ATTENTION) { |
|
412 |
return; |
|
413 |
} |
|
414 |
|
|
415 |
/* |
|
416 |
* If an INQUIRY command enters the enabled command state, |
|
417 |
* the device server shall [not] clear any unit attention condition; |
|
418 |
* See also MMC-6, paragraphs 6.5 and 6.6.2. |
|
419 |
*/ |
|
420 |
if (req->cmd.buf[0] == INQUIRY || |
|
421 |
req->cmd.buf[0] == GET_CONFIGURATION || |
|
422 |
req->cmd.buf[0] == GET_EVENT_STATUS_NOTIFICATION) { |
|
423 |
return; |
|
424 |
} |
|
425 |
|
|
426 |
if (req->dev->unit_attention.key == UNIT_ATTENTION) { |
|
427 |
ua = &req->dev->unit_attention; |
|
428 |
} else { |
|
429 |
ua = &req->bus->unit_attention; |
|
430 |
} |
|
431 |
|
|
432 |
/* |
|
433 |
* If a REPORT LUNS command enters the enabled command state, [...] |
|
434 |
* the device server shall clear any pending unit attention condition |
|
435 |
* with an additional sense code of REPORTED LUNS DATA HAS CHANGED. |
|
436 |
*/ |
|
437 |
if (req->cmd.buf[0] == REPORT_LUNS && |
|
438 |
!(ua->asc == SENSE_CODE(REPORTED_LUNS_CHANGED).asc && |
|
439 |
ua->ascq == SENSE_CODE(REPORTED_LUNS_CHANGED).ascq)) { |
|
440 |
return; |
|
441 |
} |
|
442 |
|
|
443 |
*ua = SENSE_CODE(NO_SENSE); |
|
444 |
} |
|
445 |
|
|
380 | 446 |
int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) |
381 | 447 |
{ |
448 |
int ret; |
|
449 |
|
|
382 | 450 |
assert(len >= 14); |
383 | 451 |
if (!req->sense_len) { |
384 | 452 |
return 0; |
385 | 453 |
} |
386 |
return scsi_build_sense(req->sense, req->sense_len, buf, len, true); |
|
454 |
|
|
455 |
ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true); |
|
456 |
|
|
457 |
/* |
|
458 |
* FIXME: clearing unit attention conditions upon autosense should be done |
|
459 |
* only if the UA_INTLCK_CTRL field in the Control mode page is set to 00b |
|
460 |
* (SAM-5, 5.14). |
|
461 |
* |
|
462 |
* We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and |
|
463 |
* 10b for HBAs that do not support it (do not call scsi_req_get_sense). |
|
464 |
* In the latter case, scsi_req_complete clears unit attention conditions |
|
465 |
* after moving them to the device's sense buffer. |
|
466 |
*/ |
|
467 |
scsi_clear_unit_attention(req); |
|
468 |
return ret; |
|
387 | 469 |
} |
388 | 470 |
|
389 | 471 |
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed) |
... | ... | |
983 | 1065 |
} |
984 | 1066 |
req->dev->sense_len = req->sense_len; |
985 | 1067 |
|
1068 |
/* |
|
1069 |
* Unit attention state is now stored in the device's sense buffer |
|
1070 |
* if the HBA didn't do autosense. Clear the pending unit attention |
|
1071 |
* flags. |
|
1072 |
*/ |
|
1073 |
scsi_clear_unit_attention(req); |
|
1074 |
|
|
986 | 1075 |
scsi_req_ref(req); |
987 | 1076 |
scsi_req_dequeue(req); |
988 | 1077 |
req->bus->ops->complete(req, req->status); |
Also available in: Unified diff