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