1119404Ssos/*-
2230132Suqs * Copyright (c) 1998 - 2008 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 *
15119404Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16119404Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17119404Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18119404Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19119404Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20119404Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21119404Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22119404Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23119404Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24119404Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25119404Ssos */
26119404Ssos
27119418Sobrien#include <sys/cdefs.h>
28119418Sobrien__FBSDID("$FreeBSD$");
29119418Sobrien
30119404Ssos#include <sys/param.h>
31119404Ssos#include <sys/systm.h>
32144330Ssos#include <sys/kernel.h>
33144330Ssos#include <sys/endian.h>
34119404Ssos#include <sys/ata.h>
35119404Ssos#include <sys/conf.h>
36144330Ssos#include <sys/ctype.h>
37119404Ssos#include <sys/bus.h>
38124403Ssos#include <sys/sema.h>
39119404Ssos#include <sys/taskqueue.h>
40124534Ssos#include <vm/uma.h>
41119404Ssos#include <machine/bus.h>
42119404Ssos#include <sys/rman.h>
43119404Ssos#include <dev/ata/ata-all.h>
44144330Ssos#include <dev/ata/ata-pci.h>
45144330Ssos#include <ata_if.h>
46119404Ssos
47119404Ssos/* prototypes */
48154507Ssosstatic int ata_generic_status(device_t dev);
49198717Smavstatic int ata_wait(struct ata_channel *ch, int unit, u_int8_t);
50119450Ssosstatic void ata_pio_read(struct ata_request *, int);
51119450Ssosstatic void ata_pio_write(struct ata_request *, int);
52174576Ssosstatic void ata_tf_read(struct ata_request *);
53174576Ssosstatic void ata_tf_write(struct ata_request *);
54119404Ssos
55119404Ssos/*
56119404Ssos * low level ATA functions
57119404Ssos */
58119404Ssosvoid
59145713Ssosata_generic_hw(device_t dev)
60119404Ssos{
61145713Ssos    struct ata_channel *ch = device_get_softc(dev);
62145713Ssos
63135819Ssos    ch->hw.begin_transaction = ata_begin_transaction;
64135819Ssos    ch->hw.end_transaction = ata_end_transaction;
65154507Ssos    ch->hw.status = ata_generic_status;
66178067Ssos    ch->hw.softreset = NULL;
67128183Ssos    ch->hw.command = ata_generic_command;
68174576Ssos    ch->hw.tf_read = ata_tf_read;
69174576Ssos    ch->hw.tf_write = ata_tf_write;
70178067Ssos    ch->hw.pm_read = NULL;
71178067Ssos    ch->hw.pm_write = NULL;
72119404Ssos}
73119404Ssos
74145354Ssos/* must be called with ATA channel locked and state_mtx held */
75154507Ssosint
76135819Ssosata_begin_transaction(struct ata_request *request)
77119404Ssos{
78178067Ssos    struct ata_channel *ch = device_get_softc(request->parent);
79153142Ssos    int dummy, error;
80128183Ssos
81135819Ssos    ATA_DEBUG_RQ(request, "begin transaction");
82124403Ssos
83119404Ssos    /* disable ATAPI DMA writes if HW doesn't support it */
84200171Smav    if ((ch->flags & ATA_NO_ATAPI_DMA) &&
85200171Smav	(request->flags & ATA_R_ATAPI) == ATA_R_ATAPI)
86200171Smav	    request->flags &= ~ATA_R_DMA;
87128183Ssos    if ((ch->flags & ATA_ATAPI_DMA_RO) &&
88120938Ssos	((request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE)) ==
89120938Ssos	 (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE)))
90119404Ssos	request->flags &= ~ATA_R_DMA;
91119404Ssos
92119404Ssos    switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) {
93119404Ssos
94119404Ssos    /* ATA PIO data transfer and control commands */
95119404Ssos    default:
96119404Ssos	{
97124403Ssos	/* record command direction here as our request might be gone later */
98119404Ssos	int write = (request->flags & ATA_R_WRITE);
99119404Ssos
100119404Ssos	    /* issue command */
101145818Ssos	    if (ch->hw.command(request)) {
102198717Smav		device_printf(request->parent, "error issuing %s command\n",
103133834Ssos			   ata_cmd2str(request));
104119404Ssos		request->result = EIO;
105145354Ssos		goto begin_finished;
106119404Ssos	    }
107119404Ssos
108132582Ssos	    /* device reset doesn't interrupt */
109144330Ssos	    if (request->u.ata.command == ATA_DEVICE_RESET) {
110168430Ssos
111132606Ssos		int timeout = 1000000;
112132606Ssos		do {
113132606Ssos		    DELAY(10);
114132606Ssos		    request->status = ATA_IDX_INB(ch, ATA_STATUS);
115132606Ssos		} while (request->status & ATA_S_BUSY && timeout--);
116133184Ssos		if (request->status & ATA_S_ERROR)
117132582Ssos		    request->error = ATA_IDX_INB(ch, ATA_ERROR);
118242156Smav		ch->hw.tf_read(request);
119145354Ssos		goto begin_finished;
120132582Ssos	    }
121132582Ssos
122119404Ssos	    /* if write command output the data */
123119404Ssos	    if (write) {
124198717Smav		if (ata_wait(ch, request->unit, (ATA_S_READY | ATA_S_DRQ)) < 0) {
125198717Smav		    device_printf(request->parent,
126150129Ssos				  "timeout waiting for write DRQ\n");
127119404Ssos		    request->result = EIO;
128145354Ssos		    goto begin_finished;
129119404Ssos		}
130119404Ssos		ata_pio_write(request, request->transfersize);
131119404Ssos	    }
132119404Ssos	}
133145354Ssos	goto begin_continue;
134119404Ssos
135119404Ssos    /* ATA DMA data transfer commands */
136119404Ssos    case ATA_R_DMA:
137121310Ssos	/* check sanity, setup SG list and DMA engine */
138178067Ssos	if ((error = ch->dma.load(request, NULL, &dummy))) {
139198717Smav	    device_printf(request->parent, "setting up DMA failed\n");
140153142Ssos	    request->result = error;
141145354Ssos	    goto begin_finished;
142119404Ssos	}
143119404Ssos
144208870Snwhitehorn	/* start DMA engine if necessary */
145208870Snwhitehorn	if ((ch->flags & ATA_DMA_BEFORE_CMD) &&
146208870Snwhitehorn	   ch->dma.start && ch->dma.start(request)) {
147208870Snwhitehorn	    device_printf(request->parent, "error starting DMA\n");
148208870Snwhitehorn	    request->result = EIO;
149208870Snwhitehorn	    goto begin_finished;
150208870Snwhitehorn	}
151208870Snwhitehorn
152119404Ssos	/* issue command */
153145818Ssos	if (ch->hw.command(request)) {
154198717Smav	    device_printf(request->parent, "error issuing %s command\n",
155133834Ssos		       ata_cmd2str(request));
156119404Ssos	    request->result = EIO;
157145354Ssos	    goto begin_finished;
158119404Ssos	}
159119404Ssos
160119404Ssos	/* start DMA engine */
161208870Snwhitehorn	if (!(ch->flags & ATA_DMA_BEFORE_CMD) &&
162208870Snwhitehorn	   ch->dma.start && ch->dma.start(request)) {
163198717Smav	    device_printf(request->parent, "error starting DMA\n");
164119404Ssos	    request->result = EIO;
165145354Ssos	    goto begin_finished;
166119404Ssos	}
167145354Ssos	goto begin_continue;
168119404Ssos
169119404Ssos    /* ATAPI PIO commands */
170119404Ssos    case ATA_R_ATAPI:
171119404Ssos	/* is this just a POLL DSC command ? */
172119404Ssos	if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) {
173198717Smav	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(request->unit));
174119404Ssos	    DELAY(10);
175144707Ssos	    if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DSC))
176119404Ssos		request->result = EBUSY;
177145354Ssos	    goto begin_finished;
178119404Ssos	}
179119404Ssos
180119404Ssos	/* start ATAPI operation */
181145818Ssos	if (ch->hw.command(request)) {
182198717Smav	    device_printf(request->parent, "error issuing ATA PACKET command\n");
183119404Ssos	    request->result = EIO;
184145354Ssos	    goto begin_finished;
185119404Ssos	}
186145354Ssos	goto begin_continue;
187119404Ssos
188145713Ssos   /* ATAPI DMA commands */
189119404Ssos    case ATA_R_ATAPI|ATA_R_DMA:
190119404Ssos	/* is this just a POLL DSC command ? */
191119404Ssos	if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) {
192198717Smav	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(request->unit));
193119404Ssos	    DELAY(10);
194144707Ssos	    if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DSC))
195119404Ssos		request->result = EBUSY;
196145354Ssos	    goto begin_finished;
197119404Ssos	}
198119404Ssos
199121310Ssos	/* check sanity, setup SG list and DMA engine */
200178067Ssos	if ((error = ch->dma.load(request, NULL, &dummy))) {
201198717Smav	    device_printf(request->parent, "setting up DMA failed\n");
202153142Ssos	    request->result = error;
203145354Ssos	    goto begin_finished;
204119404Ssos	}
205119404Ssos
206119404Ssos	/* start ATAPI operation */
207145818Ssos	if (ch->hw.command(request)) {
208198717Smav	    device_printf(request->parent, "error issuing ATA PACKET command\n");
209119404Ssos	    request->result = EIO;
210145354Ssos	    goto begin_finished;
211119404Ssos	}
212119404Ssos
213119404Ssos	/* start DMA engine */
214178067Ssos	if (ch->dma.start && ch->dma.start(request)) {
215119404Ssos	    request->result = EIO;
216145354Ssos	    goto begin_finished;
217119404Ssos	}
218145354Ssos	goto begin_continue;
219119404Ssos    }
220145354Ssos    /* NOT REACHED */
221145354Ssos    printf("ata_begin_transaction OOPS!!!\n");
222120881Ssos
223145354Ssosbegin_finished:
224178856Sgrehan    if (ch->dma.unload) {
225178856Sgrehan        ch->dma.unload(request);
226178856Sgrehan    }
227120881Ssos    return ATA_OP_FINISHED;
228145354Ssos
229145354Ssosbegin_continue:
230145354Ssos    callout_reset(&request->callout, request->timeout * hz,
231145354Ssos		  (timeout_t*)ata_timeout, request);
232145354Ssos    return ATA_OP_CONTINUES;
233119404Ssos}
234119404Ssos
235145354Ssos/* must be called with ATA channel locked and state_mtx held */
236154507Ssosint
237135819Ssosata_end_transaction(struct ata_request *request)
238119404Ssos{
239178067Ssos    struct ata_channel *ch = device_get_softc(request->parent);
240119404Ssos    int length;
241119404Ssos
242135819Ssos    ATA_DEBUG_RQ(request, "end transaction");
243119878Ssos
244119878Ssos    /* clear interrupt and get status */
245120128Ssos    request->status = ATA_IDX_INB(ch, ATA_STATUS);
246119878Ssos
247121910Ssos    switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_CONTROL)) {
248119404Ssos
249119404Ssos    /* ATA PIO data transfer and control commands */
250119404Ssos    default:
251144330Ssos
252144330Ssos	/* on timeouts we have no data or anything so just return */
253142974Smdodd	if (request->flags & ATA_R_TIMEOUT)
254145354Ssos	    goto end_finished;
255119404Ssos
256242156Smav	/* Read back registers to the request struct. */
257242156Smav	if ((request->status & ATA_S_ERROR) ||
258242156Smav	    (request->flags & (ATA_R_CONTROL | ATA_R_NEEDRESULT))) {
259174576Ssos	    ch->hw.tf_read(request);
260121910Ssos	}
261121910Ssos
262119404Ssos	/* if we got an error we are done with the HW */
263119404Ssos	if (request->status & ATA_S_ERROR) {
264119404Ssos	    request->error = ATA_IDX_INB(ch, ATA_ERROR);
265145354Ssos	    goto end_finished;
266119404Ssos	}
267119404Ssos
268121910Ssos	/* are we moving data ? */
269121910Ssos	if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
270119404Ssos
271121910Ssos	    /* if read data get it */
272144330Ssos	    if (request->flags & ATA_R_READ) {
273150311Ssos		int flags = ATA_S_DRQ;
274150311Ssos
275150311Ssos		if (request->u.ata.command != ATA_ATAPI_IDENTIFY)
276150311Ssos		    flags |= ATA_S_READY;
277198717Smav		if (ata_wait(ch, request->unit, flags) < 0) {
278198717Smav		    device_printf(request->parent,
279150129Ssos				  "timeout waiting for read DRQ\n");
280144330Ssos		    request->result = EIO;
281145354Ssos		    goto end_finished;
282144330Ssos		}
283121910Ssos		ata_pio_read(request, request->transfersize);
284144330Ssos	    }
285119404Ssos
286121910Ssos	    /* update how far we've gotten */
287143172Snjl	    request->donecount += request->transfersize;
288119404Ssos
289121910Ssos	    /* do we need a scoop more ? */
290121910Ssos	    if (request->bytecount > request->donecount) {
291119404Ssos
292121910Ssos		/* set this transfer size according to HW capabilities */
293121910Ssos		request->transfersize =
294121910Ssos		    min((request->bytecount - request->donecount),
295121910Ssos			request->transfersize);
296120204Ssos
297121910Ssos		/* if data write command, output the data */
298121910Ssos		if (request->flags & ATA_R_WRITE) {
299121910Ssos
300121910Ssos		    /* if we get an error here we are done with the HW */
301198717Smav		    if (ata_wait(ch, request->unit, (ATA_S_READY | ATA_S_DRQ)) < 0) {
302198717Smav			device_printf(request->parent,
303150129Ssos				      "timeout waiting for write DRQ\n");
304121910Ssos			request->status = ATA_IDX_INB(ch, ATA_STATUS);
305145354Ssos			goto end_finished;
306121910Ssos		    }
307121910Ssos
308121910Ssos		    /* output data and return waiting for new interrupt */
309121910Ssos		    ata_pio_write(request, request->transfersize);
310145354Ssos		    goto end_continue;
311119404Ssos		}
312120204Ssos
313121910Ssos		/* if data read command, return & wait for interrupt */
314121910Ssos		if (request->flags & ATA_R_READ)
315145354Ssos		    goto end_continue;
316119404Ssos	    }
317119404Ssos	}
318119404Ssos	/* done with HW */
319145354Ssos	goto end_finished;
320119404Ssos
321119404Ssos    /* ATA DMA data transfer commands */
322119404Ssos    case ATA_R_DMA:
323128183Ssos
324119404Ssos	/* stop DMA engine and get status */
325178067Ssos	if (ch->dma.stop)
326178278Ssos	    request->dma->status = ch->dma.stop(request);
327119404Ssos
328119404Ssos	/* did we get error or data */
329119404Ssos	if (request->status & ATA_S_ERROR)
330119404Ssos	    request->error = ATA_IDX_INB(ch, ATA_ERROR);
331178278Ssos	else if (request->dma->status & ATA_BMSTAT_ERROR)
332119404Ssos	    request->status |= ATA_S_ERROR;
333144330Ssos	else if (!(request->flags & ATA_R_TIMEOUT))
334119404Ssos	    request->donecount = request->bytecount;
335119404Ssos
336242156Smav	/* Read back registers to the request struct. */
337242156Smav	if ((request->status & ATA_S_ERROR) ||
338242156Smav	    (request->flags & (ATA_R_CONTROL | ATA_R_NEEDRESULT))) {
339242156Smav	    ch->hw.tf_read(request);
340242156Smav	}
341242156Smav
342121310Ssos	/* release SG list etc */
343178067Ssos	ch->dma.unload(request);
344121310Ssos
345119404Ssos	/* done with HW */
346145354Ssos	goto end_finished;
347119404Ssos
348119404Ssos    /* ATAPI PIO commands */
349119404Ssos    case ATA_R_ATAPI:
350119404Ssos	length = ATA_IDX_INB(ch, ATA_CYL_LSB)|(ATA_IDX_INB(ch, ATA_CYL_MSB)<<8);
351119404Ssos
352144330Ssos	/* on timeouts we have no data or anything so just return */
353144330Ssos	if (request->flags & ATA_R_TIMEOUT)
354145354Ssos	    goto end_finished;
355144330Ssos
356119404Ssos	switch ((ATA_IDX_INB(ch, ATA_IREASON) & (ATA_I_CMD | ATA_I_IN)) |
357119404Ssos		(request->status & ATA_S_DRQ)) {
358119404Ssos
359119404Ssos	case ATAPI_P_CMDOUT:
360119404Ssos	    /* this seems to be needed for some (slow) devices */
361119404Ssos	    DELAY(10);
362119404Ssos
363119404Ssos	    if (!(request->status & ATA_S_DRQ)) {
364198717Smav		device_printf(request->parent, "command interrupt without DRQ\n");
365119404Ssos		request->status = ATA_S_ERROR;
366145354Ssos		goto end_finished;
367119404Ssos	    }
368119404Ssos	    ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb,
369198717Smav			       (request->flags & ATA_R_ATAPI16) ? 8 : 6);
370119404Ssos	    /* return wait for interrupt */
371145354Ssos	    goto end_continue;
372119404Ssos
373119404Ssos	case ATAPI_P_WRITE:
374119404Ssos	    if (request->flags & ATA_R_READ) {
375119404Ssos		request->status = ATA_S_ERROR;
376198717Smav		device_printf(request->parent,
377144330Ssos			      "%s trying to write on read buffer\n",
378119404Ssos			   ata_cmd2str(request));
379145354Ssos		goto end_finished;
380119404Ssos	    }
381119404Ssos	    ata_pio_write(request, length);
382119404Ssos	    request->donecount += length;
383119404Ssos
384119404Ssos	    /* set next transfer size according to HW capabilities */
385119404Ssos	    request->transfersize = min((request->bytecount-request->donecount),
386119404Ssos					request->transfersize);
387119404Ssos	    /* return wait for interrupt */
388145354Ssos	    goto end_continue;
389119404Ssos
390119404Ssos	case ATAPI_P_READ:
391119404Ssos	    if (request->flags & ATA_R_WRITE) {
392119404Ssos		request->status = ATA_S_ERROR;
393198717Smav		device_printf(request->parent,
394144330Ssos			      "%s trying to read on write buffer\n",
395119404Ssos			   ata_cmd2str(request));
396145354Ssos		goto end_finished;
397119404Ssos	    }
398119404Ssos	    ata_pio_read(request, length);
399119404Ssos	    request->donecount += length;
400119404Ssos
401119404Ssos	    /* set next transfer size according to HW capabilities */
402119404Ssos	    request->transfersize = min((request->bytecount-request->donecount),
403119404Ssos					request->transfersize);
404119404Ssos	    /* return wait for interrupt */
405145354Ssos	    goto end_continue;
406119404Ssos
407119404Ssos	case ATAPI_P_DONEDRQ:
408198717Smav	    device_printf(request->parent,
409144330Ssos			  "WARNING - %s DONEDRQ non conformant device\n",
410144330Ssos			  ata_cmd2str(request));
411119404Ssos	    if (request->flags & ATA_R_READ) {
412119404Ssos		ata_pio_read(request, length);
413119404Ssos		request->donecount += length;
414119404Ssos	    }
415119404Ssos	    else if (request->flags & ATA_R_WRITE) {
416119404Ssos		ata_pio_write(request, length);
417119404Ssos		request->donecount += length;
418119404Ssos	    }
419119404Ssos	    else
420119404Ssos		request->status = ATA_S_ERROR;
421119404Ssos	    /* FALLTHROUGH */
422119404Ssos
423119404Ssos	case ATAPI_P_ABORT:
424119404Ssos	case ATAPI_P_DONE:
425119404Ssos	    if (request->status & (ATA_S_ERROR | ATA_S_DWF))
426119404Ssos		request->error = ATA_IDX_INB(ch, ATA_ERROR);
427145354Ssos	    goto end_finished;
428119404Ssos
429119404Ssos	default:
430198717Smav	    device_printf(request->parent, "unknown transfer phase\n");
431119404Ssos	    request->status = ATA_S_ERROR;
432119404Ssos	}
433121310Ssos
434119404Ssos	/* done with HW */
435145354Ssos	goto end_finished;
436119404Ssos
437119404Ssos    /* ATAPI DMA commands */
438119404Ssos    case ATA_R_ATAPI|ATA_R_DMA:
439119404Ssos
440145818Ssos	/* stop DMA engine and get status */
441178067Ssos	if (ch->dma.stop)
442178278Ssos	    request->dma->status = ch->dma.stop(request);
443119404Ssos
444119404Ssos	/* did we get error or data */
445119404Ssos	if (request->status & (ATA_S_ERROR | ATA_S_DWF))
446119404Ssos	    request->error = ATA_IDX_INB(ch, ATA_ERROR);
447178278Ssos	else if (request->dma->status & ATA_BMSTAT_ERROR)
448119404Ssos	    request->status |= ATA_S_ERROR;
449144330Ssos	else if (!(request->flags & ATA_R_TIMEOUT))
450119404Ssos	    request->donecount = request->bytecount;
451121310Ssos
452121310Ssos	/* release SG list etc */
453178067Ssos	ch->dma.unload(request);
454119404Ssos
455119404Ssos	/* done with HW */
456145354Ssos	goto end_finished;
457119404Ssos    }
458145354Ssos    /* NOT REACHED */
459145354Ssos    printf("ata_end_transaction OOPS!!\n");
460144330Ssos
461145354Ssosend_finished:
462145354Ssos    callout_stop(&request->callout);
463145354Ssos    return ATA_OP_FINISHED;
464144330Ssos
465145354Ssosend_continue:
466145354Ssos    return ATA_OP_CONTINUES;
467119404Ssos}
468119404Ssos
469154507Ssos/* must be called with ATA channel locked and state_mtx held */
470145641Ssosvoid
471145713Ssosata_generic_reset(device_t dev)
472119404Ssos{
473145713Ssos    struct ata_channel *ch = device_get_softc(dev);
474145713Ssos
475144330Ssos    u_int8_t ostat0 = 0, stat0 = 0, ostat1 = 0, stat1 = 0;
476144330Ssos    u_int8_t err = 0, lsb = 0, msb = 0;
477119404Ssos    int mask = 0, timeout;
478119404Ssos
479119404Ssos    /* do we have any signs of ATA/ATAPI HW being present ? */
480178203Ssos    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER));
481119404Ssos    DELAY(10);
482119404Ssos    ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
483212145Smav    if (((ostat0 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) &&
484212145Smav	    ostat0 != 0xa5) {
485119404Ssos	stat0 = ATA_S_BUSY;
486119404Ssos	mask |= 0x01;
487119404Ssos    }
488119404Ssos
489119404Ssos    /* in some setups we dont want to test for a slave */
490119404Ssos    if (!(ch->flags & ATA_NO_SLAVE)) {
491178203Ssos	ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_SLAVE));
492144330Ssos	DELAY(10);
493144330Ssos	ostat1 = ATA_IDX_INB(ch, ATA_STATUS);
494212145Smav	if (((ostat1 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) &&
495212145Smav		ostat1 != 0xa5) {
496119404Ssos	    stat1 = ATA_S_BUSY;
497119404Ssos	    mask |= 0x02;
498119404Ssos	}
499119404Ssos    }
500119404Ssos
501128437Ssos    if (bootverbose)
502145713Ssos	device_printf(dev, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n",
503144330Ssos		      mask, ostat0, ostat1);
504128437Ssos
505124403Ssos    /* if nothing showed up there is no need to get any further */
506250576Seadler    /* XXX SOS is that too strong?, we just might lose devices here */
507119404Ssos    ch->devices = 0;
508119404Ssos    if (!mask)
509119404Ssos	return;
510119404Ssos
511124403Ssos    /* reset (both) devices on this channel */
512178203Ssos    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER));
513119404Ssos    DELAY(10);
514144707Ssos    ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET);
515134698Ssos    ata_udelay(10000);
516144707Ssos    ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS);
517134698Ssos    ata_udelay(100000);
518121277Ssos    ATA_IDX_INB(ch, ATA_ERROR);
519119404Ssos
520119404Ssos    /* wait for BUSY to go inactive */
521119501Ssos    for (timeout = 0; timeout < 310; timeout++) {
522144330Ssos	if ((mask & 0x01) && (stat0 & ATA_S_BUSY)) {
523178203Ssos	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_MASTER));
524119404Ssos	    DELAY(10);
525212359Snwhitehorn	    if (ch->flags & ATA_STATUS_IS_LONG)
526212359Snwhitehorn		    stat0 = ATA_IDX_INL(ch, ATA_STATUS) & 0xff;
527212359Snwhitehorn	    else
528212359Snwhitehorn		    stat0 = ATA_IDX_INB(ch, ATA_STATUS);
529144330Ssos	    err = ATA_IDX_INB(ch, ATA_ERROR);
530119651Ssos	    lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
531119651Ssos	    msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
532119651Ssos	    if (bootverbose)
533145713Ssos		device_printf(dev,
534144330Ssos			      "stat0=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
535144330Ssos			      stat0, err, lsb, msb);
536145354Ssos	    if (stat0 == err && lsb == err && msb == err &&
537145354Ssos		timeout > (stat0 & ATA_S_BUSY ? 100 : 10))
538144330Ssos		mask &= ~0x01;
539119953Ssos	    if (!(stat0 & ATA_S_BUSY)) {
540120279Ssos		if ((err & 0x7f) == ATA_E_ILI) {
541120127Ssos		    if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
542120127Ssos			ch->devices |= ATA_ATAPI_MASTER;
543120127Ssos		    }
544220911Smav		    else if (lsb == 0 && msb == 0 && (stat0 & ATA_S_READY)) {
545119953Ssos			ch->devices |= ATA_ATA_MASTER;
546119953Ssos		    }
547119651Ssos		}
548144330Ssos		else if ((stat0 & 0x0f) && err == lsb && err == msb) {
549120203Ssos		    stat0 |= ATA_S_BUSY;
550120127Ssos		}
551119404Ssos	    }
552119404Ssos	}
553144330Ssos
554144591Ssos	if ((mask & 0x02) && (stat1 & ATA_S_BUSY) &&
555144591Ssos	    !((mask & 0x01) && (stat0 & ATA_S_BUSY))) {
556178203Ssos	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_SLAVE));
557119404Ssos	    DELAY(10);
558212359Snwhitehorn	    if (ch->flags & ATA_STATUS_IS_LONG)
559212359Snwhitehorn		    stat1 = ATA_IDX_INL(ch, ATA_STATUS) & 0xff;
560212359Snwhitehorn	    else
561212359Snwhitehorn		    stat1 = ATA_IDX_INB(ch, ATA_STATUS);
562144330Ssos	    err = ATA_IDX_INB(ch, ATA_ERROR);
563119651Ssos	    lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
564119651Ssos	    msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
565119651Ssos	    if (bootverbose)
566145713Ssos		device_printf(dev,
567144330Ssos			      "stat1=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
568144330Ssos			      stat1, err, lsb, msb);
569145354Ssos	    if (stat1 == err && lsb == err && msb == err &&
570145354Ssos		timeout > (stat1 & ATA_S_BUSY ? 100 : 10))
571144330Ssos		mask &= ~0x02;
572119953Ssos	    if (!(stat1 & ATA_S_BUSY)) {
573120279Ssos		if ((err & 0x7f) == ATA_E_ILI) {
574120127Ssos		    if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
575120127Ssos			ch->devices |= ATA_ATAPI_SLAVE;
576120127Ssos		    }
577220911Smav		    else if (lsb == 0 && msb == 0 && (stat1 & ATA_S_READY)) {
578119953Ssos			ch->devices |= ATA_ATA_SLAVE;
579119953Ssos		    }
580119651Ssos		}
581144591Ssos		else if ((stat1 & 0x0f) && err == lsb && err == msb) {
582144591Ssos		    stat1 |= ATA_S_BUSY;
583120127Ssos		}
584119404Ssos	    }
585119404Ssos	}
586144330Ssos
587212145Smav	if ((ch->flags & ATA_KNOWN_PRESENCE) == 0 &&
588212145Smav	    timeout > ((mask == 0x03) ? 20 : 10)) {
589212145Smav		if ((mask & 0x01) && stat0 == 0xff)
590212145Smav			mask &= ~0x01;
591212145Smav		if ((mask & 0x02) && stat1 == 0xff)
592212145Smav			mask &= ~0x02;
593212145Smav	}
594212145Smav	if (((mask & 0x01) == 0 || !(stat0 & ATA_S_BUSY)) &&
595212145Smav	    ((mask & 0x02) == 0 || !(stat1 & ATA_S_BUSY)))
596119404Ssos		break;
597134698Ssos	ata_udelay(100000);
598142972Smdodd    }
599119404Ssos
600119404Ssos    if (bootverbose)
601178203Ssos	device_printf(dev, "reset tp2 stat0=%02x stat1=%02x devices=0x%x\n",
602178203Ssos		      stat0, stat1, ch->devices);
603119404Ssos}
604119404Ssos
605154507Ssos/* must be called with ATA channel locked and state_mtx held */
606249203Smariusstatic int
607154507Ssosata_generic_status(device_t dev)
608154507Ssos{
609154507Ssos    struct ata_channel *ch = device_get_softc(dev);
610154507Ssos
611154507Ssos    if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) {
612154507Ssos	DELAY(100);
613154507Ssos	if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY)
614154507Ssos	    return 0;
615154507Ssos    }
616154507Ssos    return 1;
617154507Ssos}
618154507Ssos
619119404Ssosstatic int
620198717Smavata_wait(struct ata_channel *ch, int unit, u_int8_t mask)
621119404Ssos{
622120628Ssos    u_int8_t status;
623119404Ssos    int timeout = 0;
624119404Ssos
625119404Ssos    DELAY(1);
626120628Ssos
627144790Ssos    /* wait at max 1 second for device to get !BUSY */
628144790Ssos    while (timeout < 1000000) {
629144330Ssos	status = ATA_IDX_INB(ch, ATA_ALTSTAT);
630119404Ssos
631144330Ssos	/* if drive fails status, reselect the drive and try again */
632119404Ssos	if (status == 0xff) {
633198717Smav	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(unit));
634144330Ssos	    timeout += 1000;
635144330Ssos	    DELAY(1000);
636144330Ssos	    continue;
637119404Ssos	}
638119404Ssos
639119404Ssos	/* are we done ? */
640119404Ssos	if (!(status & ATA_S_BUSY))
641144330Ssos	    break;
642119404Ssos
643119404Ssos	if (timeout > 1000) {
644119404Ssos	    timeout += 1000;
645119404Ssos	    DELAY(1000);
646119404Ssos	}
647119404Ssos	else {
648119404Ssos	    timeout += 10;
649119404Ssos	    DELAY(10);
650119404Ssos	}
651144330Ssos    }
652144790Ssos    if (timeout >= 1000000)
653144330Ssos	return -2;
654144330Ssos    if (!mask)
655144330Ssos	return (status & ATA_S_ERROR);
656120628Ssos
657120628Ssos    DELAY(1);
658119404Ssos
659144330Ssos    /* wait 50 msec for bits wanted */
660119404Ssos    timeout = 5000;
661144330Ssos    while (timeout--) {
662144330Ssos	status = ATA_IDX_INB(ch, ATA_ALTSTAT);
663119404Ssos	if ((status & mask) == mask)
664144330Ssos	    return (status & ATA_S_ERROR);
665144330Ssos	DELAY(10);
666144330Ssos    }
667144330Ssos    return -3;
668119404Ssos}
669119404Ssos
670128183Ssosint
671145818Ssosata_generic_command(struct ata_request *request)
672119404Ssos{
673178067Ssos    struct ata_channel *ch = device_get_softc(request->parent);
674119404Ssos
675119404Ssos    /* select device */
676198717Smav    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(request->unit));
677119404Ssos
678119404Ssos    /* ready to issue command ? */
679198717Smav    if (ata_wait(ch, request->unit, 0) < 0) {
680198717Smav	device_printf(request->parent, "timeout waiting to issue command\n");
681214896Smav	request->flags |= ATA_R_TIMEOUT;
682214896Smav	return (-1);
683119404Ssos    }
684119404Ssos
685125328Ssos    /* enable interrupt */
686144707Ssos    ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT);
687125328Ssos
688145818Ssos    if (request->flags & ATA_R_ATAPI) {
689146266Ssos	int timeout = 5000;
690198717Smav	int res;
691119404Ssos
692146266Ssos	/* issue packet command to controller */
693146176Ssos	if (request->flags & ATA_R_DMA) {
694146096Ssos	    ATA_IDX_OUTB(ch, ATA_FEATURE, ATA_F_DMA);
695146176Ssos	    ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0);
696146176Ssos	    ATA_IDX_OUTB(ch, ATA_CYL_MSB, 0);
697146176Ssos	}
698146176Ssos	else {
699146176Ssos	    ATA_IDX_OUTB(ch, ATA_FEATURE, 0);
700146176Ssos	    ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->transfersize);
701146176Ssos	    ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->transfersize >> 8);
702146176Ssos	}
703146096Ssos	ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_PACKET_CMD);
704145818Ssos
705145818Ssos	/* command interrupt device ? just return and wait for interrupt */
706198717Smav	if (request->flags & ATA_R_ATAPI_INTR)
707214896Smav	    return (0);
708145818Ssos
709198717Smav	/* command processed ? */
710198717Smav	res = ata_wait(ch, request->unit, 0);
711198717Smav	if (res != 0) {
712214896Smav	    if (res < 0) {
713214896Smav		    device_printf(request->parent,
714214896Smav			"timeout waiting for PACKET command\n");
715214896Smav		    request->flags |= ATA_R_TIMEOUT;
716214896Smav	    }
717198717Smav	    return (-1);
718198717Smav	}
719145818Ssos	/* wait for ready to write ATAPI command block */
720146266Ssos	while (timeout--) {
721146266Ssos	    int reason = ATA_IDX_INB(ch, ATA_IREASON);
722146266Ssos	    int status = ATA_IDX_INB(ch, ATA_STATUS);
723145818Ssos
724146266Ssos	    if (((reason & (ATA_I_CMD | ATA_I_IN)) |
725146266Ssos		 (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT)
726146266Ssos		break;
727146266Ssos	    DELAY(20);
728146266Ssos	}
729146266Ssos	if (timeout <= 0) {
730214896Smav	    device_printf(request->parent,
731214896Smav		"timeout waiting for ATAPI ready\n");
732214896Smav	    request->flags |= ATA_R_TIMEOUT;
733214896Smav	    return (-1);
734146266Ssos	}
735145818Ssos
736146266Ssos	/* this seems to be needed for some (slow) devices */
737146266Ssos	DELAY(10);
738146266Ssos
739146266Ssos	/* output command block */
740146266Ssos	ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb,
741198717Smav			   (request->flags & ATA_R_ATAPI16) ? 8 : 6);
742119404Ssos    }
743119404Ssos    else {
744174576Ssos	ch->hw.tf_write(request);
745174576Ssos
746174576Ssos	/* issue command to controller */
747174576Ssos	ATA_IDX_OUTB(ch, ATA_COMMAND, request->u.ata.command);
748174576Ssos    }
749214896Smav    return (0);
750174576Ssos}
751174576Ssos
752174576Ssosstatic void
753174576Ssosata_tf_read(struct ata_request *request)
754174576Ssos{
755178067Ssos    struct ata_channel *ch = device_get_softc(request->parent);
756174576Ssos
757198717Smav    if (request->flags & ATA_R_48BIT) {
758174576Ssos	ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT | ATA_A_HOB);
759174576Ssos	request->u.ata.count = (ATA_IDX_INB(ch, ATA_COUNT) << 8);
760174576Ssos	request->u.ata.lba =
761174576Ssos	    ((u_int64_t)(ATA_IDX_INB(ch, ATA_SECTOR)) << 24) |
762174576Ssos	    ((u_int64_t)(ATA_IDX_INB(ch, ATA_CYL_LSB)) << 32) |
763174576Ssos	    ((u_int64_t)(ATA_IDX_INB(ch, ATA_CYL_MSB)) << 40);
764174576Ssos
765174576Ssos	ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT);
766174576Ssos	request->u.ata.count |= ATA_IDX_INB(ch, ATA_COUNT);
767174576Ssos	request->u.ata.lba |=
768174576Ssos	    (ATA_IDX_INB(ch, ATA_SECTOR) |
769174576Ssos	     (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) |
770174576Ssos	     (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16));
771174576Ssos    }
772174576Ssos    else {
773174576Ssos	request->u.ata.count = ATA_IDX_INB(ch, ATA_COUNT);
774174576Ssos	request->u.ata.lba = ATA_IDX_INB(ch, ATA_SECTOR) |
775174576Ssos			     (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) |
776174576Ssos			     (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16) |
777174576Ssos			     ((ATA_IDX_INB(ch, ATA_DRIVE) & 0xf) << 24);
778174576Ssos    }
779174576Ssos}
780174576Ssos
781174576Ssosstatic void
782174576Ssosata_tf_write(struct ata_request *request)
783174576Ssos{
784178067Ssos    struct ata_channel *ch = device_get_softc(request->parent);
785174576Ssos
786198717Smav    if (request->flags & ATA_R_48BIT) {
787174576Ssos	ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature >> 8);
788174576Ssos	ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature);
789174576Ssos	ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count >> 8);
790174576Ssos	ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count);
791174576Ssos	ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba >> 24);
792174576Ssos	ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba);
793174576Ssos	ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 32);
794174576Ssos	ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
795174576Ssos	ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 40);
796174576Ssos	ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
797198717Smav	ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(request->unit));
798174576Ssos    }
799174576Ssos    else {
800174576Ssos	ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature);
801174576Ssos	ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count);
802174576Ssos	    ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba);
803174576Ssos	    ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
804174576Ssos	    ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
805174576Ssos	    ATA_IDX_OUTB(ch, ATA_DRIVE,
806198717Smav			 ATA_D_IBM | ATA_D_LBA | ATA_DEV(request->unit) |
807174576Ssos			 ((request->u.ata.lba >> 24) & 0x0f));
808119404Ssos    }
809119404Ssos}
810119404Ssos
811119404Ssosstatic void
812119404Ssosata_pio_read(struct ata_request *request, int length)
813119404Ssos{
814178067Ssos    struct ata_channel *ch = device_get_softc(request->parent);
815238673Smav    uint8_t *addr;
816119404Ssos    int size = min(request->transfersize, length);
817119404Ssos    int resid;
818246257Smarius    uint8_t buf[2] __aligned(sizeof(int16_t));
819246257Smarius#ifndef __NO_STRICT_ALIGNMENT
820246257Smarius    int i;
821246257Smarius#endif
822119404Ssos
823238673Smav    addr = (uint8_t *)request->data + request->donecount;
824246257Smarius    if (__predict_false(ch->flags & ATA_USE_16BIT ||
825246257Smarius      (size % sizeof(int32_t)) || ((uintptr_t)addr % sizeof(int32_t)))) {
826246257Smarius#ifndef __NO_STRICT_ALIGNMENT
827246257Smarius	if (__predict_false((uintptr_t)addr % sizeof(int16_t))) {
828246257Smarius	    for (i = 0, resid = size & ~1; resid > 0; resid -=
829246257Smarius	      sizeof(int16_t)) {
830246257Smarius		*(uint16_t *)&buf = ATA_IDX_INW_STRM(ch, ATA_DATA);
831246257Smarius	        addr[i++] = buf[0];
832246257Smarius	        addr[i++] = buf[1];
833246257Smarius	    }
834246257Smarius	} else
835246257Smarius#endif
836246257Smarius	    ATA_IDX_INSW_STRM(ch, ATA_DATA, (void*)addr, size /
837246257Smarius	      sizeof(int16_t));
838214880Smav	if (size & 1) {
839246257Smarius	    *(uint16_t *)&buf = ATA_IDX_INW_STRM(ch, ATA_DATA);
840238673Smav	    (addr + (size & ~1))[0] = buf[0];
841214880Smav	}
842214880Smav    } else
843238673Smav	ATA_IDX_INSL_STRM(ch, ATA_DATA, (void*)addr, size / sizeof(int32_t));
844119404Ssos
845119404Ssos    if (request->transfersize < length) {
846198717Smav	device_printf(request->parent, "WARNING - %s read data overrun %d>%d\n",
847119404Ssos		   ata_cmd2str(request), length, request->transfersize);
848214880Smav	for (resid = request->transfersize + (size & 1); resid < length;
849119404Ssos	     resid += sizeof(int16_t))
850119404Ssos	    ATA_IDX_INW(ch, ATA_DATA);
851119404Ssos    }
852119404Ssos}
853119404Ssos
854119404Ssosstatic void
855119404Ssosata_pio_write(struct ata_request *request, int length)
856119404Ssos{
857178067Ssos    struct ata_channel *ch = device_get_softc(request->parent);
858238673Smav    uint8_t *addr;
859119404Ssos    int size = min(request->transfersize, length);
860119404Ssos    int resid;
861246257Smarius    uint8_t buf[2] __aligned(sizeof(int16_t));
862246257Smarius#ifndef __NO_STRICT_ALIGNMENT
863246257Smarius    int i;
864246257Smarius#endif
865119404Ssos
866246257Smarius    size = min(request->transfersize, length);
867238673Smav    addr = (uint8_t *)request->data + request->donecount;
868246257Smarius    if (__predict_false(ch->flags & ATA_USE_16BIT ||
869246257Smarius      (size % sizeof(int32_t)) || ((uintptr_t)addr % sizeof(int32_t)))) {
870246257Smarius#ifndef __NO_STRICT_ALIGNMENT
871246257Smarius	if (__predict_false((uintptr_t)addr % sizeof(int16_t))) {
872246257Smarius	    for (i = 0, resid = size & ~1; resid > 0; resid -=
873246257Smarius	      sizeof(int16_t)) {
874246257Smarius	        buf[0] = addr[i++];
875246257Smarius	        buf[1] = addr[i++];
876246257Smarius		ATA_IDX_OUTW_STRM(ch, ATA_DATA, *(uint16_t *)&buf);
877246257Smarius	    }
878246257Smarius	} else
879246257Smarius#endif
880246257Smarius	    ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (void*)addr, size /
881246257Smarius	      sizeof(int16_t));
882214880Smav	if (size & 1) {
883238673Smav	    buf[0] = (addr + (size & ~1))[0];
884246257Smarius	    ATA_IDX_OUTW_STRM(ch, ATA_DATA, *(uint16_t *)&buf);
885214880Smav	}
886214880Smav    } else
887238673Smav	ATA_IDX_OUTSL_STRM(ch, ATA_DATA, (void*)addr, size / sizeof(int32_t));
888119404Ssos
889119404Ssos    if (request->transfersize < length) {
890198717Smav	device_printf(request->parent, "WARNING - %s write data underrun %d>%d\n",
891119404Ssos		   ata_cmd2str(request), length, request->transfersize);
892214880Smav	for (resid = request->transfersize + (size & 1); resid < length;
893119404Ssos	     resid += sizeof(int16_t))
894119404Ssos	    ATA_IDX_OUTW(ch, ATA_DATA, 0);
895119404Ssos    }
896119404Ssos}
897