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 "IsaAtaController.h"
21 #include "PciAtaController.h"
22 #include "modules/Module.h"
23 #include "pedigree/kernel/Log.h"
24 #include "pedigree/kernel/machine/Controller.h"
25 #include "pedigree/kernel/machine/Device.h"
26 #include "pedigree/kernel/processor/types.h"
27 #include "pedigree/kernel/utilities/String.h"
28 #include "pedigree/kernel/utilities/Vector.h"
29 #include "pedigree/kernel/utilities/new"
30 
31 static int nController = 0;
32 
33 static bool bFound = false;
34 
35 // Try for a PIIX IDE controller first. We prefer the PIIX as it enables us
36 // to use DMA (and is a little easier to use for device detection).
37 static bool bPiixControllerFound = false;
38 static int piixLevel = -1;
39 static bool bFallBackISA = false;
40 
41 static bool allowProbing = false;
42 
43 static Device *probeIsaDevice(Controller *pDev)
44 {
45  // Create a new AtaController device node.
46  IsaAtaController *pController = new IsaAtaController(pDev, nController++);
47 
48  bFound = true;
49 
50  return pController;
51 }
52 
53 static Device *probePiixController(Device *pDev)
54 {
55  static uint8_t interrupt = 14;
56 
57  // Create a new AtaController device node.
58  Controller *pDevController = new Controller(pDev);
59  uintptr_t intnum = pDevController->getInterruptNumber();
60  if (intnum == 0)
61  {
62  // No valid interrupt, handle
63  pDevController->setInterruptNumber(interrupt);
64  if (interrupt < 15)
65  interrupt++;
66  else
67  {
68  ERROR("PCI IDE: Controller found with no IRQ and IRQs 14 and 15 "
69  "are already allocated");
70  delete pDevController;
71 
72  return pDev;
73  }
74  }
75 
76  PciAtaController *pController =
77  new PciAtaController(pDevController, nController++);
78 
79  bFound = true;
80 
81  return pController;
82 }
83 
85 static Device *removeIsaAta(Device *dev)
86 {
87  if (dev->getType() == Device::Controller)
88  {
89  // Get its addresses, and search for "command" and "control".
90  bool foundCommand = false;
91  bool foundControl = false;
92  for (unsigned int j = 0; j < dev->addresses().count(); j++)
93  {
95  if (dev->addresses()[j]->m_Name == "command")
96  foundCommand = true;
97  if (dev->addresses()[j]->m_Name == "control")
98  foundControl = true;
99  }
100 
101  if (foundCommand && foundControl)
102  {
103  // Destroy and remove this device.
104  return 0;
105  }
106  }
107 
108  return dev;
109 }
110 
111 static Device *probeDisk(Device *pDev)
112 {
113  // Check to see if this is an AHCI controller.
114  // Class 1 = Mass Storage. Subclass 6 = SATA.
115  if ((!allowProbing) &&
116  (pDev->getPciClassCode() == 0x01 && pDev->getPciSubclassCode() == 0x06))
117  {
118  // No AHCI support yet, so just log and keep going.
119  WARNING(
120  "Found a SATA controller of some sort, hoping for ISA fallback.");
121  }
122 
123  // Look for a PIIX controller
124  // Class/subclasss 1:1 == Mass storage + IDE.
125  if (pDev->getPciVendorId() == 0x8086 && pDev->getPciClassCode() == 1 &&
126  pDev->getPciSubclassCode() == 1)
127  {
128  // Ensure we probe the most modern PIIX that is present and available.
129  // This is important as there may be a PIIX3 in a system that also has
130  // a PIIX4, but the drives are likely to be attached to the PIIX4.
131  bool shouldProbe = false;
132  switch (pDev->getPciDeviceId())
133  {
134  case 0x1230: // PIIX
135  if (allowProbing && piixLevel == 0)
136  {
137  shouldProbe = true;
138  }
139  else if (piixLevel < 0)
140  {
141  piixLevel = 0;
142  }
143  break;
144 
145  case 0x7010: // PIIX3
146  if (allowProbing && piixLevel == 3)
147  {
148  shouldProbe = true;
149  }
150  else if (piixLevel < 3)
151  {
152  piixLevel = 3;
153  }
154  break;
155 
156  case 0x7111: // PIIX4
157  if (allowProbing && piixLevel == 4)
158  {
159  shouldProbe = true;
160  }
161  else if (piixLevel < 4)
162  {
163  piixLevel = 4;
164  }
165  break;
166  }
167 
168  if (piixLevel != -1)
169  {
170  bPiixControllerFound = true;
171  }
172 
173  if (allowProbing && shouldProbe)
174  {
175  return probePiixController(pDev);
176  }
177  }
178 
179  // No PIIX controller found, fall back to ISA
181  if (!bPiixControllerFound && bFallBackISA)
182  {
183  // Is this a controller?
184  if (pDev->getType() == Device::Controller)
185  {
186  // Check it's not an ATA controller already.
187  // Get its addresses, and search for "command" and "control".
188  bool foundCommand = false;
189  bool foundControl = false;
190  for (unsigned int j = 0; j < pDev->addresses().count(); j++)
191  {
193  if (pDev->addresses()[j]->m_Name == "command")
194  foundCommand = true;
195  if (pDev->addresses()[j]->m_Name == "control")
196  foundControl = true;
197  }
198  if (allowProbing && foundCommand && foundControl)
199  return probeIsaDevice(static_cast<Controller *>(pDev));
200  }
201  }
202 
203  return pDev;
204 }
205 
206 static bool entry()
207 {
210 
211  // Walk the device tree looking for controllers that have
212  // "control" and "command" addresses.
213  Device::foreach (probeDisk);
214 
215  // Done initial probe to find out what exists, action the findings now.
216  allowProbing = true;
217  if (bPiixControllerFound)
218  {
219  // Right, we found a PIIX controller. Let's remove the ATA
220  // controllers that are created early in the boot (ISA) now
221  // so that when we probe the controller we don't run into used
222  // ports.
223  Device::foreach (removeIsaAta);
224  Device::foreach (probeDisk);
225  }
226  if (!bFound)
227  {
228  // Try again, allowing ISA devices this time.
229  bFallBackISA = true;
230  Device::foreach (probeDisk);
231  }
232 
233  return bFound;
234 }
235 
236 static void exit()
237 {
238 }
239 
240 #ifdef PPC_COMMON
241 MODULE_INFO("ata", &entry, &exit, "scsi", "ata-specific", 0);
242 #elif defined(X86_COMMON)
243 MODULE_INFO("ata", &entry, &exit, "scsi", "pci", 0);
244 #endif
uint8_t getPciSubclassCode()
Definition: Device.h:214
virtual void setInterruptNumber(uintptr_t n)
Definition: Device.h:268
virtual Vector< Address * > & addresses()
Definition: Device.h:256
virtual uintptr_t getInterruptNumber()
Definition: Device.h:262
Definition: Device.h:43
#define WARNING(text)
Definition: Log.h:78
uint16_t getPciDeviceId()
Definition: Device.h:224
static void foreach(Callback callback, Device *root=0)
Definition: Device.cc:94
virtual Type getType()
Definition: Device.h:163
#define ERROR(text)
Definition: Log.h:82
uint8_t getPciClassCode()
Definition: Device.h:209
uint16_t getPciVendorId()
Definition: Device.h:219