xref: /haiku/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp (revision 37fedaf8494b34aad811abcc49e79aa32943f880)
1 /*
2  * Copyright 2008, Marcus Overhagen. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <string.h>
8 
9 #include "sata_request.h"
10 #include "scsi_cmds.h"
11 
12 
13 #define FIS_TYPE_REGISTER_HOST_TO_DEVICE 0x27
14 
15 
16 sata_request::sata_request()
17 	:
18 	fCcb(NULL),
19 	fIsATAPI(false),
20 	fCompletionSem(create_sem(0, "sata completion")),
21 	fCompletionStatus(0),
22 	fData(NULL),
23 	fDataSize(0)
24 {
25 }
26 
27 
28 sata_request::sata_request(scsi_ccb* ccb)
29 	:
30 	fCcb(ccb),
31 	fIsATAPI(false),
32 	fCompletionSem(-1),
33 	fCompletionStatus(0),
34 	fData(NULL),
35 	fDataSize(0)
36 {
37 }
38 
39 
40 sata_request::~sata_request()
41 {
42 	if (fCompletionSem >= 0)
43 		delete_sem(fCompletionSem);
44 }
45 
46 
47 void
48 sata_request::SetData(void* data, size_t dataSize)
49 {
50 	ASSERT(fCcb == NULL);
51 	fData = data;
52 	fDataSize = dataSize;
53 }
54 
55 
56 void
57 sata_request::SetATACommand(uint8 command)
58 {
59 	memset(fFis, 0, sizeof(fFis));
60 	fFis[0] = FIS_TYPE_REGISTER_HOST_TO_DEVICE;
61 	fFis[1] = 0x80;
62 		// This is a command
63 	fFis[2] = command;
64 }
65 
66 
67 void
68 sata_request::SetATA28Command(uint8 command, uint32 lba, uint8 sectorCount)
69 {
70 	SetATACommand(command);
71 	fFis[4] = lba & 0xff;
72 	fFis[5] = (lba >> 8) & 0xff;
73 	fFis[6] = (lba >> 16) & 0xff;
74 	fFis[7] = 0x40 | ((lba >> 24) & 0x0f);
75 		// device
76 	fFis[12] = sectorCount & 0xff;
77 }
78 
79 
80 void
81 sata_request::SetATA48Command(uint8 command, uint64 lba, uint16 sectorCount)
82 {
83 	SetATACommand(command);
84 	fFis[4] = lba & 0xff;
85 	fFis[5] = (lba >> 8) & 0xff;
86 	fFis[6] = (lba >> 16) & 0xff;
87 	fFis[7] = 0x40;
88 		// device
89 	fFis[8] = (lba >> 24) & 0xff;
90 	fFis[9] = (lba >> 32) & 0xff;
91 	fFis[10] = (lba >> 40) & 0xff;
92 	fFis[12] = sectorCount & 0xff;
93 	fFis[13] = (sectorCount >> 8) & 0xff;
94 }
95 
96 
97 void
98 sata_request::SetFeature(uint16 feature)
99 {
100 	fFis[3] = (uint8)(feature & 0xff);
101 	fFis[11] = (uint8)(feature >> 8);
102 }
103 
104 
105 void
106 sata_request::SetATAPICommand(size_t transferLength)
107 {
108 	fIsATAPI = true;
109 	SetATACommand(0xa0);
110 	if (1 /* isPIO */) {
111 		if (transferLength == 0)
112 			transferLength = 2;
113 		else if (transferLength > 0xfffe)
114 			transferLength = 0xfffe;
115 		fFis[5] = transferLength & 0xff;
116 		fFis[6] = (transferLength >> 8) & 0xff;
117 	}
118 }
119 
120 
121 void
122 sata_request::Finish(int tfd, size_t bytesTransfered)
123 {
124 	if ((tfd & (ATA_ERR | ATA_DF)) != 0) {
125 		uint8 status = tfd & 0xff;
126 		uint8 error = (tfd >> 8) & 0xff;
127 
128 		if (!IsTestUnitReady()) {
129 			dprintf("ahci: sata_request::finish ATA command 0x%02x failed\n",
130 				fFis[2]);
131 			dprintf("ahci: sata_request::finish status 0x%02x, error 0x%02x\n",
132 				status, error);
133 		}
134 	}
135 
136 	if (fCcb) {
137 		fCcb->data_resid = fCcb->data_length - bytesTransfered;
138 		fCcb->device_status = SCSI_STATUS_GOOD;
139 		fCcb->subsys_status = SCSI_REQ_CMP;
140 		if (tfd & (ATA_ERR | ATA_DF)) {
141 			fCcb->subsys_status = SCSI_REQ_CMP_ERR;
142 			if (fIsATAPI) {
143 				if (!IsTestUnitReady()) {
144 					dprintf("ahci: sata_request::finish ATAPI packet %02x %02x "
145 						"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x "
146 						"%02x %02x %02x %02x (len %d)\n",
147 						fCcb->cdb[0], fCcb->cdb[1], fCcb->cdb[2], fCcb->cdb[3],
148 						fCcb->cdb[4], fCcb->cdb[5], fCcb->cdb[6], fCcb->cdb[7],
149 						fCcb->cdb[8], fCcb->cdb[9], fCcb->cdb[10],
150 						fCcb->cdb[11], fCcb->cdb[12], fCcb->cdb[13],
151 						fCcb->cdb[14], fCcb->cdb[15], fCcb->cdb_length);
152 				}
153 
154 				fCcb->device_status = SCSI_STATUS_CHECK_CONDITION;
155 			} else {
156 				// TODO ATA error handling goes here
157 /*
158 				// TODO check ABORT bit if this is useful
159 				if ((tfd >> 8) & 0x04) { // ABRT
160 					fCcb->subsys_status = SCSI_REQ_ABORTED;
161 				} else {
162 					fCcb->device_status = SCSI_STATUS_CHECK_CONDITION;
163 					fCcb->subsys_status |= SCSI_AUTOSNS_VALID;
164 					fCcb->sense_resid = 0; //FIXME
165 					scsi_sense *sense = (scsi_sense *)fCcb->sense;
166 					sense->error_code = SCSIS_CURR_ERROR;
167 					sense->sense_key = error >> 4;
168 					sense->asc = 0;
169 					sense->ascq = 0;
170 				}
171 */
172 			}
173 		}
174 		gSCSI->finished(fCcb, 1);
175 		delete this;
176 	} else {
177 		fCompletionStatus = tfd;
178 		release_sem(fCompletionSem);
179 	}
180 }
181 
182 
183 void
184 sata_request::Abort()
185 {
186 	dprintf("ahci: sata_request::abort called for command 0x%02x\n", fFis[2]);
187 	if (fCcb != NULL) {
188 		fCcb->subsys_status = SCSI_REQ_ABORTED;
189 		gSCSI->finished(fCcb, 1);
190 		delete this;
191 	} else {
192 		fCompletionStatus = ATA_ERR;
193 		release_sem(fCompletionSem);
194 	}
195 }
196 
197 
198 void
199 sata_request::WaitForCompletion()
200 {
201 	ASSERT(fCcb == NULL);
202 	acquire_sem(fCompletionSem);
203 }
204 
205 
206 int
207 sata_request::CompletionStatus()
208 {
209 	ASSERT(fCcb == NULL);
210 	return fCompletionStatus;
211 }
212