1/* 2 * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. 3 * Distributed under the terms of the MIT License. 4 */ 5 6#include "ATAPrivate.h" 7 8 9ATARequest::ATARequest(bool hasLock) 10 : 11 fHasLock(hasLock), 12 fDevice(NULL), 13 fTimeout(0), 14 fBytesLeft(0), 15 fIsWrite(false), 16 fUseDMA(false), 17 fCCB(NULL) 18{ 19 if (hasLock) 20 mutex_init(&fLock, "ata request"); 21 22 ClearSense(); 23} 24 25 26ATARequest::~ATARequest() 27{ 28 if (fHasLock) 29 mutex_destroy(&fLock); 30} 31 32 33void 34ATARequest::SetStatus(uint8 status) 35{ 36 fStatus = status; 37} 38 39 40void 41ATARequest::SetSense(uint8 key, uint16 codeQualifier) 42{ 43 fSenseKey = key; 44 fSenseCode = (uint8)(codeQualifier >> 8); 45 fSenseQualifier = (uint8)(codeQualifier & 0xff); 46} 47 48 49void 50ATARequest::ClearSense() 51{ 52 fSenseKey = fSenseCode = fSenseQualifier = 0; 53} 54 55 56void 57ATARequest::SetDevice(ATADevice *device) 58{ 59 fDevice = device; 60} 61 62 63void 64ATARequest::SetTimeout(bigtime_t timeout) 65{ 66 fTimeout = timeout; 67} 68 69 70void 71ATARequest::SetIsWrite(bool isWrite) 72{ 73 fIsWrite = isWrite; 74} 75 76 77void 78ATARequest::SetUseDMA(bool useDMA) 79{ 80 fUseDMA = useDMA; 81} 82 83 84void 85ATARequest::SetBytesLeft(uint32 bytesLeft) 86{ 87 fBytesLeft = bytesLeft; 88} 89 90 91status_t 92ATARequest::Start(scsi_ccb *ccb) 93{ 94 if (mutex_trylock(&fLock) != B_OK) 95 return B_BUSY; 96 97 fCCB = ccb; 98 fStatus = SCSI_REQ_CMP; 99 fCCB->device_status = SCSI_STATUS_GOOD; 100 fIsWrite = false; 101 return B_OK; 102} 103 104 105status_t 106ATARequest::Finish(bool resubmit) 107{ 108 // when the request completed and has set sense 109 // data, report this to the scsi stack by setting 110 // CHECK CONDITION status 111 if (fStatus == SCSI_REQ_CMP && fSenseKey != 0) { 112 TRACE("setting check condition\n"); 113 114 fCCB->subsys_status = SCSI_REQ_CMP_ERR; 115 fCCB->device_status = SCSI_STATUS_CHECK_CONDITION; 116 117 // copy sense data if caller requested it 118 if ((fCCB->flags & SCSI_DIS_AUTOSENSE) == 0) { 119 // we cannot copy sense directly as sense buffer may be too small 120 scsi_sense sense; 121 _FillSense(&sense); 122 123 size_t senseLength = MIN(sizeof(fCCB->sense), sizeof(sense)); 124 memcpy(fCCB->sense, &sense, senseLength); 125 fCCB->sense_resid = SCSI_MAX_SENSE_SIZE - senseLength; 126 fCCB->subsys_status |= SCSI_AUTOSNS_VALID; 127 ClearSense(); 128 } 129 } else 130 fCCB->subsys_status = fStatus; 131 132 mutex_unlock(&fLock); 133 134 if (resubmit) 135 gSCSIModule->resubmit(fCCB); 136 else 137 gSCSIModule->finished(fCCB, 1); 138 139 return B_OK; 140} 141 142 143void 144ATARequest::RequestSense() 145{ 146 // Copy sense data from last request into data buffer of current request. 147 // The sense data of last request is still present in the current request, 148 // as it isn't cleared on SCSI_OP_REQUEST_SENSE. 149 scsi_sense sense; 150 if (fSenseKey != 0) 151 _FillSense(&sense); 152 else 153 memset(&sense, 0, sizeof(sense)); 154 155 scsi_cmd_request_sense *command = (scsi_cmd_request_sense *)fCCB->cdb; 156 copy_sg_data(fCCB, 0, command->allocation_length, &sense, sizeof(sense), 157 false); 158 159 fCCB->data_resid = fCCB->data_length - MIN(MIN(sizeof(sense), 160 command->allocation_length), fCCB->data_length); 161 ClearSense(); 162} 163 164 165void 166ATARequest::PrepareSGInfo() 167{ 168 fSGElementsLeft = fCCB->sg_count; 169 fCurrentSGElement = fCCB->sg_list; 170 fCurrentSGOffset = 0; 171 fHasOddByte = false; 172 fCCB->data_resid = fCCB->data_length; 173} 174 175 176void 177ATARequest::AdvanceSG(uint32 bytes) 178{ 179 uint32 bytesLeft = fCurrentSGElement->size - fCurrentSGOffset; 180 if (bytesLeft <= bytes) { 181 fCurrentSGOffset = 0; 182 fCurrentSGElement++; 183 fSGElementsLeft--; 184 } else 185 fCurrentSGOffset += bytes; 186} 187 188 189void 190ATARequest::SetOddByte(uint8 byte) 191{ 192 fOddByte = byte; 193 fHasOddByte = true; 194} 195 196 197bool 198ATARequest::GetOddByte(uint8 *byte) 199{ 200 if (!fHasOddByte) 201 return false; 202 203 if (byte != NULL) 204 *byte = fOddByte; 205 206 fHasOddByte = false; 207 return true; 208} 209 210 211void 212ATARequest::_FillSense(scsi_sense *sense) 213{ 214 memset(sense, 0, sizeof(*sense)); 215 sense->error_code = SCSIS_CURR_ERROR; 216 sense->sense_key = fSenseKey; 217 sense->add_sense_length = sizeof(*sense) - 7; 218 sense->asc = fSenseCode; 219 sense->ascq = fSenseQualifier; 220 sense->sense_key_spec.raw.SKSV = 0; // no additional info 221} 222