From 6a2bc1027bc2e679655e319f5eb5d45702efee58 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 18 Apr 2009 22:37:04 +0000 Subject: [PATCH] For packet devices we want to actually return a check condition when the device indicates an error. Also we then need to pass through the request sense command to the device. This should fix media status reporting for ATAPI. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30253 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/bus_managers/ata/ATAChannel.cpp | 2 +- .../kernel/bus_managers/ata/ATAPIDevice.cpp | 54 +++++++++++-------- .../kernel/bus_managers/ata/ATAPrivate.h | 3 ++ 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/ata/ATAChannel.cpp b/src/add-ons/kernel/bus_managers/ata/ATAChannel.cpp index bba1194f0f..1d6e3ced6a 100644 --- a/src/add-ons/kernel/bus_managers/ata/ATAChannel.cpp +++ b/src/add-ons/kernel/bus_managers/ata/ATAChannel.cpp @@ -215,7 +215,7 @@ ATAChannel::ExecuteIO(scsi_ccb *ccb) if (result != B_OK) return result; - if (ccb->cdb[0] == SCSI_OP_REQUEST_SENSE) { + if (ccb->cdb[0] == SCSI_OP_REQUEST_SENSE && fRequest->HasSense()) { TRACE("request sense\n"); fRequest->RequestSense(); fRequest->Finish(false); diff --git a/src/add-ons/kernel/bus_managers/ata/ATAPIDevice.cpp b/src/add-ons/kernel/bus_managers/ata/ATAPIDevice.cpp index cbf5ddde16..ca0752a6f7 100644 --- a/src/add-ons/kernel/bus_managers/ata/ATAPIDevice.cpp +++ b/src/add-ons/kernel/bus_managers/ata/ATAPIDevice.cpp @@ -95,13 +95,8 @@ ATAPIDevice::SendPacket(ATARequest *request) return B_ERROR; } - if (!request->HasData()) { - result = fChannel->FinishRequest(request, ATA_WAIT_FINISH - | ATA_CHECK_DEVICE_FAULT, ATA_ERROR_ALL); - if (result != B_OK) - TRACE_ERROR("device indicates error after non-data command\n"); - return result; - } + if (!request->HasData()) + return _FinishRequest(request, ATA_WAIT_FINISH); if (request->UseDMA()) { fChannel->PrepareWaitingForInterrupt(); @@ -114,8 +109,7 @@ ATAPIDevice::SendPacket(ATARequest *request) return B_TIMED_OUT; } - result = fChannel->FinishRequest(request, ATA_CHECK_DEVICE_FAULT, - ATA_ERROR_ALL); + result = _FinishRequest(request, ATA_WAIT_FINISH); if (result != B_OK) { TRACE_ERROR("device indicates transfer error after dma\n"); return result; @@ -148,8 +142,7 @@ ATAPIDevice::SendPacket(ATARequest *request) request->SetStatus(SCSI_CMD_TIMEOUT); return B_TIMED_OUT; } else - return fChannel->FinishRequest(request, ATA_WAIT_FINISH - | ATA_CHECK_DEVICE_FAULT, ATA_ERROR_ALL); + return _FinishRequest(request, 0); } // PIO data transfer @@ -170,10 +163,14 @@ ATAPIDevice::SendPacket(ATARequest *request) request->SetBytesLeft(length); fChannel->ExecutePIOTransfer(request); - if (fChannel->Wait(0, ATA_STATUS_BUSY, 0, request->Timeout()) != B_OK) { - TRACE_ERROR("timeout waiting for device to finish transfer\n"); - request->SetStatus(SCSI_CMD_TIMEOUT); - return B_TIMED_OUT; + result = fChannel->Wait(0, ATA_STATUS_BUSY, 0, request->Timeout()); + if (result != B_OK) { + if (result == B_TIMED_OUT) { + TRACE_ERROR("timeout waiting for device to finish transfer\n"); + request->SetStatus(SCSI_CMD_TIMEOUT); + return B_TIMED_OUT; + } else + return _FinishRequest(request, 0); } if ((fChannel->AltStatus() & ATA_STATUS_DATA_REQUEST) == 0) { @@ -183,12 +180,7 @@ ATAPIDevice::SendPacket(ATARequest *request) } } - result = fChannel->FinishRequest(request, ATA_WAIT_FINISH - | ATA_CHECK_DEVICE_FAULT, ATA_ERROR_ALL); - if (result != B_OK) - TRACE_ERROR("device indicates transfer error after pio\n"); - - return result; + return _FinishRequest(request, ATA_WAIT_FINISH); } @@ -242,3 +234,23 @@ ATAPIDevice::_FillTaskFilePacket(ATARequest *request) fTaskFile.packet.command = ATA_COMMAND_PACKET; return B_OK; } + + +status_t +ATAPIDevice::_FinishRequest(ATARequest *request, uint32 flags) +{ + if (fChannel->FinishRequest(request, flags + | ATA_CHECK_DEVICE_FAULT, 0) != B_OK) { + // when we get an error from a packet device, we instruct the + // scsi layer to do a request sense. but since we don't want to + // return an emulated sense coming from ata, we clear our sense + // key first so that the next request sense will go to the packet + // device directly (as a packet command). + request->ClearSense(); + request->SetStatus(SCSI_REQ_CMP_ERR); + request->CCB()->device_status = SCSI_STATUS_CHECK_CONDITION; + return B_ERROR; + } + + return B_OK; +} diff --git a/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h b/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h index 081dd9fc10..3ed1a1da62 100644 --- a/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h +++ b/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h @@ -235,6 +235,8 @@ virtual status_t Configure(); private: status_t _FillTaskFilePacket(ATARequest *request); + status_t _FinishRequest(ATARequest *request, + uint32 flags); uint8 fPacket[12]; }; @@ -270,6 +272,7 @@ public: size_t * BytesLeft() { return &fBytesLeft; }; bool HasData() { return fCCB->data_length > 0; }; + bool HasSense() { return fSenseKey != 0; }; status_t Finish(bool resubmit);