1/*
2 * Copyright 2007-2009, Marcus Overhagen. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include "ahci_controller.h"
7
8#include <KernelExport.h>
9#include <string.h>
10#include <new>
11
12#define TRACE(a...) dprintf("ahci: " a)
13//#define FLOW(a...)	dprintf("ahci: " a)
14#define FLOW(a...)
15
16
17//	#pragma mark - SIM module interface
18
19
20static void
21ahci_set_scsi_bus(scsi_sim_cookie cookie, scsi_bus bus)
22{
23}
24
25
26//! execute request
27static void
28ahci_scsi_io(scsi_sim_cookie cookie, scsi_ccb *request)
29{
30	FLOW("ahci_scsi_io, cookie %p, path_id %u, target_id %u, target_lun %u\n",
31		cookie, request->path_id, request->target_id, request->target_lun);
32	static_cast<AHCIController *>(cookie)->ExecuteRequest(request);
33}
34
35
36//! abort request
37static uchar
38ahci_abort_io(scsi_sim_cookie cookie, scsi_ccb *request)
39{
40	TRACE("ahci_abort_io, cookie %p\n", cookie);
41	return static_cast<AHCIController *>(cookie)->AbortRequest(request);
42}
43
44
45static uchar
46ahci_reset_device(scsi_sim_cookie cookie, uchar targetID, uchar targetLUN)
47{
48	TRACE("ahci_reset_device, cookie %p\n", cookie);
49	return static_cast<AHCIController *>(cookie)->ResetDevice(targetID, targetLUN);
50}
51
52
53//! terminate request
54static uchar
55ahci_terminate_io(scsi_sim_cookie cookie, scsi_ccb *request)
56{
57	TRACE("ahci_terminate_io, cookie %p\n", cookie);
58	return static_cast<AHCIController *>(cookie)->TerminateRequest(request);
59}
60
61
62//! get information about bus
63static uchar
64ahci_path_inquiry(scsi_sim_cookie cookie, scsi_path_inquiry *info)
65{
66	TRACE("ahci_path_inquiry, cookie %p\n", cookie);
67
68	memset(info, 0, sizeof(*info));
69	info->version_num = 1;
70	// supports tagged requests and soft reset
71	info->hba_inquiry = 0; // SCSI_PI_TAG_ABLE | SCSI_PI_SOFT_RST;
72	// controller is 32, devices are 0 to 31
73	info->initiator_id = 32;
74	// adapter command queue size
75	info->hba_queue_size = 1;
76
77	return SCSI_REQ_CMP;
78}
79
80
81//! this is called immediately before the SCSI bus manager scans the bus
82static uchar
83ahci_scan_bus(scsi_sim_cookie cookie)
84{
85	TRACE("ahci_scan_bus, cookie %p\n", cookie);
86
87	return SCSI_REQ_CMP;
88}
89
90
91static uchar
92ahci_reset_bus(scsi_sim_cookie cookie)
93{
94	TRACE("ahci_reset_bus, cookie %p\n", cookie);
95
96	return SCSI_REQ_CMP;
97}
98
99
100/*!	Get restrictions of one device
101	(used for non-SCSI transport protocols and bug fixes)
102*/
103static void
104ahci_get_restrictions(scsi_sim_cookie cookie, uchar targetID, bool *isATAPI,
105	bool *noAutoSense, uint32 *maxBlocks)
106{
107	TRACE("ahci_get_restrictions, cookie %p\n", cookie);
108
109	static_cast<AHCIController *>(cookie)->GetRestrictions(targetID, isATAPI, noAutoSense, maxBlocks);
110}
111
112
113static status_t
114ahci_ioctl(scsi_sim_cookie cookie, uint8 targetID, uint32 op, void *buffer,
115	size_t length)
116{
117	TRACE("ahci_ioctl, cookie %p\n", cookie);
118	return B_DEV_INVALID_IOCTL;
119}
120
121
122//	#pragma mark -
123
124
125static status_t
126ahci_sim_init_bus(device_node *node, void **_cookie)
127{
128	TRACE("ahci_sim_init_bus\n");
129
130	// get the PCI device from our parent's parent
131	device_node *parent = gDeviceManager->get_parent_node(node);
132	device_node *pciParent = gDeviceManager->get_parent_node(parent);
133	gDeviceManager->put_node(parent);
134
135	pci_device_module_info *pci;
136	pci_device *pciDevice;
137	gDeviceManager->get_driver(pciParent, (driver_module_info **)&pci,
138		(void **)&pciDevice);
139	gDeviceManager->put_node(pciParent);
140
141	TRACE("ahci_sim_init_bus: pciDevice %p\n", pciDevice);
142
143	AHCIController *controller =  new(std::nothrow) AHCIController(node, pci,
144		pciDevice);
145	if (!controller)
146		return B_NO_MEMORY;
147	status_t status = controller->Init();
148	if (status < B_OK) {
149		delete controller;
150		return status;
151	}
152
153	*_cookie = controller;
154	TRACE("cookie = %p\n", *_cookie);
155	return B_OK;
156}
157
158
159static void
160ahci_sim_uninit_bus(void *cookie)
161{
162	TRACE("ahci_sim_uninit_bus, cookie %p\n", cookie);
163	AHCIController *controller = static_cast<AHCIController *>(cookie);
164
165	controller->Uninit();
166	delete controller;
167}
168
169
170static void
171ahci_sim_bus_removed(void *cookie)
172{
173	TRACE("ahci_sim_bus_removed, cookie %p\n", cookie);
174}
175
176
177static status_t
178std_ops(int32 op, ...)
179{
180	switch (op) {
181		case B_MODULE_INIT:
182		case B_MODULE_UNINIT:
183			return B_OK;
184
185		default:
186			return B_ERROR;
187	}
188}
189
190
191scsi_sim_interface gAHCISimInterface = {
192	{
193		{
194			AHCI_SIM_MODULE_NAME,
195			0,
196			std_ops
197		},
198		NULL,	// supported devices
199		NULL,	// register node
200		ahci_sim_init_bus,
201		ahci_sim_uninit_bus,
202		NULL,	// register child devices
203		NULL,	// rescan
204		ahci_sim_bus_removed
205	},
206	ahci_set_scsi_bus,
207	ahci_scsi_io,
208	ahci_abort_io,
209	ahci_reset_device,
210	ahci_terminate_io,
211	ahci_path_inquiry,
212	ahci_scan_bus,
213	ahci_reset_bus,
214	ahci_get_restrictions,
215	ahci_ioctl
216};
217