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
ATARequest(bool hasLock)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
~ATARequest()26 ATARequest::~ATARequest()
27 {
28 if (fHasLock)
29 mutex_destroy(&fLock);
30 }
31
32
33 void
SetStatus(uint8 status)34 ATARequest::SetStatus(uint8 status)
35 {
36 fStatus = status;
37 }
38
39
40 void
SetSense(uint8 key,uint16 codeQualifier)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
ClearSense()50 ATARequest::ClearSense()
51 {
52 fSenseKey = fSenseCode = fSenseQualifier = 0;
53 }
54
55
56 void
SetDevice(ATADevice * device)57 ATARequest::SetDevice(ATADevice *device)
58 {
59 fDevice = device;
60 }
61
62
63 void
SetTimeout(bigtime_t timeout)64 ATARequest::SetTimeout(bigtime_t timeout)
65 {
66 fTimeout = timeout;
67 }
68
69
70 void
SetIsWrite(bool isWrite)71 ATARequest::SetIsWrite(bool isWrite)
72 {
73 fIsWrite = isWrite;
74 }
75
76
77 void
SetUseDMA(bool useDMA)78 ATARequest::SetUseDMA(bool useDMA)
79 {
80 fUseDMA = useDMA;
81 }
82
83
84 void
SetBytesLeft(uint32 bytesLeft)85 ATARequest::SetBytesLeft(uint32 bytesLeft)
86 {
87 fBytesLeft = bytesLeft;
88 }
89
90
91 status_t
Start(scsi_ccb * ccb)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
Finish(bool resubmit)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
RequestSense()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
PrepareSGInfo()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
AdvanceSG(uint32 bytes)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
SetOddByte(uint8 byte)190 ATARequest::SetOddByte(uint8 byte)
191 {
192 fOddByte = byte;
193 fHasOddByte = true;
194 }
195
196
197 bool
GetOddByte(uint8 * byte)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
_FillSense(scsi_sense * sense)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