xref: /haiku/src/add-ons/kernel/busses/scsi/ahci/sata_request.cpp (revision 83b732c7328f1c4601e1a64ce234b93615c0ddc8)
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:"
130 				" status 0x%02x, error 0x%02x\n", fFis[2], status, error);
131 		}
132 	}
133 
134 	if (fCcb) {
135 		fCcb->data_resid = fCcb->data_length - bytesTransfered;
136 		fCcb->device_status = SCSI_STATUS_GOOD;
137 		fCcb->subsys_status = SCSI_REQ_CMP;
138 		if (tfd & (ATA_ERR | ATA_DF)) {
139 			fCcb->subsys_status = SCSI_REQ_CMP_ERR;
140 			if (fIsATAPI) {
141 				if (!IsTestUnitReady()) {
142 					dprintf("ahci: sata_request::finish ATAPI packet %02x %02x "
143 						"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x "
144 						"%02x %02x %02x %02x (len %d)\n",
145 						fCcb->cdb[0], fCcb->cdb[1], fCcb->cdb[2], fCcb->cdb[3],
146 						fCcb->cdb[4], fCcb->cdb[5], fCcb->cdb[6], fCcb->cdb[7],
147 						fCcb->cdb[8], fCcb->cdb[9], fCcb->cdb[10],
148 						fCcb->cdb[11], fCcb->cdb[12], fCcb->cdb[13],
149 						fCcb->cdb[14], fCcb->cdb[15], fCcb->cdb_length);
150 				}
151 
152 				fCcb->device_status = SCSI_STATUS_CHECK_CONDITION;
153 			} else {
154 				// TODO ATA error handling goes here
155 /*
156 				// TODO check ABORT bit if this is useful
157 				if ((tfd >> 8) & 0x04) { // ABRT
158 					fCcb->subsys_status = SCSI_REQ_ABORTED;
159 				} else {
160 					fCcb->device_status = SCSI_STATUS_CHECK_CONDITION;
161 					fCcb->subsys_status |= SCSI_AUTOSNS_VALID;
162 					fCcb->sense_resid = 0; //FIXME
163 					scsi_sense *sense = (scsi_sense *)fCcb->sense;
164 					sense->error_code = SCSIS_CURR_ERROR;
165 					sense->sense_key = error >> 4;
166 					sense->asc = 0;
167 					sense->ascq = 0;
168 				}
169 */
170 			}
171 		}
172 		gSCSI->finished(fCcb, 1);
173 		delete this;
174 	} else {
175 		fCompletionStatus = tfd;
176 		release_sem(fCompletionSem);
177 	}
178 }
179 
180 
181 void
182 sata_request::Abort()
183 {
184 	dprintf("ahci: sata_request::abort called for command 0x%02x\n", fFis[2]);
185 	if (fCcb != NULL) {
186 		fCcb->subsys_status = SCSI_REQ_ABORTED;
187 		gSCSI->finished(fCcb, 1);
188 		delete this;
189 	} else {
190 		fCompletionStatus = ATA_ERR;
191 		release_sem(fCompletionSem);
192 	}
193 }
194 
195 
196 void
197 sata_request::WaitForCompletion()
198 {
199 	ASSERT(fCcb == NULL);
200 	acquire_sem(fCompletionSem);
201 }
202 
203 
204 int
205 sata_request::CompletionStatus()
206 {
207 	ASSERT(fCcb == NULL);
208 	return fCompletionStatus;
209 }
210