1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-27 11:55:06 +00:00

Implement automatic SCSI sense fetching for ata(4) in ATA_CAM mode.

While it could be successfully done by CAM error recovery code, I was
told by several people that it is also a SIM obligation.
This commit is contained in:
Alexander Motin 2011-04-12 09:55:24 +00:00
parent 891b8ed467
commit f3c987e58e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=220563
2 changed files with 81 additions and 4 deletions

View File

@ -1475,6 +1475,72 @@ ata_cam_begin_transaction(device_t dev, union ccb *ccb)
}
}
static void
ata_cam_request_sense(device_t dev, struct ata_request *request)
{
struct ata_channel *ch = device_get_softc(dev);
union ccb *ccb = request->ccb;
ch->requestsense = 1;
bzero(request, sizeof(&request));
request->dev = NULL;
request->parent = dev;
request->unit = ccb->ccb_h.target_id;
request->data = (void *)&ccb->csio.sense_data;
request->bytecount = ccb->csio.sense_len;
request->u.atapi.ccb[0] = ATAPI_REQUEST_SENSE;
request->u.atapi.ccb[4] = ccb->csio.sense_len;
request->flags |= ATA_R_ATAPI;
if (ch->curr[ccb->ccb_h.target_id].atapi == 16)
request->flags |= ATA_R_ATAPI16;
if (ch->curr[ccb->ccb_h.target_id].mode >= ATA_DMA)
request->flags |= ATA_R_DMA;
request->flags |= ATA_R_READ;
request->transfersize = min(request->bytecount,
ch->curr[ccb->ccb_h.target_id].bytecount);
request->retries = 0;
request->timeout = (ccb->ccb_h.timeout + 999) / 1000;
callout_init_mtx(&request->callout, &ch->state_mtx, CALLOUT_RETURNUNLOCKED);
request->ccb = ccb;
ch->running = request;
ch->state = ATA_ACTIVE;
if (ch->hw.begin_transaction(request) == ATA_OP_FINISHED) {
ch->running = NULL;
ch->state = ATA_IDLE;
ata_cam_end_transaction(dev, request);
return;
}
}
static void
ata_cam_process_sense(device_t dev, struct ata_request *request)
{
struct ata_channel *ch = device_get_softc(dev);
union ccb *ccb = request->ccb;
int fatalerr = 0;
ch->requestsense = 0;
if (request->flags & ATA_R_TIMEOUT)
fatalerr = 1;
if ((request->flags & ATA_R_TIMEOUT) == 0 &&
(request->status & ATA_S_ERROR) == 0 &&
request->result == 0) {
ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
} else {
ccb->ccb_h.status &= ~CAM_STATUS_MASK;
ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
}
ata_free_request(request);
xpt_done(ccb);
/* Do error recovery if needed. */
if (fatalerr)
ata_reinit(dev);
}
void
ata_cam_end_transaction(device_t dev, struct ata_request *request)
{
@ -1482,6 +1548,11 @@ ata_cam_end_transaction(device_t dev, struct ata_request *request)
union ccb *ccb = request->ccb;
int fatalerr = 0;
if (ch->requestsense) {
ata_cam_process_sense(dev, request);
return;
}
ccb->ccb_h.status &= ~CAM_STATUS_MASK;
if (request->flags & ATA_R_TIMEOUT) {
xpt_freeze_simq(ch->sim, 1);
@ -1531,8 +1602,13 @@ ata_cam_end_transaction(device_t dev, struct ata_request *request)
ccb->csio.dxfer_len - request->donecount;
}
}
ata_free_request(request);
xpt_done(ccb);
if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR &&
(ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
ata_cam_request_sense(dev, request);
else {
ata_free_request(request);
xpt_done(ccb);
}
/* Do error recovery if needed. */
if (fatalerr)
ata_reinit(dev);

View File

@ -585,8 +585,9 @@ struct ata_channel {
#ifdef ATA_CAM
struct cam_sim *sim;
struct cam_path *path;
struct ata_cam_device user[16]; /* User-specified settings */
struct ata_cam_device curr[16]; /* Current settings */
struct ata_cam_device user[16]; /* User-specified settings */
struct ata_cam_device curr[16]; /* Current settings */
int requestsense; /* CCB waiting for SENSE. */
#endif
struct callout poll_callout; /* Periodic status poll. */
};