xref: /haiku/src/add-ons/kernel/bus_managers/ata/ATARequest.cpp (revision 83b1a68c52ba3e0e8796282759f694b7fdddf06d)
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