The Pedigree Project 0.1
modules/drivers/common/ata/main.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/linker/KernelElf.h"
22#include "pedigree/kernel/machine/Controller.h"
23#include "pedigree/kernel/machine/Device.h"
24#include "pedigree/kernel/processor/types.h"
25#include "pedigree/kernel/utilities/String.h"
26#include "pedigree/kernel/utilities/Vector.h"
27#include "pedigree/kernel/utilities/new"
28
29#include "IsaAtaController.h"
30#include "PciAtaController.h"
31#include "modules/Module.h"
32
33static int nController = 0;
34
35static bool bFound = false;
36
37// Try for a PIIX IDE controller first. We prefer the PIIX as it enables us
38// to use DMA (and is a little easier to use for device detection).
39static bool bPiixControllerFound = false;
40static int piixLevel = -1;
41static bool bFallBackISA = false;
42
43static bool allowProbing = false;
44
45static Vector<AtaController*> g_Controllers;
46
48 public:
49 explicit RestoredAtaController(Controller* controller) : Controller(controller) {
50 // Device's transfer constructor copies child pointers. The old ATA
51 // controller remains their sole owner until foreach deletes it.
53 }
54};
55
56static Device* probeIsaDevice(Controller* pDev) {
57 // Create a new AtaController device node.
58 IsaAtaController* pController = new IsaAtaController(pDev, nController++);
59 g_Controllers.pushBack(pController);
60
61 bFound = true;
62
63 return pController;
64}
65
66static Device* probePiixController(Device* pDev) {
67 EMIT_IF(PEDIGREE_MACHINE_HASPCI) {
68 static uint8_t interrupt = 14;
69
70 // Create a new AtaController device node.
71 Controller* pDevController = new Controller(pDev);
72 uintptr_t intnum = pDevController->getInterruptNumber();
73 if (intnum == 0) {
74 // No valid interrupt, handle
75 pDevController->setInterruptNumber(interrupt);
76 if (interrupt < 15)
77 interrupt++;
78 else {
79 ERROR(
80 "PCI IDE: Controller found with no IRQ and IRQs 14 and 15 "
81 "are already allocated");
82 delete pDevController;
83
84 return pDev;
85 }
86 }
87
88 PciAtaController* pController = new PciAtaController(pDevController, nController++);
89 g_Controllers.pushBack(pController);
90
91 bFound = true;
92
93 return pController;
94 }
95 else {
96 return nullptr;
97 }
98}
99
101static Device* removeIsaAta(Device* dev) {
102 if (dev->getType() == Device::Controller) {
103 // Get its addresses, and search for "command" and "control".
104 bool foundCommand = false;
105 bool foundControl = false;
106 for (unsigned int j = 0; j < dev->addresses().count(); j++) {
107 if (dev->addresses()[j]->m_Name.compare("command"))
108 foundCommand = true;
109 if (dev->addresses()[j]->m_Name.compare("control"))
110 foundControl = true;
111 }
112
113 if (foundCommand && foundControl) {
114 // Destroy and remove this device.
115 return 0;
116 }
117 }
118
119 return dev;
120}
121
122static Device* probeDisk(Device* pDev) {
123 // Native SATA controllers belong to the AHCI driver, not legacy IDE probing.
124 if (pDev->getPciClassCode() == 0x01 && pDev->getPciSubclassCode() == 0x06)
125 return pDev;
126
127 // Look for a PIIX controller
128 // Class/subclasss 1:1 == Mass storage + IDE.
129 if (pDev->getPciVendorId() == 0x8086 && pDev->getPciClassCode() == 1 &&
130 pDev->getPciSubclassCode() == 1) {
131 // Ensure we probe the most modern PIIX that is present and available.
132 // This is important as there may be a PIIX3 in a system that also has
133 // a PIIX4, but the drives are likely to be attached to the PIIX4.
134 bool shouldProbe = false;
135 switch (pDev->getPciDeviceId()) {
136 case 0x1230: // PIIX
137 if (allowProbing && piixLevel == 0) {
138 shouldProbe = true;
139 } else if (piixLevel < 0) {
140 piixLevel = 0;
141 }
142 break;
143
144 case 0x7010: // PIIX3
145 if (allowProbing && piixLevel == 3) {
146 shouldProbe = true;
147 } else if (piixLevel < 3) {
148 piixLevel = 3;
149 }
150 break;
151
152 case 0x7111: // PIIX4
153 if (allowProbing && piixLevel == 4) {
154 shouldProbe = true;
155 } else if (piixLevel < 4) {
156 piixLevel = 4;
157 }
158 break;
159 }
160
161 if (piixLevel != -1) {
162 bPiixControllerFound = true;
163 }
164
165 if (allowProbing && shouldProbe) {
166 return probePiixController(pDev);
167 }
168 }
169
170 // No PIIX controller found, fall back to ISA
172 if (!bPiixControllerFound && bFallBackISA) {
173 // Is this a controller?
174 if (pDev->getType() == Device::Controller) {
175 // Check it's not an ATA controller already.
176 // Get its addresses, and search for "command" and "control".
177 bool foundCommand = false;
178 bool foundControl = false;
179 for (unsigned int j = 0; j < pDev->addresses().count(); j++) {
180 if (pDev->addresses()[j]->m_Name.compare("command"))
181 foundCommand = true;
182 if (pDev->addresses()[j]->m_Name.compare("control"))
183 foundControl = true;
184 }
185 if (allowProbing && foundCommand && foundControl)
186 return probeIsaDevice(static_cast<Controller*>(pDev));
187 }
188 }
189
190 return pDev;
191}
192
193static Module::UnloadAdmission admitUnload(bool) {
194 for (auto* controller : g_Controllers) {
195 if (controller && !controller->prepareDiskRemoval()) {
196 for (auto* rollback : g_Controllers) {
197 if (rollback)
198 rollback->cancelDiskRemoval();
199 }
200 return Module::UnloadAdmission::Busy;
201 }
202 }
203 return Module::UnloadAdmission::Ready;
204}
205
206static bool entry() {
209
210 // Walk the device tree looking for controllers that have
211 // "control" and "command" addresses.
212 Device::foreach (probeDisk);
213
214 // Done initial probe to find out what exists, action the findings now.
215 allowProbing = true;
216 if (bPiixControllerFound) {
217 // Right, we found a PIIX controller. Let's remove the ATA
218 // controllers that are created early in the boot (ISA) now
219 // so that when we probe the controller we don't run into used
220 // ports.
221 Device::foreach (removeIsaAta);
222 Device::foreach (probeDisk);
223 }
224 if (!bFound) {
225 // Try again, allowing ISA devices this time.
226 bFallBackISA = true;
227 Device::foreach (probeDisk);
228 }
229
230 return bFound && KernelElf::instance().registerUnloadAdmission(&entry, &admitUnload);
231}
232
233static Device* removeAtaController(Device* device) {
234 for (size_t i = 0; i < g_Controllers.count(); ++i) {
235 AtaController* controller = g_Controllers[i];
236 if (controller != device) {
237 continue;
238 }
239
240 // Hardware callbacks and disk caches need the live I/O mappings. Retire
241 // them before the transfer constructor takes ownership of those mappings.
242 controller->shutdown();
243 g_Controllers[i] = nullptr;
244 return new RestoredAtaController(controller);
245 }
246 return device;
247}
248
249static void exit() {
250 Device::foreach (removeAtaController);
251 g_Controllers.clear();
252 nController = 0;
253 bFound = false;
254 bPiixControllerFound = false;
255 piixLevel = -1;
256 bFallBackISA = false;
257 allowProbing = false;
258}
259
260#if X86_COMMON
261MODULE_INFO("ata", &entry, &exit, "scsi", "pci", 0);
262#endif
virtual void shutdown()=0
uint16_t getPciDeviceId()
Definition Device.h:228
uint16_t getPciVendorId()
Definition Device.h:224
static void foreach(Callback callback, Device *root=0)
Definition Device.cc:107
virtual Vector< Address * > & addresses()
Definition Device.h:266
@ Controller
Definition Device.h:85
virtual void setInterruptNumber(uintptr_t n)
Definition Device.h:276
uint8_t getPciClassCode()
Definition Device.h:216
uint8_t getPciSubclassCode()
Definition Device.h:220
Vector< Device * > m_Children
Definition Device.h:351
virtual Type getType()
Definition Device.h:178
virtual uintptr_t getInterruptNumber()
Definition Device.h:271
bool registerUnloadAdmission(ModuleEntry ownerEntry, Module::UnloadAdmissionHook hook)
static KernelElf & instance()
Definition KernelElf.h:135
A vector / dynamic array.
Definition Vector.h:33
void clear(bool freeMem=false)
Definition Vector.h:378