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