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 9 ATARequest::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 26 ATARequest::~ATARequest() 27 { 28 if (fHasLock) 29 mutex_destroy(&fLock); 30 } 31 32 33 void 34 ATARequest::SetStatus(uint8 status) 35 { 36 fStatus = status; 37 } 38 39 40 void 41 ATARequest::SetSense(uint8 key, uint16 codeQualifier) 42 { 43 fSenseKey = key; 44 fSenseCode = (uint8)(codeQualifier >> 8); 45 fSenseQualifier = (uint8)(codeQualifier & 0xff); 46 } 47 48 49 void 50 ATARequest::ClearSense() 51 { 52 fSenseKey = fSenseCode = fSenseQualifier = 0; 53 } 54 55 56 void 57 ATARequest::SetDevice(ATADevice *device) 58 { 59 fDevice = device; 60 } 61 62 63 void 64 ATARequest::SetTimeout(bigtime_t timeout) 65 { 66 fTimeout = timeout; 67 } 68 69 70 void 71 ATARequest::SetIsWrite(bool isWrite) 72 { 73 fIsWrite = isWrite; 74 } 75 76 77 void 78 ATARequest::SetUseDMA(bool useDMA) 79 { 80 fUseDMA = useDMA; 81 } 82 83 84 void 85 ATARequest::SetBytesLeft(uint32 bytesLeft) 86 { 87 fBytesLeft = bytesLeft; 88 } 89 90 91 status_t 92 ATARequest::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 105 status_t 106 ATARequest::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 143 void 144 ATARequest::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 165 void 166 ATARequest::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 176 void 177 ATARequest::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 189 void 190 ATARequest::SetOddByte(uint8 byte) 191 { 192 fOddByte = byte; 193 fHasOddByte = true; 194 } 195 196 197 bool 198 ATARequest::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 211 void 212 ATARequest::_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