ata-lowlevel.c revision 124403
1119404Ssos/*-
2124403Ssos * Copyright (c) 1998 - 2004 S�ren Schmidt <sos@FreeBSD.org>
3119404Ssos * All rights reserved.
4119404Ssos *
5119404Ssos * Redistribution and use in source and binary forms, with or without
6119404Ssos * modification, are permitted provided that the following conditions
7119404Ssos * are met:
8119404Ssos * 1. Redistributions of source code must retain the above copyright
9119404Ssos *    notice, this list of conditions and the following disclaimer,
10119404Ssos *    without modification, immediately at the beginning of the file.
11119404Ssos * 2. Redistributions in binary form must reproduce the above copyright
12119404Ssos *    notice, this list of conditions and the following disclaimer in the
13119404Ssos *    documentation and/or other materials provided with the distribution.
14119404Ssos * 3. The name of the author may not be used to endorse or promote products
15119404Ssos *    derived from this software without specific prior written permission.
16119404Ssos *
17119404Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18119404Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19119404Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20119404Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21119404Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22119404Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23119404Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24119404Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25119404Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26119404Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27119404Ssos */
28119404Ssos
29119418Sobrien#include <sys/cdefs.h>
30119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/ata/ata-lowlevel.c 124403 2004-01-11 22:08:34Z sos $");
31119418Sobrien
32119404Ssos#include "opt_ata.h"
33119404Ssos#include <sys/param.h>
34119404Ssos#include <sys/systm.h>
35119404Ssos#include <sys/ata.h>
36119404Ssos#include <sys/kernel.h>
37119404Ssos#include <sys/conf.h>
38119404Ssos#include <sys/bus.h>
39124403Ssos#include <sys/sema.h>
40119404Ssos#include <sys/taskqueue.h>
41119404Ssos#include <machine/bus.h>
42119404Ssos#include <sys/rman.h>
43119404Ssos#include <dev/ata/ata-all.h>
44119404Ssos
45119404Ssos/* prototypes */
46119450Ssosstatic int ata_transaction(struct ata_request *);
47119450Ssosstatic void ata_interrupt(void *);
48119450Ssosstatic void ata_reset(struct ata_channel *);
49119450Ssosstatic int ata_wait(struct ata_device *, u_int8_t);
50119450Ssosstatic int ata_command(struct ata_device *, u_int8_t, u_int64_t, u_int16_t, u_int16_t);
51119450Ssosstatic void ata_pio_read(struct ata_request *, int);
52119450Ssosstatic void ata_pio_write(struct ata_request *, int);
53119404Ssos
54119404Ssos/* local vars */
55119404Ssosstatic int atadebug = 0;
56119404Ssos
57119404Ssos/*
58119404Ssos * low level ATA functions
59119404Ssos */
60119404Ssosvoid
61119404Ssosata_generic_hw(struct ata_channel *ch)
62119404Ssos{
63119404Ssos    ch->hw.reset = ata_reset;
64119404Ssos    ch->hw.transaction = ata_transaction;
65119404Ssos    ch->hw.interrupt = ata_interrupt;
66119404Ssos}
67119404Ssos
68119404Ssos/* must be called with ATA channel locked */
69119404Ssosstatic int
70119404Ssosata_transaction(struct ata_request *request)
71119404Ssos{
72124403Ssos    /* safety check, device might have been detached FIXME SOS */
73124403Ssos    if (!request->device->param) {
74124403Ssos	request->result = ENXIO;
75124403Ssos	return ATA_OP_FINISHED;
76124403Ssos    }
77124403Ssos
78119404Ssos    /* record the request as running */
79119404Ssos    request->device->channel->running = request;
80119404Ssos
81124403Ssos    ATA_DEBUG_RQ(request, "transaction");
82124403Ssos
83119404Ssos    /* disable ATAPI DMA writes if HW doesn't support it */
84120938Ssos    if ((request->device->channel->flags & ATA_ATAPI_DMA_RO) &&
85120938Ssos	((request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE)) ==
86120938Ssos	 (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE)))
87119404Ssos	request->flags &= ~ATA_R_DMA;
88119404Ssos
89119404Ssos    switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) {
90119404Ssos
91119404Ssos    /* ATA PIO data transfer and control commands */
92119404Ssos    default:
93119404Ssos	{
94124403Ssos	/* record command direction here as our request might be gone later */
95119404Ssos	int write = (request->flags & ATA_R_WRITE);
96119404Ssos
97119404Ssos	    /* issue command */
98119404Ssos	    if (ata_command(request->device, request->u.ata.command,
99119404Ssos			    request->u.ata.lba, request->u.ata.count,
100119404Ssos			    request->u.ata.feature)) {
101119404Ssos		ata_prtdev(request->device, "error issueing PIO command\n");
102119404Ssos		request->result = EIO;
103120881Ssos		break;
104119404Ssos	    }
105119404Ssos
106119404Ssos	    /* if write command output the data */
107119404Ssos	    if (write) {
108119404Ssos		if (ata_wait(request->device,
109119404Ssos			     (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) {
110119404Ssos		    ata_prtdev(request->device,"timeout waiting for write DRQ");
111119404Ssos		    request->result = EIO;
112120881Ssos		    break;
113119404Ssos		}
114119404Ssos		ata_pio_write(request, request->transfersize);
115119404Ssos	    }
116119404Ssos	}
117124403Ssos
118119404Ssos	/* return and wait for interrupt */
119119404Ssos	return ATA_OP_CONTINUES;
120119404Ssos
121119404Ssos    /* ATA DMA data transfer commands */
122119404Ssos    case ATA_R_DMA:
123121310Ssos	/* check sanity, setup SG list and DMA engine */
124121310Ssos	if (request->device->channel->dma->load(request->device,
125121310Ssos						request->data,
126121310Ssos						request->bytecount,
127121310Ssos						request->flags & ATA_R_READ)) {
128119404Ssos	    ata_prtdev(request->device, "setting up DMA failed\n");
129119404Ssos	    request->result = EIO;
130120881Ssos	    break;
131119404Ssos	}
132119404Ssos
133119404Ssos	/* issue command */
134119404Ssos	if (ata_command(request->device, request->u.ata.command,
135119404Ssos			request->u.ata.lba, request->u.ata.count,
136119404Ssos			request->u.ata.feature)) {
137119404Ssos	    ata_prtdev(request->device, "error issuing DMA command\n");
138119404Ssos	    request->result = EIO;
139120881Ssos	    break;
140119404Ssos	}
141119404Ssos
142119404Ssos	/* start DMA engine */
143121310Ssos	if (request->device->channel->dma->start(request->device->channel)) {
144120881Ssos	    ata_prtdev(request->device, "error starting DMA\n");
145119404Ssos	    request->result = EIO;
146120881Ssos	    break;
147119404Ssos	}
148124403Ssos
149119404Ssos	/* return and wait for interrupt */
150119404Ssos	return ATA_OP_CONTINUES;
151119404Ssos
152119404Ssos    /* ATAPI PIO commands */
153119404Ssos    case ATA_R_ATAPI:
154119404Ssos	/* is this just a POLL DSC command ? */
155119404Ssos	if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) {
156119404Ssos	    ATA_IDX_OUTB(request->device->channel, ATA_DRIVE,
157119404Ssos			 ATA_D_IBM | request->device->unit);
158119404Ssos	    DELAY(10);
159119404Ssos	    if (!(ATA_IDX_INB(request->device->channel, ATA_ALTSTAT)&ATA_S_DSC))
160119404Ssos		request->result = EBUSY;
161120881Ssos	    break;
162119404Ssos	}
163119404Ssos
164119404Ssos	/* start ATAPI operation */
165119404Ssos	if (ata_command(request->device, ATA_PACKET_CMD,
166119404Ssos			request->transfersize << 8, 0, 0)) {
167119404Ssos	    ata_prtdev(request->device, "error issuing ATA PACKET command\n");
168119404Ssos	    request->result = EIO;
169120881Ssos	    break;
170119404Ssos	}
171119404Ssos
172119404Ssos	/* command interrupt device ? just return and wait for interrupt */
173119404Ssos	if ((request->device->param->config & ATA_DRQ_MASK) == ATA_DRQ_INTR)
174119404Ssos	    return ATA_OP_CONTINUES;
175119404Ssos
176119404Ssos	/* wait for ready to write ATAPI command block */
177119404Ssos	{
178119404Ssos	    int timeout = 5000; /* might be less for fast devices */
179119404Ssos	    while (timeout--) {
180119404Ssos		int reason = ATA_IDX_INB(request->device->channel, ATA_IREASON);
181119404Ssos		int status = ATA_IDX_INB(request->device->channel, ATA_STATUS);
182119404Ssos
183119404Ssos		if (((reason & (ATA_I_CMD | ATA_I_IN)) |
184119404Ssos		     (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT)
185119404Ssos		    break;
186119404Ssos		DELAY(20);
187119404Ssos	    }
188119404Ssos	    if (timeout <= 0) {
189119404Ssos		ata_prtdev(request->device,
190119404Ssos			   "timeout waiting for ATAPI ready\n");
191119404Ssos		request->result = EIO;
192120881Ssos		break;
193119404Ssos	    }
194119404Ssos	}
195119404Ssos
196119404Ssos	/* this seems to be needed for some (slow) devices */
197119404Ssos	DELAY(10);
198119404Ssos
199119404Ssos	/* output actual command block */
200119404Ssos	ATA_IDX_OUTSW_STRM(request->device->channel, ATA_DATA,
201119404Ssos			   (int16_t *)request->u.atapi.ccb,
202119404Ssos			   (request->device->param->config & ATA_PROTO_MASK) ==
203119404Ssos			   ATA_PROTO_ATAPI_12 ? 6 : 8);
204119404Ssos
205119404Ssos	/* return and wait for interrupt */
206119404Ssos	return ATA_OP_CONTINUES;
207119404Ssos
208119404Ssos    case ATA_R_ATAPI|ATA_R_DMA:
209119404Ssos	/* is this just a POLL DSC command ? */
210119404Ssos	if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) {
211119404Ssos	    ATA_IDX_OUTB(request->device->channel, ATA_DRIVE,
212119404Ssos			 ATA_D_IBM | request->device->unit);
213119404Ssos	    DELAY(10);
214119404Ssos	    if (!(ATA_IDX_INB(request->device->channel, ATA_ALTSTAT)&ATA_S_DSC))
215119404Ssos		request->result = EBUSY;
216120881Ssos	    break;
217119404Ssos	}
218119404Ssos
219121310Ssos	/* check sanity, setup SG list and DMA engine */
220121310Ssos	if (request->device->channel->dma->load(request->device,
221121310Ssos						request->data,
222121310Ssos						request->bytecount,
223121310Ssos						request->flags & ATA_R_READ)) {
224119404Ssos	    ata_prtdev(request->device, "setting up DMA failed\n");
225119404Ssos	    request->result = EIO;
226120881Ssos	    break;
227119404Ssos	}
228119404Ssos
229119404Ssos	/* start ATAPI operation */
230119404Ssos	if (ata_command(request->device, ATA_PACKET_CMD, 0, 0, ATA_F_DMA)) {
231119404Ssos	    ata_prtdev(request->device, "error issuing ATAPI packet command\n");
232119404Ssos	    request->result = EIO;
233120881Ssos	    break;
234119404Ssos	}
235119404Ssos
236119404Ssos	/* wait for ready to write ATAPI command block */
237119404Ssos	{
238119404Ssos	    int timeout = 5000; /* might be less for fast devices */
239119404Ssos	    while (timeout--) {
240119404Ssos		int reason = ATA_IDX_INB(request->device->channel, ATA_IREASON);
241119404Ssos		int status = ATA_IDX_INB(request->device->channel, ATA_STATUS);
242119404Ssos
243119404Ssos		if (((reason & (ATA_I_CMD | ATA_I_IN)) |
244119404Ssos		     (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT)
245119404Ssos		    break;
246119404Ssos		DELAY(20);
247119404Ssos	    }
248119404Ssos	    if (timeout <= 0) {
249120881Ssos		ata_prtdev(request->device,"timeout waiting for ATAPI ready\n");
250119404Ssos		request->result = EIO;
251120881Ssos		break;
252119404Ssos	    }
253119404Ssos	}
254119404Ssos
255119404Ssos	/* this seems to be needed for some (slow) devices */
256119404Ssos	DELAY(10);
257119404Ssos
258119404Ssos	/* output actual command block */
259119404Ssos	ATA_IDX_OUTSW_STRM(request->device->channel, ATA_DATA,
260119404Ssos			   (int16_t *)request->u.atapi.ccb,
261119404Ssos			   (request->device->param->config & ATA_PROTO_MASK) ==
262119404Ssos			   ATA_PROTO_ATAPI_12 ? 6 : 8);
263119404Ssos
264119404Ssos	/* start DMA engine */
265121310Ssos	if (request->device->channel->dma->start(request->device->channel)) {
266119404Ssos	    request->result = EIO;
267120881Ssos	    break;
268119404Ssos	}
269119404Ssos
270119404Ssos	/* return and wait for interrupt */
271119404Ssos	return ATA_OP_CONTINUES;
272119404Ssos    }
273120881Ssos
274120881Ssos    /* request finish here */
275121311Ssos    if (request->device->channel->dma->flags & ATA_DMA_ACTIVE)
276121311Ssos	request->device->channel->dma->unload(request->device->channel);
277120881Ssos    request->device->channel->running = NULL;
278120881Ssos    return ATA_OP_FINISHED;
279119404Ssos}
280119404Ssos
281119404Ssosstatic void
282119404Ssosata_interrupt(void *data)
283119404Ssos{
284119404Ssos    struct ata_channel *ch = (struct ata_channel *)data;
285119404Ssos    struct ata_request *request = ch->running;
286119404Ssos    int length;
287119404Ssos
288120128Ssos    /* ignore this interrupt if there is no running request */
289120128Ssos    if (!request) {
290120128Ssos	if (ATA_LOCK_CH(ch, ATA_CONTROL)) {
291120128Ssos	    u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS);
292120128Ssos	    u_int8_t error = ATA_IDX_INB(ch, ATA_ERROR);
293120128Ssos
294120128Ssos	    if (bootverbose)
295120128Ssos		ata_printf(ch, -1,
296120128Ssos			   "spurious interrupt - status=0x%02x error=0x%02x\n",
297120128Ssos			   status, error);
298120128Ssos	    ATA_UNLOCK_CH(ch);
299120128Ssos	}
300120128Ssos	else {
301120128Ssos	    if (bootverbose)
302120128Ssos		ata_printf(ch, -1, "spurious interrupt - channel busy\n");
303120128Ssos	}
304119878Ssos	return;
305120128Ssos    }
306119878Ssos
307124403Ssos    ATA_DEBUG_RQ(request, "interrupt");
308124403Ssos
309120128Ssos    /* ignore interrupt if device is busy */
310124403Ssos    if (!(request->flags & ATA_R_TIMEOUT) &&
311124403Ssos	ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) {
312119878Ssos	DELAY(100);
313119878Ssos	if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DRQ))
314119878Ssos	    return;
315119878Ssos    }
316119878Ssos
317124403Ssos    ATA_DEBUG_RQ(request, "interrupt accepted");
318124403Ssos
319119878Ssos    /* clear interrupt and get status */
320120128Ssos    request->status = ATA_IDX_INB(ch, ATA_STATUS);
321119878Ssos
322124403Ssos    request->flags |= ATA_R_INTR_SEEN;
323124403Ssos
324121910Ssos    switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_CONTROL)) {
325119404Ssos
326119404Ssos    /* ATA PIO data transfer and control commands */
327119404Ssos    default:
328119404Ssos
329121910Ssos	/* on control commands read back registers to the request struct */
330121910Ssos	if (request->flags & ATA_R_CONTROL) {
331121910Ssos	    request->u.ata.count = ATA_IDX_INB(ch, ATA_COUNT);
332121910Ssos	    request->u.ata.lba = ATA_IDX_INB(ch, ATA_SECTOR) |
333121910Ssos				 (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) |
334121910Ssos				 (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16);
335121910Ssos	}
336121910Ssos
337119404Ssos	/* if we got an error we are done with the HW */
338119404Ssos	if (request->status & ATA_S_ERROR) {
339119404Ssos	    request->error = ATA_IDX_INB(ch, ATA_ERROR);
340119404Ssos	    break;
341119404Ssos	}
342119404Ssos
343121910Ssos	/* are we moving data ? */
344121910Ssos	if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
345119404Ssos
346121910Ssos	    /* if read data get it */
347121910Ssos	    if (request->flags & ATA_R_READ)
348121910Ssos		ata_pio_read(request, request->transfersize);
349119404Ssos
350121910Ssos	    /* update how far we've gotten */
351121910Ssos		request->donecount += request->transfersize;
352119404Ssos
353121910Ssos	    /* do we need a scoop more ? */
354121910Ssos	    if (request->bytecount > request->donecount) {
355119404Ssos
356121910Ssos		/* set this transfer size according to HW capabilities */
357121910Ssos		request->transfersize =
358121910Ssos		    min((request->bytecount - request->donecount),
359121910Ssos			request->transfersize);
360120204Ssos
361121910Ssos		/* if data write command, output the data */
362121910Ssos		if (request->flags & ATA_R_WRITE) {
363121910Ssos
364121910Ssos		    /* if we get an error here we are done with the HW */
365121910Ssos		    if (ata_wait(request->device,
366121910Ssos				 (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) {
367121910Ssos			ata_prtdev(request->device,
368121910Ssos				   "timeout waiting for write DRQ");
369121910Ssos			request->status = ATA_IDX_INB(ch, ATA_STATUS);
370121910Ssos			break;
371121910Ssos		    }
372121910Ssos
373121910Ssos		    /* output data and return waiting for new interrupt */
374121910Ssos		    ata_pio_write(request, request->transfersize);
375121910Ssos		    return;
376119404Ssos		}
377120204Ssos
378121910Ssos		/* if data read command, return & wait for interrupt */
379121910Ssos		if (request->flags & ATA_R_READ)
380121910Ssos		    return;
381119404Ssos	    }
382119404Ssos	}
383119404Ssos	/* done with HW */
384119404Ssos	break;
385119404Ssos
386119404Ssos    /* ATA DMA data transfer commands */
387119404Ssos    case ATA_R_DMA:
388119404Ssos	/* stop DMA engine and get status */
389119404Ssos	request->dmastat = ch->dma->stop(ch);
390119404Ssos
391119404Ssos	/* did we get error or data */
392119404Ssos	if (request->status & ATA_S_ERROR)
393119404Ssos	    request->error = ATA_IDX_INB(ch, ATA_ERROR);
394119404Ssos	else if (request->dmastat & ATA_BMSTAT_ERROR)
395119404Ssos	    request->status |= ATA_S_ERROR;
396119404Ssos	else
397119404Ssos	    request->donecount = request->bytecount;
398119404Ssos
399121310Ssos	/* release SG list etc */
400121310Ssos	ch->dma->unload(ch);
401121310Ssos
402119404Ssos	/* done with HW */
403119404Ssos	break;
404119404Ssos
405119404Ssos    /* ATAPI PIO commands */
406119404Ssos    case ATA_R_ATAPI:
407119404Ssos	length = ATA_IDX_INB(ch, ATA_CYL_LSB)|(ATA_IDX_INB(ch, ATA_CYL_MSB)<<8);
408119404Ssos
409119404Ssos	switch ((ATA_IDX_INB(ch, ATA_IREASON) & (ATA_I_CMD | ATA_I_IN)) |
410119404Ssos		(request->status & ATA_S_DRQ)) {
411119404Ssos
412119404Ssos	case ATAPI_P_CMDOUT:
413119404Ssos	    /* this seems to be needed for some (slow) devices */
414119404Ssos	    DELAY(10);
415119404Ssos
416119404Ssos	    if (!(request->status & ATA_S_DRQ)) {
417119404Ssos		ata_prtdev(request->device, "command interrupt without DRQ\n");
418119404Ssos		request->status = ATA_S_ERROR;
419119404Ssos		break;
420119404Ssos	    }
421119404Ssos	    ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb,
422119404Ssos			       (request->device->param->config &
423119404Ssos				ATA_PROTO_MASK)== ATA_PROTO_ATAPI_12 ? 6 : 8);
424119404Ssos	    /* return wait for interrupt */
425119404Ssos	    return;
426119404Ssos
427119404Ssos	case ATAPI_P_WRITE:
428119404Ssos	    if (request->flags & ATA_R_READ) {
429119404Ssos		request->status = ATA_S_ERROR;
430119404Ssos		ata_prtdev(request->device,
431119404Ssos			   "%s trying to write on read buffer\n",
432119404Ssos			   ata_cmd2str(request));
433119404Ssos		break;
434119404Ssos	    }
435119404Ssos	    ata_pio_write(request, length);
436119404Ssos	    request->donecount += length;
437119404Ssos
438119404Ssos	    /* set next transfer size according to HW capabilities */
439119404Ssos	    request->transfersize = min((request->bytecount-request->donecount),
440119404Ssos					request->transfersize);
441119404Ssos	    /* return wait for interrupt */
442119404Ssos	    return;
443119404Ssos
444119404Ssos	case ATAPI_P_READ:
445119404Ssos	    if (request->flags & ATA_R_WRITE) {
446119404Ssos		request->status = ATA_S_ERROR;
447119404Ssos		ata_prtdev(request->device,
448119404Ssos			   "%s trying to read on write buffer\n",
449119404Ssos			   ata_cmd2str(request));
450119404Ssos		break;
451119404Ssos	    }
452119404Ssos	    ata_pio_read(request, length);
453119404Ssos	    request->donecount += length;
454119404Ssos
455119404Ssos	    /* set next transfer size according to HW capabilities */
456119404Ssos	    request->transfersize = min((request->bytecount-request->donecount),
457119404Ssos					request->transfersize);
458119404Ssos	    /* return wait for interrupt */
459119404Ssos	    return;
460119404Ssos
461119404Ssos	case ATAPI_P_DONEDRQ:
462119404Ssos	    ata_prtdev(request->device,
463119404Ssos		       "WARNING - %s DONEDRQ non conformant device\n",
464119404Ssos		       ata_cmd2str(request));
465119404Ssos	    if (request->flags & ATA_R_READ) {
466119404Ssos		ata_pio_read(request, length);
467119404Ssos		request->donecount += length;
468119404Ssos	    }
469119404Ssos	    else if (request->flags & ATA_R_WRITE) {
470119404Ssos		ata_pio_write(request, length);
471119404Ssos		request->donecount += length;
472119404Ssos	    }
473119404Ssos	    else
474119404Ssos		request->status = ATA_S_ERROR;
475119404Ssos	    /* FALLTHROUGH */
476119404Ssos
477119404Ssos	case ATAPI_P_ABORT:
478119404Ssos	case ATAPI_P_DONE:
479119404Ssos	    if (request->status & (ATA_S_ERROR | ATA_S_DWF))
480119404Ssos		request->error = ATA_IDX_INB(ch, ATA_ERROR);
481119404Ssos	    break;
482119404Ssos
483119404Ssos	default:
484119404Ssos	    ata_prtdev(request->device, "unknown transfer phase\n");
485119404Ssos	    request->status = ATA_S_ERROR;
486119404Ssos	}
487121310Ssos
488119404Ssos	/* done with HW */
489119404Ssos	break;
490119404Ssos
491119404Ssos    /* ATAPI DMA commands */
492119404Ssos    case ATA_R_ATAPI|ATA_R_DMA:
493119404Ssos
494119404Ssos	/* stop the engine and get engine status */
495119404Ssos	request->dmastat = ch->dma->stop(ch);
496119404Ssos
497119404Ssos	/* did we get error or data */
498119404Ssos	if (request->status & (ATA_S_ERROR | ATA_S_DWF))
499119404Ssos	    request->error = ATA_IDX_INB(ch, ATA_ERROR);
500119404Ssos	else if (request->dmastat & ATA_BMSTAT_ERROR)
501119404Ssos	    request->status |= ATA_S_ERROR;
502119404Ssos	else
503119404Ssos	    request->donecount = request->bytecount;
504121310Ssos
505121310Ssos	/* release SG list etc */
506121310Ssos	ch->dma->unload(ch);
507119404Ssos
508119404Ssos	/* done with HW */
509119404Ssos	break;
510119404Ssos    }
511119404Ssos
512124403Ssos    /* if we timed out, we hold on to the channel, ata_reinit() will unlock */
513124403Ssos    if (request->flags & ATA_R_TIMEOUT) {
514124403Ssos	ata_finish(request);
515124403Ssos	return;
516124403Ssos    }
517124403Ssos
518124403Ssos    /* schedule completition for this request */
519119404Ssos    ata_finish(request);
520119404Ssos
521121310Ssos    /* unlock the ATA channel for new work */
522119404Ssos    ch->running = NULL;
523119404Ssos    ATA_UNLOCK_CH(ch);
524119404Ssos    ch->locking(ch, ATA_LF_UNLOCK);
525119404Ssos}
526119404Ssos
527119404Ssos/* must be called with ATA channel locked */
528119404Ssosstatic void
529119404Ssosata_reset(struct ata_channel *ch)
530119404Ssos{
531119651Ssos    u_int8_t err, lsb, msb, ostat0, ostat1;
532119404Ssos    u_int8_t stat0 = 0, stat1 = 0;
533119404Ssos    int mask = 0, timeout;
534119404Ssos
535119404Ssos    /* do we have any signs of ATA/ATAPI HW being present ? */
536119404Ssos    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
537119404Ssos    DELAY(10);
538119404Ssos    ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
539119404Ssos    if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) {
540119404Ssos	stat0 = ATA_S_BUSY;
541119404Ssos	mask |= 0x01;
542119404Ssos    }
543119404Ssos
544119404Ssos    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
545119404Ssos    DELAY(10);
546119404Ssos    ostat1 = ATA_IDX_INB(ch, ATA_STATUS);
547119651Ssos
548119404Ssos    /* in some setups we dont want to test for a slave */
549119404Ssos    if (!(ch->flags & ATA_NO_SLAVE)) {
550119404Ssos	if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) {
551119404Ssos	    stat1 = ATA_S_BUSY;
552119404Ssos	    mask |= 0x02;
553119404Ssos	}
554119404Ssos    }
555119404Ssos
556124403Ssos    /* if nothing showed up there is no need to get any further */
557119404Ssos    /* SOS is that too strong?, we just might loose devices here XXX */
558119404Ssos    ch->devices = 0;
559119404Ssos    if (!mask)
560119404Ssos	return;
561119404Ssos
562119404Ssos    if (bootverbose)
563119651Ssos	ata_printf(ch, -1, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n",
564119404Ssos		   mask, ostat0, ostat1);
565119404Ssos
566124403Ssos    /* reset host end of channel (if supported) */
567124403Ssos    if (ch->reset)
568124403Ssos	ch->reset(ch);
569124403Ssos
570124403Ssos    /* reset (both) devices on this channel */
571119404Ssos    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
572119404Ssos    DELAY(10);
573119404Ssos    ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET);
574119404Ssos    DELAY(10000);
575119404Ssos    ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS);
576121277Ssos    DELAY(100000);
577121277Ssos    ATA_IDX_INB(ch, ATA_ERROR);
578119404Ssos
579119404Ssos    /* wait for BUSY to go inactive */
580119501Ssos    for (timeout = 0; timeout < 310; timeout++) {
581119404Ssos	if (stat0 & ATA_S_BUSY) {
582119404Ssos	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
583119404Ssos	    DELAY(10);
584119651Ssos    	    err = ATA_IDX_INB(ch, ATA_ERROR);
585119651Ssos	    lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
586119651Ssos	    msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
587119404Ssos	    stat0 = ATA_IDX_INB(ch, ATA_STATUS);
588119651Ssos	    if (bootverbose)
589119651Ssos		ata_printf(ch, ATA_MASTER,
590119651Ssos			   "stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
591119651Ssos			   stat0, err, lsb, msb);
592119953Ssos	    if (!(stat0 & ATA_S_BUSY)) {
593120279Ssos		if ((err & 0x7f) == ATA_E_ILI) {
594120127Ssos		    if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
595120127Ssos			ch->devices |= ATA_ATAPI_MASTER;
596120127Ssos		    }
597120127Ssos		    else if (stat0 & ATA_S_READY) {
598119953Ssos			ch->devices |= ATA_ATA_MASTER;
599119953Ssos		    }
600119651Ssos		}
601120203Ssos		else if ((stat0 & 0x4f) && err == lsb && err == msb) {
602120203Ssos		    stat0 |= ATA_S_BUSY;
603120127Ssos		}
604119404Ssos	    }
605119404Ssos	}
606123127Ssos	if (!((mask == 0x03) && (stat0 & ATA_S_BUSY)) && (stat1 & ATA_S_BUSY)) {
607119404Ssos	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
608119404Ssos	    DELAY(10);
609119651Ssos    	    err = ATA_IDX_INB(ch, ATA_ERROR);
610119651Ssos	    lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
611119651Ssos	    msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
612119404Ssos	    stat1 = ATA_IDX_INB(ch, ATA_STATUS);
613119651Ssos	    if (bootverbose)
614119651Ssos		ata_printf(ch, ATA_SLAVE,
615119953Ssos			   " stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
616119953Ssos			   stat1, err, lsb, msb);
617119953Ssos	    if (!(stat1 & ATA_S_BUSY)) {
618120279Ssos		if ((err & 0x7f) == ATA_E_ILI) {
619120127Ssos		    if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
620120127Ssos			ch->devices |= ATA_ATAPI_SLAVE;
621120127Ssos		    }
622120127Ssos		    else if (stat1 & ATA_S_READY) {
623119953Ssos			ch->devices |= ATA_ATA_SLAVE;
624119953Ssos		    }
625119651Ssos		}
626120203Ssos		else if ((stat1 & 0x4f) && err == lsb && err == msb) {
627120203Ssos		    stat1 |= ATA_S_BUSY;
628120127Ssos		}
629119404Ssos	    }
630119404Ssos	}
631119953Ssos	if (mask == 0x01)	/* wait for master only */
632119523Ssos	    if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 20))
633119404Ssos		break;
634119953Ssos	if (mask == 0x02)	/* wait for slave only */
635119523Ssos	    if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 20))
636119404Ssos		break;
637123421Ssos	if (mask == 0x03) {	/* wait for both master & slave */
638123421Ssos	    if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY))
639119404Ssos		break;
640123421Ssos	    if (stat0 == 0xff && timeout > 20)
641123421Ssos		mask &= ~0x01;
642123421Ssos	    if (stat1 == 0xff && timeout > 20)
643123421Ssos		mask &= ~0x02;
644123421Ssos	}
645119501Ssos	DELAY(100000);
646119404Ssos    }
647119404Ssos
648124403Ssos    /* enable interrupt */
649124403Ssos    DELAY(10);
650124403Ssos    ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT);
651124403Ssos
652119404Ssos    if (stat0 & ATA_S_BUSY)
653119404Ssos	mask &= ~0x01;
654119404Ssos    if (stat1 & ATA_S_BUSY)
655119404Ssos	mask &= ~0x02;
656119651Ssos
657119404Ssos    if (bootverbose)
658119651Ssos	ata_printf(ch, -1,
659119651Ssos		   "reset tp2 mask=%02x stat0=%02x stat1=%02x devices=0x%b\n",
660119651Ssos		   mask, stat0, stat1, ch->devices,
661119651Ssos		   "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
662119404Ssos}
663119404Ssos
664119404Ssosstatic int
665119404Ssosata_wait(struct ata_device *atadev, u_int8_t mask)
666119404Ssos{
667120628Ssos    u_int8_t status;
668119404Ssos    int timeout = 0;
669119404Ssos
670119404Ssos    DELAY(1);
671120628Ssos
672120628Ssos    /* wait 5 seconds for device to get !BUSY */
673120628Ssos    while (timeout < 5000000) {
674119404Ssos	status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
675119404Ssos
676119404Ssos	/* if drive fails status, reselect the drive just to be sure */
677119404Ssos	if (status == 0xff) {
678119404Ssos	    ata_prtdev(atadev, "WARNING no status, reselecting device\n");
679119404Ssos	    ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
680119404Ssos	    DELAY(10);
681119404Ssos	    status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
682119404Ssos	    if (status == 0xff)
683119404Ssos		return -1;
684119404Ssos	}
685119404Ssos
686119404Ssos	/* are we done ? */
687119404Ssos	if (!(status & ATA_S_BUSY))
688119404Ssos	    break;
689119404Ssos
690119404Ssos	if (timeout > 1000) {
691119404Ssos	    timeout += 1000;
692119404Ssos	    DELAY(1000);
693119404Ssos	}
694119404Ssos	else {
695119404Ssos	    timeout += 10;
696119404Ssos	    DELAY(10);
697119404Ssos	}
698119404Ssos    }
699119404Ssos    if (timeout >= 5000000)
700119404Ssos	return -1;
701119404Ssos    if (!mask)
702119404Ssos	return (status & ATA_S_ERROR);
703120628Ssos
704120628Ssos    DELAY(1);
705119404Ssos
706120628Ssos    /* wait 50 msec for bits wanted */
707119404Ssos    timeout = 5000;
708119404Ssos    while (timeout--) {
709119404Ssos	status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
710119404Ssos	if ((status & mask) == mask)
711119404Ssos	    return (status & ATA_S_ERROR);
712119404Ssos	DELAY (10);
713119404Ssos    }
714119404Ssos    return -1;
715119404Ssos}
716119404Ssos
717119404Ssosstatic int
718119404Ssosata_command(struct ata_device *atadev, u_int8_t command,
719119404Ssos	    u_int64_t lba, u_int16_t count, u_int16_t feature)
720119404Ssos{
721119404Ssos    if (atadebug)
722119404Ssos	ata_prtdev(atadev, "ata_command: addr=%04lx, command=%02x, "
723119404Ssos		   "lba=%jd, count=%d, feature=%d\n",
724119404Ssos		   rman_get_start(atadev->channel->r_io[ATA_DATA].res),
725119404Ssos		   command, (intmax_t)lba, count, feature);
726119404Ssos
727119404Ssos    /* select device */
728119404Ssos    ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
729119404Ssos
730119404Ssos    /* ready to issue command ? */
731119404Ssos    if (ata_wait(atadev, 0) < 0) {
732119404Ssos	ata_prtdev(atadev, "timeout sending command=%02x\n", command);
733119404Ssos	return -1;
734119404Ssos    }
735119404Ssos
736119404Ssos    /* only use 48bit addressing if needed (avoid bugs and overhead) */
737119404Ssos    if ((lba > 268435455 || count > 256) && atadev->param &&
738119404Ssos	atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) {
739119404Ssos
740119404Ssos	/* translate command into 48bit version */
741119404Ssos	switch (command) {
742119404Ssos	case ATA_READ:
743119404Ssos	    command = ATA_READ48; break;
744119404Ssos	case ATA_READ_MUL:
745119404Ssos	    command = ATA_READ_MUL48; break;
746119404Ssos	case ATA_READ_DMA:
747119404Ssos	    command = ATA_READ_DMA48; break;
748119404Ssos	case ATA_READ_DMA_QUEUED:
749119404Ssos	    command = ATA_READ_DMA_QUEUED48; break;
750119404Ssos	case ATA_WRITE:
751119404Ssos	    command = ATA_WRITE48; break;
752119404Ssos	case ATA_WRITE_MUL:
753119404Ssos	    command = ATA_WRITE_MUL48; break;
754119404Ssos	case ATA_WRITE_DMA:
755119404Ssos	    command = ATA_WRITE_DMA48; break;
756119404Ssos	case ATA_WRITE_DMA_QUEUED:
757119404Ssos	    command = ATA_WRITE_DMA_QUEUED48; break;
758119404Ssos	case ATA_FLUSHCACHE:
759119404Ssos	    command = ATA_FLUSHCACHE48; break;
760119404Ssos	default:
761119404Ssos	    ata_prtdev(atadev, "can't translate cmd to 48bit version\n");
762119404Ssos	    return -1;
763119404Ssos	}
764119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, (feature>>8) & 0xff);
765119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature & 0xff);
766119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_COUNT, (count>>8) & 0xff);
767119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count & 0xff);
768119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, (lba>>24) & 0xff);
769119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff);
770119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>32) & 0xff);
771119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff);
772119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>40) & 0xff);
773119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff);
774119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_LBA | atadev->unit);
775119404Ssos	atadev->channel->flags |= ATA_48BIT_ACTIVE;
776119404Ssos    }
777119404Ssos    else {
778119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature);
779119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count);
780119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff);
781119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff);
782119404Ssos	ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff);
783119404Ssos	if (atadev->flags & ATA_D_USE_CHS)
784119404Ssos	    ATA_IDX_OUTB(atadev->channel, ATA_DRIVE,
785119404Ssos			 ATA_D_IBM | atadev->unit | ((lba>>24) & 0xf));
786119404Ssos	else
787119404Ssos	    ATA_IDX_OUTB(atadev->channel, ATA_DRIVE,
788119404Ssos			 ATA_D_IBM | ATA_D_LBA | atadev->unit|((lba>>24)&0xf));
789119404Ssos	atadev->channel->flags &= ~ATA_48BIT_ACTIVE;
790119404Ssos    }
791119404Ssos
792119404Ssos    /* issue command to controller */
793119404Ssos    ATA_IDX_OUTB(atadev->channel, ATA_CMD, command);
794119404Ssos
795119404Ssos    return 0;
796119404Ssos}
797119404Ssos
798119404Ssosstatic void
799119404Ssosata_pio_read(struct ata_request *request, int length)
800119404Ssos{
801119404Ssos    int size = min(request->transfersize, length);
802119404Ssos    struct ata_channel *ch = request->device->channel;
803119404Ssos    int resid;
804119404Ssos
805119404Ssos    if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)))
806119404Ssos	ATA_IDX_INSW_STRM(ch, ATA_DATA,
807119404Ssos			  (void*)((uintptr_t)request->data+request->donecount),
808119404Ssos			  size / sizeof(int16_t));
809119404Ssos    else
810119404Ssos	ATA_IDX_INSL_STRM(ch, ATA_DATA,
811119404Ssos			  (void*)((uintptr_t)request->data+request->donecount),
812119404Ssos			  size / sizeof(int32_t));
813119404Ssos
814119404Ssos    if (request->transfersize < length) {
815119523Ssos	ata_prtdev(request->device, "WARNING - %s read data overrun %d>%d\n",
816119404Ssos		   ata_cmd2str(request), length, request->transfersize);
817119404Ssos	for (resid = request->transfersize; resid < length;
818119404Ssos	     resid += sizeof(int16_t))
819119404Ssos	    ATA_IDX_INW(ch, ATA_DATA);
820119404Ssos    }
821119404Ssos}
822119404Ssos
823119404Ssosstatic void
824119404Ssosata_pio_write(struct ata_request *request, int length)
825119404Ssos{
826119404Ssos    int size = min(request->transfersize, length);
827119404Ssos    struct ata_channel *ch = request->device->channel;
828119404Ssos    int resid;
829119404Ssos
830119404Ssos    if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)))
831119404Ssos	ATA_IDX_OUTSW_STRM(ch, ATA_DATA,
832119404Ssos			   (void*)((uintptr_t)request->data+request->donecount),
833119404Ssos			   size / sizeof(int16_t));
834119404Ssos    else
835119404Ssos	ATA_IDX_OUTSL_STRM(ch, ATA_DATA,
836119404Ssos			   (void*)((uintptr_t)request->data+request->donecount),
837119404Ssos			   size / sizeof(int32_t));
838119404Ssos
839119404Ssos    if (request->transfersize < length) {
840119523Ssos	ata_prtdev(request->device, "WARNING - %s write data underrun %d>%d\n",
841119404Ssos		   ata_cmd2str(request), length, request->transfersize);
842119404Ssos	for (resid = request->transfersize; resid < length;
843119404Ssos	     resid += sizeof(int16_t))
844119404Ssos	    ATA_IDX_OUTW(ch, ATA_DATA, 0);
845119404Ssos    }
846119404Ssos}
847