1/*
2** Copyright 2007, Marcus Overhagen. All rights reserved.
3** Copyright 2002/03, Thomas Kurschel. All rights reserved.
4** Distributed under the terms of the Haiku License.
5*/
6
7/*
8	Part of Open IDE bus manager
9
10	Device manager
11
12	As the IDE bus manager is an SCSI to IDE translater, it
13	has to know a bit more about connected devices then a standard
14	SIM. This file contains device detection and classification.
15*/
16
17#include "ide_internal.h"
18#include "ide_sim.h"
19#include "ide_cmds.h"
20
21#include <string.h>
22#include <malloc.h>
23#include <ByteOrder.h>
24
25#define TRACE(x...) dprintf("IDE: " x)
26
27/** cleanup links devices on one bus when <device> is deleted */
28
29static void
30cleanup_device_links(ide_device_info *device)
31{
32	ide_bus_info *bus = device->bus;
33
34	TRACE("cleanup_device_links: device %p\n", device);
35
36	bus->devices[device->is_device1] = NULL;
37
38	if (device->other_device) {
39		if (device->other_device != device) {
40			device->other_device->other_device = device->other_device;
41			bus->first_device = device->other_device;
42		} else
43			bus->first_device = NULL;
44	}
45
46	device->other_device = NULL;
47}
48
49
50/** destroy device info */
51
52static void
53destroy_device(ide_device_info *device)
54{
55	TRACE("destroy_device: device %p\n", device);
56
57	// paranoia
58	device->exec_io = NULL;
59	cancel_timer(&device->reconnect_timer.te);
60
61	scsi->free_dpc(device->reconnect_timeout_dpc);
62
63	cleanup_device_links(device);
64
65	destroy_qreq_array(device);
66
67	uninit_synced_pc(&device->reconnect_timeout_synced_pc);
68
69	free(device);
70}
71
72
73/** setup links between the devices on one bus */
74
75static void
76setup_device_links(ide_bus_info *bus, ide_device_info *device)
77{
78	TRACE("setup_device_links: bus %p, device %p\n", bus, device);
79
80	device->bus = bus;
81	bus->devices[device->is_device1] = device;
82
83	device->other_device = device;
84
85	if (device->is_device1) {
86		if (bus->devices[0]) {
87			device->other_device = bus->devices[0];
88			bus->devices[0]->other_device = device;
89		}
90	} else {
91		if (bus->devices[1]) {
92			device->other_device = bus->devices[1];
93			bus->devices[1]->other_device = device;
94		}
95	}
96
97	if (bus->first_device == NULL)
98		bus->first_device = device;
99}
100
101
102/** create device info */
103
104static ide_device_info *
105create_device(ide_bus_info *bus, bool is_device1)
106{
107	ide_device_info *device;
108
109	TRACE("create_device: bus %p, device-number %d\n", bus, is_device1);
110
111	device = (ide_device_info *)malloc(sizeof(*device));
112	if (device == NULL)
113		return NULL;
114
115	memset(device, 0, sizeof(*device));
116
117	device->is_device1 = is_device1;
118	device->target_id = is_device1;
119
120	setup_device_links(bus, device);
121
122	device->DMA_failures = 0;
123	device->CQ_failures = 0;
124	device->num_failed_send = 0;
125
126	device->combined_sense = 0;
127
128	device->num_running_reqs = 0;
129
130	device->reconnect_timer.device = device;
131
132	init_synced_pc(&device->reconnect_timeout_synced_pc,
133		reconnect_timeout_worker);
134
135	if (scsi->alloc_dpc(&device->reconnect_timeout_dpc) != B_OK)
136		goto err;
137
138	device->total_sectors = 0;
139	return device;
140
141err:
142	destroy_device(device);
143	return NULL;
144}
145
146#if B_HOST_IS_LENDIAN
147
148#define B_BENDIAN_TO_HOST_MULTI(v, n) do {		\
149	size_t __swap16_multi_n = (n);				\
150	uint16 *__swap16_multi_v = (v);				\
151												\
152	while( __swap16_multi_n ) {					\
153		*__swap16_multi_v = B_SWAP_INT16(*__swap16_multi_v); \
154		__swap16_multi_v++;						\
155		__swap16_multi_n--;						\
156	}											\
157} while (0)
158
159#else
160
161#define B_BENDIAN_TO_HOST_MULTI(v, n)
162
163#endif
164
165
166/** prepare infoblock for further use, i.e. fix endianess */
167
168static void
169prep_infoblock(ide_device_info *device)
170{
171	ide_device_infoblock *infoblock = &device->infoblock;
172
173	B_BENDIAN_TO_HOST_MULTI((uint16 *)infoblock->serial_number,
174		sizeof(infoblock->serial_number) / 2);
175
176	B_BENDIAN_TO_HOST_MULTI( (uint16 *)infoblock->firmware_version,
177		sizeof(infoblock->firmware_version) / 2);
178
179	B_BENDIAN_TO_HOST_MULTI( (uint16 *)infoblock->model_number,
180		sizeof(infoblock->model_number) / 2);
181
182	infoblock->LBA_total_sectors = B_LENDIAN_TO_HOST_INT32(infoblock->LBA_total_sectors);
183	infoblock->LBA48_total_sectors = B_LENDIAN_TO_HOST_INT64(infoblock->LBA48_total_sectors);
184}
185
186
187/** read info block of ATA or ATAPI device */
188
189static bool
190scan_device_int(ide_device_info *device, bool atapi)
191{
192	ide_bus_info *bus = device->bus;
193	int status;
194
195	TRACE("scan_device_int: device %p, atapi %d\n", device, atapi);
196
197	device->tf_param_mask = 0;
198	device->tf.write.command = atapi ? IDE_CMD_IDENTIFY_PACKET_DEVICE
199		: IDE_CMD_IDENTIFY_DEVICE;
200
201	// initialize device selection flags,
202	// this is the only place where this bit gets initialized in the task file
203	if (bus->controller->read_command_block_regs(bus->channel_cookie, &device->tf,
204			ide_mask_device_head) != B_OK) {
205		TRACE("scan_device_int: read_command_block_regs failed\n");
206		return false;
207	}
208
209	device->tf.lba.device = device->is_device1;
210
211	if (!send_command(device, NULL, atapi ? false : true, 20, ide_state_sync_waiting)) {
212		TRACE("scan_device_int: send_command failed\n");
213		return false;
214	}
215
216	// do a short wait first - if there's no device at all we could wait forever
217	// ToDo: have a look at this; if it times out (when the time is too short),
218	//		the kernel seems to crash a little later)!
219	TRACE("scan_device_int: waiting 100ms...\n");
220	if (acquire_sem_etc(bus->sync_wait_sem, 1, B_RELATIVE_TIMEOUT, 100000) == B_TIMED_OUT) {
221		bool cont;
222
223		TRACE("scan_device_int: no fast response to inquiry\n");
224
225		// check the busy flag - if it's still set, there's probably no device
226		IDE_LOCK(bus);
227
228		status = bus->controller->get_altstatus(bus->channel_cookie);
229		cont = (status & ide_status_bsy) == ide_status_bsy;
230
231		IDE_UNLOCK(bus);
232
233		TRACE("scan_device_int: status %#04x\n", status);
234
235		if (!cont) {
236			TRACE("scan_device_int: busy bit not set after 100ms - probably noone there\n");
237			// no reaction -> abort waiting
238			cancel_irq_timeout(bus);
239
240			// timeout or irq may have been fired, reset semaphore just is case
241			acquire_sem_etc(bus->sync_wait_sem, 1, B_RELATIVE_TIMEOUT, 0);
242
243			TRACE("scan_device_int: aborting because busy bit not set\n");
244			return false;
245		}
246
247		TRACE("scan_device_int: busy bit set, give device more time\n");
248
249		// there is something, so wait for it
250		acquire_sem(bus->sync_wait_sem);
251	}
252	TRACE("scan_device_int: got a fast response\n");
253
254	// cancel the timeout manually; usually this is done by wait_for_sync(), but
255	// we've used the wait semaphore directly
256	cancel_irq_timeout(bus);
257
258	if (bus->sync_wait_timeout) {
259		TRACE("scan_device_int: aborting on sync_wait_timeout\n");
260		return false;
261	}
262
263	ide_wait(device, ide_status_drq, ide_status_bsy, true, 1000);
264
265	status = bus->controller->get_altstatus(bus->channel_cookie);
266
267	if ((status & ide_status_err) != 0) {
268		// if there's no device, all bits including the error bit are set
269		TRACE("scan_device_int: error bit set - no device or wrong type (status: %#04x)\n", status);
270		return false;
271	}
272
273	// get the infoblock
274	bus->controller->read_pio(bus->channel_cookie, (uint16 *)&device->infoblock,
275		sizeof(device->infoblock) / sizeof(uint16), false);
276
277	if (!wait_for_drqdown(device)) {
278		TRACE("scan_device_int: wait_for_drqdown failed\n");
279		return false;
280	}
281
282	TRACE("scan_device_int: device found\n");
283
284	prep_infoblock(device);
285	return true;
286}
287
288
289/** scan one device */
290
291void
292scan_device_worker(ide_bus_info *bus, void *arg)
293{
294	int is_device1 = (int)arg;
295	ide_device_info *device;
296
297	TRACE("scan_device_worker: bus %p, device-number %d\n", bus, is_device1);
298
299	// forget everything we know about the device;
300	// don't care about peripheral drivers using this device
301	// as the device info is only used by us and not published
302	// directly or indirectly to the SCSI bus manager
303	if (bus->devices[is_device1])
304		destroy_device(bus->devices[is_device1]);
305
306	device = create_device(bus, is_device1);
307
308	// reset status so we can see what goes wrong during detection
309	device->subsys_status = SCSI_REQ_CMP;
310
311	if (scan_device_int(device, false)) {
312		if (!prep_ata(device))
313			goto err;
314	} else if (device->subsys_status != SCSI_TID_INVALID
315				&& scan_device_int(device, true)) {
316		// only try ATAPI if there is at least some device
317		// (see send_command - this error code must be unique!)
318		if (!prep_atapi(device))
319			goto err;
320	} else
321		goto err;
322
323	bus->state = ide_state_idle;
324	release_sem(bus->scan_device_sem);
325	return;
326
327err:
328	destroy_device(device);
329
330	bus->state = ide_state_idle;
331	release_sem(bus->scan_device_sem);
332}
333