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
sata_request()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
sata_request(scsi_ccb * ccb)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
~sata_request()40 sata_request::~sata_request()
41 {
42 if (fCompletionSem >= 0)
43 delete_sem(fCompletionSem);
44 }
45
46
47 void
SetData(void * data,size_t dataSize)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
SetATACommand(uint8 command)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
SetATA28Command(uint8 command,uint32 lba,uint8 sectorCount)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
SetATA48Command(uint8 command,uint64 lba,uint16 sectorCount)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
SetFeature(uint16 feature)98 sata_request::SetFeature(uint16 feature)
99 {
100 fFis[3] = (uint8)(feature & 0xff);
101 fFis[11] = (uint8)(feature >> 8);
102 }
103
104
105 void
SetATAPICommand(size_t transferLength)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
Finish(int tfd,size_t bytesTransfered)122 sata_request::Finish(int tfd, size_t bytesTransfered)
123 {
124 if ((tfd & (ATA_STATUS_ERROR | ATA_STATUS_DEVICE_FAULT)) != 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_STATUS_ERROR | ATA_STATUS_DEVICE_FAULT)) {
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
Abort()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_STATUS_ERROR;
191 release_sem(fCompletionSem);
192 }
193 }
194
195
196 void
WaitForCompletion()197 sata_request::WaitForCompletion()
198 {
199 ASSERT(fCcb == NULL);
200 acquire_sem(fCompletionSem);
201 }
202
203
204 int
CompletionStatus()205 sata_request::CompletionStatus()
206 {
207 ASSERT(fCcb == NULL);
208 return fCompletionStatus;
209 }
210