1c1b3d7c5SThomas E. Spanjaard /*-
2f6e8a0a1SImre Vadasz * Copyright (c) 1998 - 2006 Søren Schmidt <sos@FreeBSD.org>
3c1b3d7c5SThomas E. Spanjaard * All rights reserved.
4c1b3d7c5SThomas E. Spanjaard *
5c1b3d7c5SThomas E. Spanjaard * Redistribution and use in source and binary forms, with or without
6c1b3d7c5SThomas E. Spanjaard * modification, are permitted provided that the following conditions
7c1b3d7c5SThomas E. Spanjaard * are met:
8c1b3d7c5SThomas E. Spanjaard * 1. Redistributions of source code must retain the above copyright
9c1b3d7c5SThomas E. Spanjaard * notice, this list of conditions and the following disclaimer,
10c1b3d7c5SThomas E. Spanjaard * without modification, immediately at the beginning of the file.
11c1b3d7c5SThomas E. Spanjaard * 2. Redistributions in binary form must reproduce the above copyright
12c1b3d7c5SThomas E. Spanjaard * notice, this list of conditions and the following disclaimer in the
13c1b3d7c5SThomas E. Spanjaard * documentation and/or other materials provided with the distribution.
14c1b3d7c5SThomas E. Spanjaard *
15c1b3d7c5SThomas E. Spanjaard * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16c1b3d7c5SThomas E. Spanjaard * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17c1b3d7c5SThomas E. Spanjaard * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18c1b3d7c5SThomas E. Spanjaard * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19c1b3d7c5SThomas E. Spanjaard * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20c1b3d7c5SThomas E. Spanjaard * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21c1b3d7c5SThomas E. Spanjaard * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22c1b3d7c5SThomas E. Spanjaard * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23c1b3d7c5SThomas E. Spanjaard * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24c1b3d7c5SThomas E. Spanjaard * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25c1b3d7c5SThomas E. Spanjaard *
2602d7aa4aSSascha Wildner * $FreeBSD: src/sys/dev/ata/ata-queue.c,v 1.67 2007/01/27 21:15:58 remko Exp $
27c1b3d7c5SThomas E. Spanjaard */
28c1b3d7c5SThomas E. Spanjaard
29c1b3d7c5SThomas E. Spanjaard #include "opt_ata.h"
30c1b3d7c5SThomas E. Spanjaard
31c1b3d7c5SThomas E. Spanjaard #include <sys/param.h>
32c1b3d7c5SThomas E. Spanjaard #include <sys/bus.h>
33c1b3d7c5SThomas E. Spanjaard #include <sys/callout.h>
34c1b3d7c5SThomas E. Spanjaard #include <sys/nata.h>
35c1b3d7c5SThomas E. Spanjaard #include <sys/queue.h>
3615bd3c73SMatthew Dillon #include <sys/lock.h>
379469b9f3SMatthew Dillon #include <sys/buf.h>
38c1b3d7c5SThomas E. Spanjaard #include <sys/systm.h>
39c1b3d7c5SThomas E. Spanjaard #include <sys/taskqueue.h>
40c1b3d7c5SThomas E. Spanjaard
41c1b3d7c5SThomas E. Spanjaard #include "ata-all.h"
42c1b3d7c5SThomas E. Spanjaard #include "ata_if.h"
43c1b3d7c5SThomas E. Spanjaard
44c1b3d7c5SThomas E. Spanjaard /* prototypes */
45c1b3d7c5SThomas E. Spanjaard static void ata_completed(void *, int);
46c1b3d7c5SThomas E. Spanjaard static void ata_sort_queue(struct ata_channel *ch, struct ata_request *request);
479469b9f3SMatthew Dillon static void atawritereorder(struct ata_channel *ch);
48c1b3d7c5SThomas E. Spanjaard static char *ata_skey2str(u_int8_t);
49c1b3d7c5SThomas E. Spanjaard
50c1b3d7c5SThomas E. Spanjaard void
ata_queue_init(struct ata_channel * ch)519469b9f3SMatthew Dillon ata_queue_init(struct ata_channel *ch)
529469b9f3SMatthew Dillon {
539469b9f3SMatthew Dillon TAILQ_INIT(&ch->ata_queue);
549469b9f3SMatthew Dillon ch->reorder = 0;
559469b9f3SMatthew Dillon ch->transition = NULL;
569469b9f3SMatthew Dillon }
579469b9f3SMatthew Dillon
58ef352403SAlex Hornung /*
59ef352403SAlex Hornung * Rudely drop all requests queued to the channel of specified device.
60ef352403SAlex Hornung * XXX: The requests are leaked, use only in fatal case.
61ef352403SAlex Hornung */
62ef352403SAlex Hornung void
ata_drop_requests(device_t dev)63ef352403SAlex Hornung ata_drop_requests(device_t dev)
64ef352403SAlex Hornung {
65ef352403SAlex Hornung struct ata_channel *ch = device_get_softc(device_get_parent(dev));
66ef352403SAlex Hornung struct ata_request *request, *tmp;
67ef352403SAlex Hornung
6815bd3c73SMatthew Dillon lockmgr(&ch->queue_mtx, LK_EXCLUSIVE);
69ef352403SAlex Hornung TAILQ_FOREACH_MUTABLE(request, &ch->ata_queue, chain, tmp) {
70ef352403SAlex Hornung TAILQ_REMOVE(&ch->ata_queue, request, chain);
71ef352403SAlex Hornung request->result = ENXIO;
72ef352403SAlex Hornung }
7315bd3c73SMatthew Dillon lockmgr(&ch->queue_mtx, LK_RELEASE);
74ef352403SAlex Hornung }
75ef352403SAlex Hornung
769469b9f3SMatthew Dillon void
ata_queue_request(struct ata_request * request)77c1b3d7c5SThomas E. Spanjaard ata_queue_request(struct ata_request *request)
78c1b3d7c5SThomas E. Spanjaard {
79c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch;
80c1b3d7c5SThomas E. Spanjaard
81c1b3d7c5SThomas E. Spanjaard /* treat request as virgin (this might be an ATA_R_REQUEUE) */
82c1b3d7c5SThomas E. Spanjaard request->result = request->status = request->error = 0;
83c1b3d7c5SThomas E. Spanjaard
84c04da965Szrj /* check that the device is still valid */
85c1b3d7c5SThomas E. Spanjaard if (!(request->parent = device_get_parent(request->dev))) {
86c1b3d7c5SThomas E. Spanjaard request->result = ENXIO;
87c1b3d7c5SThomas E. Spanjaard if (request->callback)
88c1b3d7c5SThomas E. Spanjaard (request->callback)(request);
89c1b3d7c5SThomas E. Spanjaard return;
90c1b3d7c5SThomas E. Spanjaard }
91c1b3d7c5SThomas E. Spanjaard ch = device_get_softc(request->parent);
9215bd3c73SMatthew Dillon /* serialization done via state_mtx */
9315bd3c73SMatthew Dillon callout_init_lk(&request->callout, &ch->state_mtx);
94c1b3d7c5SThomas E. Spanjaard if (!request->callback && !(request->flags & ATA_R_REQUEUE))
9515bd3c73SMatthew Dillon lockinit(&request->done, "ataqueuerqdone", 0, 0);
96c1b3d7c5SThomas E. Spanjaard
97c1b3d7c5SThomas E. Spanjaard /* in ATA_STALL_QUEUE state we call HW directly */
98c1b3d7c5SThomas E. Spanjaard if ((ch->state & ATA_STALL_QUEUE) && (request->flags & ATA_R_CONTROL)) {
9915bd3c73SMatthew Dillon lockmgr(&ch->state_mtx, LK_EXCLUSIVE);
100c1b3d7c5SThomas E. Spanjaard ch->running = request;
101c1b3d7c5SThomas E. Spanjaard if (ch->hw.begin_transaction(request) == ATA_OP_FINISHED) {
102c1b3d7c5SThomas E. Spanjaard ch->running = NULL;
103c1b3d7c5SThomas E. Spanjaard if (!request->callback)
10415bd3c73SMatthew Dillon lockuninit(&request->done);
10515bd3c73SMatthew Dillon lockmgr(&ch->state_mtx, LK_RELEASE);
106c1b3d7c5SThomas E. Spanjaard return;
107c1b3d7c5SThomas E. Spanjaard }
108658104b9SMatthew Dillon /* interlock against interrupt */
109658104b9SMatthew Dillon request->flags |= ATA_R_HWCMDQUEUED;
11015bd3c73SMatthew Dillon lockmgr(&ch->state_mtx, LK_RELEASE);
111c1b3d7c5SThomas E. Spanjaard }
112c1b3d7c5SThomas E. Spanjaard /* otherwise put request on the locked queue at the specified location */
113c1b3d7c5SThomas E. Spanjaard else {
11415bd3c73SMatthew Dillon lockmgr(&ch->queue_mtx, LK_EXCLUSIVE);
1159469b9f3SMatthew Dillon if (request->flags & ATA_R_AT_HEAD) {
116c1b3d7c5SThomas E. Spanjaard TAILQ_INSERT_HEAD(&ch->ata_queue, request, chain);
1179469b9f3SMatthew Dillon } else if (request->flags & ATA_R_ORDERED) {
118c1b3d7c5SThomas E. Spanjaard ata_sort_queue(ch, request);
1199469b9f3SMatthew Dillon } else {
120c1b3d7c5SThomas E. Spanjaard TAILQ_INSERT_TAIL(&ch->ata_queue, request, chain);
1219469b9f3SMatthew Dillon ch->transition = NULL;
1229469b9f3SMatthew Dillon }
12315bd3c73SMatthew Dillon lockmgr(&ch->queue_mtx, LK_RELEASE);
124c1b3d7c5SThomas E. Spanjaard ATA_DEBUG_RQ(request, "queued");
125c1b3d7c5SThomas E. Spanjaard ata_start(ch->dev);
126c1b3d7c5SThomas E. Spanjaard }
127c1b3d7c5SThomas E. Spanjaard
128c1b3d7c5SThomas E. Spanjaard /* if this is a requeued request callback/sleep we're done */
129c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_REQUEUE)
130c1b3d7c5SThomas E. Spanjaard return;
131c1b3d7c5SThomas E. Spanjaard
132c1b3d7c5SThomas E. Spanjaard /* if this is not a callback wait until request is completed */
133c1b3d7c5SThomas E. Spanjaard if (!request->callback) {
1344554c338SThomas E. Spanjaard ATA_DEBUG_RQ(request, "wait for completion");
1354554c338SThomas E. Spanjaard if (!dumping) {
1364554c338SThomas E. Spanjaard /* interlock against wakeup */
13715bd3c73SMatthew Dillon lockmgr(&request->done, LK_EXCLUSIVE);
1384554c338SThomas E. Spanjaard /* check if the request was completed already */
1394554c338SThomas E. Spanjaard if (!(request->flags & ATA_R_COMPLETED))
14015bd3c73SMatthew Dillon lksleep(request, &request->done, 0, "ATA request completion "
1414554c338SThomas E. Spanjaard "wait", request->timeout * hz * 4);
14215bd3c73SMatthew Dillon lockmgr(&request->done, LK_RELEASE);
1434554c338SThomas E. Spanjaard /* check if the request was completed while sleeping */
1444554c338SThomas E. Spanjaard if (!(request->flags & ATA_R_COMPLETED)) {
1454554c338SThomas E. Spanjaard /* apparently not */
1464554c338SThomas E. Spanjaard device_printf(request->dev, "WARNING - %s taskqueue timeout - "
1474554c338SThomas E. Spanjaard "completing request directly\n",
148c1b3d7c5SThomas E. Spanjaard ata_cmd2str(request));
149c1b3d7c5SThomas E. Spanjaard request->flags |= ATA_R_DANGER1;
150c1b3d7c5SThomas E. Spanjaard ata_completed(request, 0);
151c1b3d7c5SThomas E. Spanjaard }
1524554c338SThomas E. Spanjaard }
15315bd3c73SMatthew Dillon lockuninit(&request->done);
154c1b3d7c5SThomas E. Spanjaard }
155c1b3d7c5SThomas E. Spanjaard }
156c1b3d7c5SThomas E. Spanjaard
157c1b3d7c5SThomas E. Spanjaard int
ata_controlcmd(device_t dev,u_int8_t command,u_int16_t feature,u_int64_t lba,u_int16_t count)158c1b3d7c5SThomas E. Spanjaard ata_controlcmd(device_t dev, u_int8_t command, u_int16_t feature,
159c1b3d7c5SThomas E. Spanjaard u_int64_t lba, u_int16_t count)
160c1b3d7c5SThomas E. Spanjaard {
1619243051bSzrj struct ata_device *atadev = device_get_softc(dev);
162c1b3d7c5SThomas E. Spanjaard struct ata_request *request = ata_alloc_request();
163c1b3d7c5SThomas E. Spanjaard int error = ENOMEM;
164c1b3d7c5SThomas E. Spanjaard
165c1b3d7c5SThomas E. Spanjaard if (request) {
166c1b3d7c5SThomas E. Spanjaard request->dev = dev;
167c1b3d7c5SThomas E. Spanjaard request->u.ata.command = command;
168c1b3d7c5SThomas E. Spanjaard request->u.ata.lba = lba;
169c1b3d7c5SThomas E. Spanjaard request->u.ata.count = count;
170c1b3d7c5SThomas E. Spanjaard request->u.ata.feature = feature;
171c1b3d7c5SThomas E. Spanjaard request->flags = ATA_R_CONTROL;
1729243051bSzrj if (atadev->spindown_state) {
1739243051bSzrj device_printf(dev, "request while spun down, starting.\n");
1749243051bSzrj atadev->spindown_state = 0;
1759243051bSzrj request->timeout = MAX(ATA_DEFAULT_TIMEOUT, 31);
1769243051bSzrj } else {
1776b7107f9SVenkatesh Srinivas request->timeout = ATA_DEFAULT_TIMEOUT;
1789243051bSzrj }
179c1b3d7c5SThomas E. Spanjaard request->retries = 0;
180c1b3d7c5SThomas E. Spanjaard ata_queue_request(request);
181c1b3d7c5SThomas E. Spanjaard error = request->result;
182c1b3d7c5SThomas E. Spanjaard ata_free_request(request);
183c1b3d7c5SThomas E. Spanjaard }
184c1b3d7c5SThomas E. Spanjaard return error;
185c1b3d7c5SThomas E. Spanjaard }
186c1b3d7c5SThomas E. Spanjaard
187c1b3d7c5SThomas E. Spanjaard int
ata_atapicmd(device_t dev,u_int8_t * ccb,caddr_t data,int count,int flags,int timeout)188c1b3d7c5SThomas E. Spanjaard ata_atapicmd(device_t dev, u_int8_t *ccb, caddr_t data,
189c1b3d7c5SThomas E. Spanjaard int count, int flags, int timeout)
190c1b3d7c5SThomas E. Spanjaard {
191c1b3d7c5SThomas E. Spanjaard struct ata_request *request = ata_alloc_request();
192c1b3d7c5SThomas E. Spanjaard struct ata_device *atadev = device_get_softc(dev);
193c1b3d7c5SThomas E. Spanjaard int error = ENOMEM;
194c1b3d7c5SThomas E. Spanjaard
195c1b3d7c5SThomas E. Spanjaard if (request) {
196c1b3d7c5SThomas E. Spanjaard request->dev = dev;
197c1b3d7c5SThomas E. Spanjaard if ((atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12)
198c1b3d7c5SThomas E. Spanjaard bcopy(ccb, request->u.atapi.ccb, 12);
199c1b3d7c5SThomas E. Spanjaard else
200c1b3d7c5SThomas E. Spanjaard bcopy(ccb, request->u.atapi.ccb, 16);
201c1b3d7c5SThomas E. Spanjaard request->data = data;
202c1b3d7c5SThomas E. Spanjaard request->bytecount = count;
203c1b3d7c5SThomas E. Spanjaard request->transfersize = min(request->bytecount, 65534);
204c1b3d7c5SThomas E. Spanjaard request->flags = flags | ATA_R_ATAPI;
205c1b3d7c5SThomas E. Spanjaard request->timeout = timeout;
206c1b3d7c5SThomas E. Spanjaard request->retries = 0;
207c1b3d7c5SThomas E. Spanjaard ata_queue_request(request);
208c1b3d7c5SThomas E. Spanjaard error = request->result;
209c1b3d7c5SThomas E. Spanjaard ata_free_request(request);
210c1b3d7c5SThomas E. Spanjaard }
211c1b3d7c5SThomas E. Spanjaard return error;
212c1b3d7c5SThomas E. Spanjaard }
213c1b3d7c5SThomas E. Spanjaard
214c1b3d7c5SThomas E. Spanjaard void
ata_start(device_t dev)215c1b3d7c5SThomas E. Spanjaard ata_start(device_t dev)
216c1b3d7c5SThomas E. Spanjaard {
217c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch = device_get_softc(dev);
218c1b3d7c5SThomas E. Spanjaard struct ata_request *request;
219c1b3d7c5SThomas E. Spanjaard struct ata_composite *cptr;
220c1b3d7c5SThomas E. Spanjaard int dependencies = 0;
221c1b3d7c5SThomas E. Spanjaard
222c1b3d7c5SThomas E. Spanjaard /* if we have a request on the queue try to get it running */
22315bd3c73SMatthew Dillon lockmgr(&ch->queue_mtx, LK_EXCLUSIVE);
224c1b3d7c5SThomas E. Spanjaard if ((request = TAILQ_FIRST(&ch->ata_queue))) {
225c1b3d7c5SThomas E. Spanjaard
226c1b3d7c5SThomas E. Spanjaard /* we need the locking function to get the lock for this channel */
227c1b3d7c5SThomas E. Spanjaard if (ATA_LOCKING(dev, ATA_LF_LOCK) == ch->unit) {
228c1b3d7c5SThomas E. Spanjaard
229c1b3d7c5SThomas E. Spanjaard /* check for composite dependencies */
230c1b3d7c5SThomas E. Spanjaard if ((cptr = request->composite)) {
23115bd3c73SMatthew Dillon lockmgr(&cptr->lock, LK_EXCLUSIVE);
232c1b3d7c5SThomas E. Spanjaard if ((request->flags & ATA_R_WRITE) &&
233c1b3d7c5SThomas E. Spanjaard (cptr->wr_depend & cptr->rd_done) != cptr->wr_depend) {
234c1b3d7c5SThomas E. Spanjaard dependencies = 1;
235c1b3d7c5SThomas E. Spanjaard }
23615bd3c73SMatthew Dillon lockmgr(&cptr->lock, LK_RELEASE);
237c1b3d7c5SThomas E. Spanjaard }
238c1b3d7c5SThomas E. Spanjaard
239c1b3d7c5SThomas E. Spanjaard /* check we are in the right state and has no dependencies */
24015bd3c73SMatthew Dillon lockmgr(&ch->state_mtx, LK_EXCLUSIVE);
241c1b3d7c5SThomas E. Spanjaard if (ch->state == ATA_IDLE && !dependencies) {
242c1b3d7c5SThomas E. Spanjaard ATA_DEBUG_RQ(request, "starting");
2439469b9f3SMatthew Dillon
2449469b9f3SMatthew Dillon if (ch->transition == request)
2459469b9f3SMatthew Dillon ch->transition = TAILQ_NEXT(request, chain);
246c1b3d7c5SThomas E. Spanjaard TAILQ_REMOVE(&ch->ata_queue, request, chain);
247c1b3d7c5SThomas E. Spanjaard ch->running = request;
248c1b3d7c5SThomas E. Spanjaard ch->state = ATA_ACTIVE;
249c1b3d7c5SThomas E. Spanjaard
250c1b3d7c5SThomas E. Spanjaard if (ch->hw.begin_transaction(request) == ATA_OP_FINISHED) {
251c1b3d7c5SThomas E. Spanjaard ch->running = NULL;
252c1b3d7c5SThomas E. Spanjaard ch->state = ATA_IDLE;
25315bd3c73SMatthew Dillon lockmgr(&ch->state_mtx, LK_RELEASE);
25415bd3c73SMatthew Dillon lockmgr(&ch->queue_mtx, LK_RELEASE);
255c1b3d7c5SThomas E. Spanjaard ATA_LOCKING(dev, ATA_LF_UNLOCK);
256c1b3d7c5SThomas E. Spanjaard ata_finish(request);
257c1b3d7c5SThomas E. Spanjaard return;
258c1b3d7c5SThomas E. Spanjaard }
259658104b9SMatthew Dillon
260658104b9SMatthew Dillon /* interlock against interrupt */
261658104b9SMatthew Dillon request->flags |= ATA_R_HWCMDQUEUED;
262658104b9SMatthew Dillon
263c1b3d7c5SThomas E. Spanjaard if (dumping) {
26415bd3c73SMatthew Dillon lockmgr(&ch->state_mtx, LK_RELEASE);
26515bd3c73SMatthew Dillon lockmgr(&ch->queue_mtx, LK_RELEASE);
266c1b3d7c5SThomas E. Spanjaard while (!ata_interrupt(ch))
267c1b3d7c5SThomas E. Spanjaard DELAY(10);
268c1b3d7c5SThomas E. Spanjaard return;
269c1b3d7c5SThomas E. Spanjaard }
270c1b3d7c5SThomas E. Spanjaard }
27115bd3c73SMatthew Dillon lockmgr(&ch->state_mtx, LK_RELEASE);
272c1b3d7c5SThomas E. Spanjaard }
273c1b3d7c5SThomas E. Spanjaard }
27415bd3c73SMatthew Dillon lockmgr(&ch->queue_mtx, LK_RELEASE);
275c1b3d7c5SThomas E. Spanjaard }
276c1b3d7c5SThomas E. Spanjaard
277c1b3d7c5SThomas E. Spanjaard void
ata_finish(struct ata_request * request)278c1b3d7c5SThomas E. Spanjaard ata_finish(struct ata_request *request)
279c1b3d7c5SThomas E. Spanjaard {
280c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch = device_get_softc(request->parent);
281c1b3d7c5SThomas E. Spanjaard
282c1b3d7c5SThomas E. Spanjaard /*
283c1b3d7c5SThomas E. Spanjaard * if in ATA_STALL_QUEUE state or request has ATA_R_DIRECT flags set
284c1b3d7c5SThomas E. Spanjaard * we need to call ata_complete() directly here (no taskqueue involvement)
285c1b3d7c5SThomas E. Spanjaard */
286c1b3d7c5SThomas E. Spanjaard if (dumping ||
287c1b3d7c5SThomas E. Spanjaard (ch->state & ATA_STALL_QUEUE) || (request->flags & ATA_R_DIRECT)) {
288c1b3d7c5SThomas E. Spanjaard ATA_DEBUG_RQ(request, "finish directly");
289c1b3d7c5SThomas E. Spanjaard ata_completed(request, 0);
290c1b3d7c5SThomas E. Spanjaard }
291c1b3d7c5SThomas E. Spanjaard else {
29287870bc8SMatthew Dillon /* put request on the proper taskqueue for completion */
29387870bc8SMatthew Dillon /* XXX FreeBSD has some sort of bio_taskqueue code here */
294c1b3d7c5SThomas E. Spanjaard TASK_INIT(&request->task, 0, ata_completed, request);
295cf5f86b6SMatthew Dillon ATA_DEBUG_RQ(request, "finish taskqueue_swi_mp");
296cf5f86b6SMatthew Dillon taskqueue_enqueue(taskqueue_swi_mp, &request->task);
297c1b3d7c5SThomas E. Spanjaard }
298c1b3d7c5SThomas E. Spanjaard }
299c1b3d7c5SThomas E. Spanjaard
300c1b3d7c5SThomas E. Spanjaard static void
ata_completed(void * context,int dummy)301c1b3d7c5SThomas E. Spanjaard ata_completed(void *context, int dummy)
302c1b3d7c5SThomas E. Spanjaard {
303c1b3d7c5SThomas E. Spanjaard struct ata_request *request = (struct ata_request *)context;
304c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch = device_get_softc(request->parent);
305c1b3d7c5SThomas E. Spanjaard struct ata_device *atadev = device_get_softc(request->dev);
306c1b3d7c5SThomas E. Spanjaard struct ata_composite *composite;
307c1b3d7c5SThomas E. Spanjaard
308c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_DANGER2) {
309c1b3d7c5SThomas E. Spanjaard device_printf(request->dev,
310c1b3d7c5SThomas E. Spanjaard "WARNING - %s freeing taskqueue zombie request\n",
311c1b3d7c5SThomas E. Spanjaard ata_cmd2str(request));
312c1b3d7c5SThomas E. Spanjaard request->flags &= ~(ATA_R_DANGER1 | ATA_R_DANGER2);
313c1b3d7c5SThomas E. Spanjaard ata_free_request(request);
314c1b3d7c5SThomas E. Spanjaard return;
315c1b3d7c5SThomas E. Spanjaard }
316c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_DANGER1)
317c1b3d7c5SThomas E. Spanjaard request->flags |= ATA_R_DANGER2;
318c1b3d7c5SThomas E. Spanjaard
319c1b3d7c5SThomas E. Spanjaard ATA_DEBUG_RQ(request, "completed entered");
320c1b3d7c5SThomas E. Spanjaard
321c1b3d7c5SThomas E. Spanjaard /* if we had a timeout, reinit channel and deal with the falldown */
322c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_TIMEOUT) {
323c1b3d7c5SThomas E. Spanjaard /*
324c1b3d7c5SThomas E. Spanjaard * if the channel is still present and
325c1b3d7c5SThomas E. Spanjaard * reinit succeeds and
326c1b3d7c5SThomas E. Spanjaard * the device doesn't get detached and
327c1b3d7c5SThomas E. Spanjaard * there are retries left we reinject this request
328c1b3d7c5SThomas E. Spanjaard */
329c1b3d7c5SThomas E. Spanjaard if (ch && !ata_reinit(ch->dev) && !request->result &&
330c1b3d7c5SThomas E. Spanjaard (request->retries-- > 0)) {
331c1b3d7c5SThomas E. Spanjaard if (!(request->flags & ATA_R_QUIET)) {
332c1b3d7c5SThomas E. Spanjaard device_printf(request->dev,
333c1b3d7c5SThomas E. Spanjaard "TIMEOUT - %s retrying (%d retr%s left)",
334c1b3d7c5SThomas E. Spanjaard ata_cmd2str(request), request->retries,
335c1b3d7c5SThomas E. Spanjaard request->retries == 1 ? "y" : "ies");
336c1b3d7c5SThomas E. Spanjaard if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
337e3869ec7SSascha Wildner kprintf(" LBA=%ju", request->u.ata.lba);
338e3869ec7SSascha Wildner kprintf("\n");
339c1b3d7c5SThomas E. Spanjaard }
340c1b3d7c5SThomas E. Spanjaard request->flags &= ~(ATA_R_TIMEOUT | ATA_R_DEBUG);
341c1b3d7c5SThomas E. Spanjaard request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE);
342c1b3d7c5SThomas E. Spanjaard ATA_DEBUG_RQ(request, "completed reinject");
343c1b3d7c5SThomas E. Spanjaard ata_queue_request(request);
344c1b3d7c5SThomas E. Spanjaard return;
345c1b3d7c5SThomas E. Spanjaard }
346c1b3d7c5SThomas E. Spanjaard
347c1b3d7c5SThomas E. Spanjaard /* ran out of good intentions so finish with error */
348c1b3d7c5SThomas E. Spanjaard if (!request->result) {
349c1b3d7c5SThomas E. Spanjaard if (!(request->flags & ATA_R_QUIET)) {
350c1b3d7c5SThomas E. Spanjaard if (request->dev) {
351c1b3d7c5SThomas E. Spanjaard device_printf(request->dev, "FAILURE - %s timed out",
352c1b3d7c5SThomas E. Spanjaard ata_cmd2str(request));
353c1b3d7c5SThomas E. Spanjaard if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
354e3869ec7SSascha Wildner kprintf(" LBA=%ju", request->u.ata.lba);
355e3869ec7SSascha Wildner kprintf("\n");
356c1b3d7c5SThomas E. Spanjaard }
357c1b3d7c5SThomas E. Spanjaard }
358c1b3d7c5SThomas E. Spanjaard request->result = EIO;
359c1b3d7c5SThomas E. Spanjaard }
360c1b3d7c5SThomas E. Spanjaard }
361c1b3d7c5SThomas E. Spanjaard else if (!(request->flags & ATA_R_ATAPI) ){
362c1b3d7c5SThomas E. Spanjaard /* if this is a soft ECC error warn about it */
363c1b3d7c5SThomas E. Spanjaard /* XXX SOS we could do WARF here */
364c1b3d7c5SThomas E. Spanjaard if ((request->status & (ATA_S_CORR | ATA_S_ERROR)) == ATA_S_CORR) {
365c1b3d7c5SThomas E. Spanjaard device_printf(request->dev,
366c1b3d7c5SThomas E. Spanjaard "WARNING - %s soft error (ECC corrected)",
367c1b3d7c5SThomas E. Spanjaard ata_cmd2str(request));
368c1b3d7c5SThomas E. Spanjaard if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
369e3869ec7SSascha Wildner kprintf(" LBA=%ju", request->u.ata.lba);
370e3869ec7SSascha Wildner kprintf("\n");
371c1b3d7c5SThomas E. Spanjaard }
372c1b3d7c5SThomas E. Spanjaard
373c1b3d7c5SThomas E. Spanjaard /* if this is a UDMA CRC error we reinject if there are retries left */
374c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_DMA && request->error & ATA_E_ICRC) {
375c1b3d7c5SThomas E. Spanjaard if (request->retries-- > 0) {
376c1b3d7c5SThomas E. Spanjaard device_printf(request->dev,
377c1b3d7c5SThomas E. Spanjaard "WARNING - %s UDMA ICRC error (retrying request)",
378c1b3d7c5SThomas E. Spanjaard ata_cmd2str(request));
379c1b3d7c5SThomas E. Spanjaard if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
380e3869ec7SSascha Wildner kprintf(" LBA=%ju", request->u.ata.lba);
381e3869ec7SSascha Wildner kprintf("\n");
382c1b3d7c5SThomas E. Spanjaard request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE);
383c1b3d7c5SThomas E. Spanjaard ata_queue_request(request);
384c1b3d7c5SThomas E. Spanjaard return;
385c1b3d7c5SThomas E. Spanjaard }
386c1b3d7c5SThomas E. Spanjaard }
387c1b3d7c5SThomas E. Spanjaard }
388c1b3d7c5SThomas E. Spanjaard
389c1b3d7c5SThomas E. Spanjaard switch (request->flags & ATA_R_ATAPI) {
390c1b3d7c5SThomas E. Spanjaard
391c1b3d7c5SThomas E. Spanjaard /* ATA errors */
392c1b3d7c5SThomas E. Spanjaard default:
393c1b3d7c5SThomas E. Spanjaard if (!request->result && request->status & ATA_S_ERROR) {
394c1b3d7c5SThomas E. Spanjaard if (!(request->flags & ATA_R_QUIET)) {
395c1b3d7c5SThomas E. Spanjaard device_printf(request->dev,
396c3783d8fSzrj "FAILURE - %s status=%pb%i error=%pb%i",
397c1b3d7c5SThomas E. Spanjaard ata_cmd2str(request),
398c3783d8fSzrj "\20\10BUSY\7READY\6DMA_READY"
399c1b3d7c5SThomas E. Spanjaard "\5DSC\4DRQ\3CORRECTABLE\2INDEX\1ERROR",
400c3783d8fSzrj request->status,
401c3783d8fSzrj "\20\10ICRC\7UNCORRECTABLE"
402c1b3d7c5SThomas E. Spanjaard "\6MEDIA_CHANGED\5NID_NOT_FOUND"
403c1b3d7c5SThomas E. Spanjaard "\4MEDIA_CHANGE_REQEST"
404c3783d8fSzrj "\3ABORTED\2NO_MEDIA\1ILLEGAL_LENGTH",
405c3783d8fSzrj request->error);
406c1b3d7c5SThomas E. Spanjaard if ((request->flags & ATA_R_DMA) &&
407c1b3d7c5SThomas E. Spanjaard (request->dmastat & ATA_BMSTAT_ERROR))
408e3869ec7SSascha Wildner kprintf(" dma=0x%02x", request->dmastat);
409c1b3d7c5SThomas E. Spanjaard if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
410e3869ec7SSascha Wildner kprintf(" LBA=%ju", request->u.ata.lba);
411e3869ec7SSascha Wildner kprintf("\n");
412c1b3d7c5SThomas E. Spanjaard }
413c1b3d7c5SThomas E. Spanjaard request->result = EIO;
414c1b3d7c5SThomas E. Spanjaard }
415c1b3d7c5SThomas E. Spanjaard break;
416c1b3d7c5SThomas E. Spanjaard
417c1b3d7c5SThomas E. Spanjaard /* ATAPI errors */
418c1b3d7c5SThomas E. Spanjaard case ATA_R_ATAPI:
419c1b3d7c5SThomas E. Spanjaard /* skip if result already set */
420c1b3d7c5SThomas E. Spanjaard if (request->result)
421c1b3d7c5SThomas E. Spanjaard break;
422c1b3d7c5SThomas E. Spanjaard
423c1b3d7c5SThomas E. Spanjaard /* if we have a sensekey -> request sense from device */
424c1b3d7c5SThomas E. Spanjaard if ((request->error & ATA_E_ATAPI_SENSE_MASK) &&
425c1b3d7c5SThomas E. Spanjaard (request->u.atapi.ccb[0] != ATAPI_REQUEST_SENSE)) {
426c1b3d7c5SThomas E. Spanjaard static u_int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0,
427c1b3d7c5SThomas E. Spanjaard sizeof(struct atapi_sense),
428c1b3d7c5SThomas E. Spanjaard 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
429c1b3d7c5SThomas E. Spanjaard
430c1b3d7c5SThomas E. Spanjaard request->u.atapi.saved_cmd = request->u.atapi.ccb[0];
431c1b3d7c5SThomas E. Spanjaard bcopy(ccb, request->u.atapi.ccb, 16);
432c1b3d7c5SThomas E. Spanjaard request->data = (caddr_t)&request->u.atapi.sense;
433c1b3d7c5SThomas E. Spanjaard request->bytecount = sizeof(struct atapi_sense);
434c1b3d7c5SThomas E. Spanjaard request->donecount = 0;
435c1b3d7c5SThomas E. Spanjaard request->transfersize = sizeof(struct atapi_sense);
4363c0963e0SMatthew Dillon request->timeout = ATA_DEFAULT_TIMEOUT;
437c1b3d7c5SThomas E. Spanjaard request->flags &= (ATA_R_ATAPI | ATA_R_QUIET);
438c1b3d7c5SThomas E. Spanjaard request->flags |= (ATA_R_READ | ATA_R_AT_HEAD | ATA_R_REQUEUE);
439c1b3d7c5SThomas E. Spanjaard ATA_DEBUG_RQ(request, "autoissue request sense");
440c1b3d7c5SThomas E. Spanjaard ata_queue_request(request);
441c1b3d7c5SThomas E. Spanjaard return;
442c1b3d7c5SThomas E. Spanjaard }
443c1b3d7c5SThomas E. Spanjaard
444c1b3d7c5SThomas E. Spanjaard switch (request->u.atapi.sense.key & ATA_SENSE_KEY_MASK) {
445c1b3d7c5SThomas E. Spanjaard case ATA_SENSE_RECOVERED_ERROR:
446c1b3d7c5SThomas E. Spanjaard device_printf(request->dev, "WARNING - %s recovered error\n",
447c1b3d7c5SThomas E. Spanjaard ata_cmd2str(request));
448c1b3d7c5SThomas E. Spanjaard /* FALLTHROUGH */
449c1b3d7c5SThomas E. Spanjaard
450c1b3d7c5SThomas E. Spanjaard case ATA_SENSE_NO_SENSE:
451c1b3d7c5SThomas E. Spanjaard request->result = 0;
452c1b3d7c5SThomas E. Spanjaard break;
453c1b3d7c5SThomas E. Spanjaard
454c1b3d7c5SThomas E. Spanjaard case ATA_SENSE_NOT_READY:
455c1b3d7c5SThomas E. Spanjaard request->result = EBUSY;
456c1b3d7c5SThomas E. Spanjaard break;
457c1b3d7c5SThomas E. Spanjaard
458c1b3d7c5SThomas E. Spanjaard case ATA_SENSE_UNIT_ATTENTION:
459c1b3d7c5SThomas E. Spanjaard atadev->flags |= ATA_D_MEDIA_CHANGED;
460c1b3d7c5SThomas E. Spanjaard request->result = EIO;
461c1b3d7c5SThomas E. Spanjaard break;
462c1b3d7c5SThomas E. Spanjaard
463c1b3d7c5SThomas E. Spanjaard default:
464c1b3d7c5SThomas E. Spanjaard request->result = EIO;
465c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_QUIET)
466c1b3d7c5SThomas E. Spanjaard break;
467c1b3d7c5SThomas E. Spanjaard
468c1b3d7c5SThomas E. Spanjaard device_printf(request->dev,
469c1b3d7c5SThomas E. Spanjaard "FAILURE - %s %s asc=0x%02x ascq=0x%02x ",
470c1b3d7c5SThomas E. Spanjaard ata_cmd2str(request), ata_skey2str(
471c1b3d7c5SThomas E. Spanjaard (request->u.atapi.sense.key & ATA_SENSE_KEY_MASK)),
472c1b3d7c5SThomas E. Spanjaard request->u.atapi.sense.asc,
473c1b3d7c5SThomas E. Spanjaard request->u.atapi.sense.ascq);
474c1b3d7c5SThomas E. Spanjaard if (request->u.atapi.sense.specific & ATA_SENSE_SPEC_VALID)
475e3869ec7SSascha Wildner kprintf("sks=0x%02x 0x%02x 0x%02x\n",
476c1b3d7c5SThomas E. Spanjaard request->u.atapi.sense.specific & ATA_SENSE_SPEC_MASK,
477c1b3d7c5SThomas E. Spanjaard request->u.atapi.sense.specific1,
478c1b3d7c5SThomas E. Spanjaard request->u.atapi.sense.specific2);
479c1b3d7c5SThomas E. Spanjaard else
480e3869ec7SSascha Wildner kprintf("\n");
481c1b3d7c5SThomas E. Spanjaard }
482c1b3d7c5SThomas E. Spanjaard
483c1b3d7c5SThomas E. Spanjaard if ((request->u.atapi.sense.key & ATA_SENSE_KEY_MASK ?
484c1b3d7c5SThomas E. Spanjaard request->u.atapi.sense.key & ATA_SENSE_KEY_MASK :
485c1b3d7c5SThomas E. Spanjaard request->error))
486c1b3d7c5SThomas E. Spanjaard request->result = EIO;
487c1b3d7c5SThomas E. Spanjaard }
488c1b3d7c5SThomas E. Spanjaard
489c1b3d7c5SThomas E. Spanjaard ATA_DEBUG_RQ(request, "completed callback/wakeup");
490c1b3d7c5SThomas E. Spanjaard
491c1b3d7c5SThomas E. Spanjaard /* if we are part of a composite operation we need to maintain progress */
492c1b3d7c5SThomas E. Spanjaard if ((composite = request->composite)) {
493c1b3d7c5SThomas E. Spanjaard int index = 0;
494c1b3d7c5SThomas E. Spanjaard
49515bd3c73SMatthew Dillon lockmgr(&composite->lock, LK_EXCLUSIVE);
496c1b3d7c5SThomas E. Spanjaard
497c1b3d7c5SThomas E. Spanjaard /* update whats done */
498c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_READ)
499c1b3d7c5SThomas E. Spanjaard composite->rd_done |= (1 << request->this);
500c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_WRITE)
501c1b3d7c5SThomas E. Spanjaard composite->wr_done |= (1 << request->this);
502c1b3d7c5SThomas E. Spanjaard
503c1b3d7c5SThomas E. Spanjaard /* find ready to go dependencies */
504c1b3d7c5SThomas E. Spanjaard if (composite->wr_depend &&
505c1b3d7c5SThomas E. Spanjaard (composite->rd_done & composite->wr_depend)==composite->wr_depend &&
506c1b3d7c5SThomas E. Spanjaard (composite->wr_needed & (~composite->wr_done))) {
507c1b3d7c5SThomas E. Spanjaard index = composite->wr_needed & ~composite->wr_done;
508c1b3d7c5SThomas E. Spanjaard }
509c1b3d7c5SThomas E. Spanjaard
51015bd3c73SMatthew Dillon lockmgr(&composite->lock, LK_RELEASE);
511c1b3d7c5SThomas E. Spanjaard
512c1b3d7c5SThomas E. Spanjaard /* if we have any ready candidates kick them off */
513c1b3d7c5SThomas E. Spanjaard if (index) {
514c1b3d7c5SThomas E. Spanjaard int bit;
515c1b3d7c5SThomas E. Spanjaard
516c1b3d7c5SThomas E. Spanjaard for (bit = 0; bit < MAX_COMPOSITES; bit++) {
517c1b3d7c5SThomas E. Spanjaard if (index & (1 << bit))
518c1b3d7c5SThomas E. Spanjaard ata_start(device_get_parent(composite->request[bit]->dev));
519c1b3d7c5SThomas E. Spanjaard }
520c1b3d7c5SThomas E. Spanjaard }
521c1b3d7c5SThomas E. Spanjaard }
522c1b3d7c5SThomas E. Spanjaard
523c1b3d7c5SThomas E. Spanjaard /* get results back to the initiator for this request */
524c1b3d7c5SThomas E. Spanjaard if (request->callback)
525c1b3d7c5SThomas E. Spanjaard (request->callback)(request);
526c1b3d7c5SThomas E. Spanjaard else {
52715bd3c73SMatthew Dillon lockmgr(&request->done, LK_EXCLUSIVE);
5284554c338SThomas E. Spanjaard request->flags |= ATA_R_COMPLETED;
52915bd3c73SMatthew Dillon lockmgr(&request->done, LK_RELEASE);
53087870bc8SMatthew Dillon wakeup_one(request);
531c1b3d7c5SThomas E. Spanjaard }
532c1b3d7c5SThomas E. Spanjaard
533c1b3d7c5SThomas E. Spanjaard /* only call ata_start if channel is present */
534c1b3d7c5SThomas E. Spanjaard if (ch)
535c1b3d7c5SThomas E. Spanjaard ata_start(ch->dev);
536c1b3d7c5SThomas E. Spanjaard }
537c1b3d7c5SThomas E. Spanjaard
538c1b3d7c5SThomas E. Spanjaard void
ata_timeout(struct ata_request * request)539c1b3d7c5SThomas E. Spanjaard ata_timeout(struct ata_request *request)
540c1b3d7c5SThomas E. Spanjaard {
541c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch = device_get_softc(request->parent);
542c1b3d7c5SThomas E. Spanjaard
54315bd3c73SMatthew Dillon /*
54415bd3c73SMatthew Dillon * NOTE: callout acquired ch->state_mtx for us.
54515bd3c73SMatthew Dillon */
546c1b3d7c5SThomas E. Spanjaard /*request->flags |= ATA_R_DEBUG;*/
547c1b3d7c5SThomas E. Spanjaard ATA_DEBUG_RQ(request, "timeout");
548c1b3d7c5SThomas E. Spanjaard
549c1b3d7c5SThomas E. Spanjaard /*
550c1b3d7c5SThomas E. Spanjaard * if we have an ATA_ACTIVE request running, we flag the request
551c1b3d7c5SThomas E. Spanjaard * ATA_R_TIMEOUT so ata_finish will handle it correctly
552c1b3d7c5SThomas E. Spanjaard * also NULL out the running request so we wont loose
553c1b3d7c5SThomas E. Spanjaard * the race with an eventual interrupt arriving late
554c1b3d7c5SThomas E. Spanjaard */
555c1b3d7c5SThomas E. Spanjaard if (ch->state == ATA_ACTIVE) {
556c1b3d7c5SThomas E. Spanjaard request->flags |= ATA_R_TIMEOUT;
55715bd3c73SMatthew Dillon lockmgr(&ch->state_mtx, LK_RELEASE);
558c1b3d7c5SThomas E. Spanjaard ATA_LOCKING(ch->dev, ATA_LF_UNLOCK);
559c1b3d7c5SThomas E. Spanjaard ata_finish(request);
56015bd3c73SMatthew Dillon lockmgr(&ch->state_mtx, LK_EXCLUSIVE);
561c1b3d7c5SThomas E. Spanjaard }
562c1b3d7c5SThomas E. Spanjaard }
563c1b3d7c5SThomas E. Spanjaard
564c1b3d7c5SThomas E. Spanjaard void
ata_fail_requests(device_t dev)565c1b3d7c5SThomas E. Spanjaard ata_fail_requests(device_t dev)
566c1b3d7c5SThomas E. Spanjaard {
567c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch = device_get_softc(device_get_parent(dev));
568c1b3d7c5SThomas E. Spanjaard struct ata_request *request, *tmp;
569c1b3d7c5SThomas E. Spanjaard TAILQ_HEAD(, ata_request) fail_requests;
570c1b3d7c5SThomas E. Spanjaard TAILQ_INIT(&fail_requests);
571c1b3d7c5SThomas E. Spanjaard
572c1b3d7c5SThomas E. Spanjaard /* grap all channel locks to avoid races */
57315bd3c73SMatthew Dillon lockmgr(&ch->queue_mtx, LK_EXCLUSIVE);
57415bd3c73SMatthew Dillon lockmgr(&ch->state_mtx, LK_EXCLUSIVE);
575c1b3d7c5SThomas E. Spanjaard
576c1b3d7c5SThomas E. Spanjaard /* do we have any running request to care about ? */
577c1b3d7c5SThomas E. Spanjaard if ((request = ch->running) && (!dev || request->dev == dev)) {
578*eb67213aSMatthew Dillon callout_cancel(&request->callout);
579c1b3d7c5SThomas E. Spanjaard ch->running = NULL;
580c1b3d7c5SThomas E. Spanjaard request->result = ENXIO;
581c1b3d7c5SThomas E. Spanjaard TAILQ_INSERT_TAIL(&fail_requests, request, chain);
582c1b3d7c5SThomas E. Spanjaard }
583c1b3d7c5SThomas E. Spanjaard
584c1b3d7c5SThomas E. Spanjaard /* fail all requests queued on this channel for device dev if !NULL */
585c1b3d7c5SThomas E. Spanjaard TAILQ_FOREACH_MUTABLE(request, &ch->ata_queue, chain, tmp) {
586c1b3d7c5SThomas E. Spanjaard if (!dev || request->dev == dev) {
5879469b9f3SMatthew Dillon if (ch->transition == request)
5889469b9f3SMatthew Dillon ch->transition = TAILQ_NEXT(request, chain);
589c1b3d7c5SThomas E. Spanjaard TAILQ_REMOVE(&ch->ata_queue, request, chain);
590c1b3d7c5SThomas E. Spanjaard request->result = ENXIO;
591c1b3d7c5SThomas E. Spanjaard TAILQ_INSERT_TAIL(&fail_requests, request, chain);
592c1b3d7c5SThomas E. Spanjaard }
593c1b3d7c5SThomas E. Spanjaard }
594c1b3d7c5SThomas E. Spanjaard
59515bd3c73SMatthew Dillon lockmgr(&ch->state_mtx, LK_RELEASE);
59615bd3c73SMatthew Dillon lockmgr(&ch->queue_mtx, LK_RELEASE);
597c1b3d7c5SThomas E. Spanjaard
598c1b3d7c5SThomas E. Spanjaard /* finish up all requests collected above */
599c1b3d7c5SThomas E. Spanjaard TAILQ_FOREACH_MUTABLE(request, &fail_requests, chain, tmp) {
600c1b3d7c5SThomas E. Spanjaard TAILQ_REMOVE(&fail_requests, request, chain);
601c1b3d7c5SThomas E. Spanjaard ata_finish(request);
602c1b3d7c5SThomas E. Spanjaard }
603c1b3d7c5SThomas E. Spanjaard }
604c1b3d7c5SThomas E. Spanjaard
605c1b3d7c5SThomas E. Spanjaard static u_int64_t
ata_get_lba(struct ata_request * request)606c1b3d7c5SThomas E. Spanjaard ata_get_lba(struct ata_request *request)
607c1b3d7c5SThomas E. Spanjaard {
608c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_ATAPI) {
609c1b3d7c5SThomas E. Spanjaard switch (request->u.atapi.ccb[0]) {
610c1b3d7c5SThomas E. Spanjaard case ATAPI_READ_BIG:
611c1b3d7c5SThomas E. Spanjaard case ATAPI_WRITE_BIG:
612c1b3d7c5SThomas E. Spanjaard case ATAPI_READ_CD:
613c1b3d7c5SThomas E. Spanjaard return (request->u.atapi.ccb[5]) | (request->u.atapi.ccb[4]<<8) |
614c1b3d7c5SThomas E. Spanjaard (request->u.atapi.ccb[3]<<16)|(request->u.atapi.ccb[2]<<24);
615c1b3d7c5SThomas E. Spanjaard case ATAPI_READ:
616c1b3d7c5SThomas E. Spanjaard case ATAPI_WRITE:
617c1b3d7c5SThomas E. Spanjaard return (request->u.atapi.ccb[4]) | (request->u.atapi.ccb[3]<<8) |
618c1b3d7c5SThomas E. Spanjaard (request->u.atapi.ccb[2]<<16);
619c1b3d7c5SThomas E. Spanjaard default:
620c1b3d7c5SThomas E. Spanjaard return 0;
621c1b3d7c5SThomas E. Spanjaard }
622c1b3d7c5SThomas E. Spanjaard }
623c1b3d7c5SThomas E. Spanjaard else
624c1b3d7c5SThomas E. Spanjaard return request->u.ata.lba;
625c1b3d7c5SThomas E. Spanjaard }
626c1b3d7c5SThomas E. Spanjaard
6279469b9f3SMatthew Dillon /*
6289469b9f3SMatthew Dillon * This implements exactly bioqdisksort() in the DragonFly kernel.
6299469b9f3SMatthew Dillon * The short description is: Because megabytes and megabytes worth of
6309469b9f3SMatthew Dillon * writes can be queued there needs to be a read-prioritization mechanism
6319469b9f3SMatthew Dillon * or reads get completely starved out.
6329469b9f3SMatthew Dillon */
633c1b3d7c5SThomas E. Spanjaard static void
ata_sort_queue(struct ata_channel * ch,struct ata_request * request)634c1b3d7c5SThomas E. Spanjaard ata_sort_queue(struct ata_channel *ch, struct ata_request *request)
635c1b3d7c5SThomas E. Spanjaard {
6369469b9f3SMatthew Dillon if ((request->flags & ATA_R_WRITE) == 0) {
6379469b9f3SMatthew Dillon if (ch->transition) {
6381d727bacSMatthew Dillon /*
6399469b9f3SMatthew Dillon * Insert before the first write
6401d727bacSMatthew Dillon */
6419469b9f3SMatthew Dillon TAILQ_INSERT_BEFORE(ch->transition, request, chain);
6424afeea0dSMatthew Dillon if (++ch->reorder >= bioq_reorder_minor_interval) {
6439469b9f3SMatthew Dillon ch->reorder = 0;
6449469b9f3SMatthew Dillon atawritereorder(ch);
64503a48513SMatthew Dillon }
646dbe4d046SMatthew Dillon } else {
6479469b9f3SMatthew Dillon /*
6489469b9f3SMatthew Dillon * No writes queued (or ordering was forced),
6499469b9f3SMatthew Dillon * insert at tail.
6509469b9f3SMatthew Dillon */
6519469b9f3SMatthew Dillon TAILQ_INSERT_TAIL(&ch->ata_queue, request, chain);
6529469b9f3SMatthew Dillon }
6539469b9f3SMatthew Dillon } else {
6549469b9f3SMatthew Dillon /*
6559469b9f3SMatthew Dillon * Writes are always appended. If no writes were previously
6569469b9f3SMatthew Dillon * queued or an ordered tail insertion occured the transition
6579469b9f3SMatthew Dillon * field will be NULL.
6589469b9f3SMatthew Dillon */
6599469b9f3SMatthew Dillon TAILQ_INSERT_TAIL(&ch->ata_queue, request, chain);
6609469b9f3SMatthew Dillon if (ch->transition == NULL)
6619469b9f3SMatthew Dillon ch->transition = request;
6629469b9f3SMatthew Dillon }
6639469b9f3SMatthew Dillon if (request->composite) {
6649469b9f3SMatthew Dillon ch->transition = NULL;
6659469b9f3SMatthew Dillon ch->reorder = 0;
6669469b9f3SMatthew Dillon }
6679469b9f3SMatthew Dillon }
6689469b9f3SMatthew Dillon
6699469b9f3SMatthew Dillon /*
6709469b9f3SMatthew Dillon * Move the transition point to prevent reads from completely
6719469b9f3SMatthew Dillon * starving our writes. This brings a number of writes into
6729469b9f3SMatthew Dillon * the fold every N reads.
6739469b9f3SMatthew Dillon */
6749469b9f3SMatthew Dillon static void
atawritereorder(struct ata_channel * ch)6759469b9f3SMatthew Dillon atawritereorder(struct ata_channel *ch)
6769469b9f3SMatthew Dillon {
6779469b9f3SMatthew Dillon struct ata_request *req;
6789469b9f3SMatthew Dillon u_int64_t next_offset;
6794afeea0dSMatthew Dillon size_t left = (size_t)bioq_reorder_minor_bytes;
6809469b9f3SMatthew Dillon size_t n;
6819469b9f3SMatthew Dillon
6829469b9f3SMatthew Dillon next_offset = ata_get_lba(ch->transition);
6839469b9f3SMatthew Dillon while ((req = ch->transition) != NULL &&
6849469b9f3SMatthew Dillon next_offset == ata_get_lba(req)) {
6859469b9f3SMatthew Dillon n = req->u.ata.count;
6869469b9f3SMatthew Dillon next_offset = ata_get_lba(req);
6879469b9f3SMatthew Dillon ch->transition = TAILQ_NEXT(req, chain);
6889469b9f3SMatthew Dillon if (left < n)
6899469b9f3SMatthew Dillon break;
6909469b9f3SMatthew Dillon left -= n;
691c1b3d7c5SThomas E. Spanjaard }
692dbe4d046SMatthew Dillon }
693c1b3d7c5SThomas E. Spanjaard
69459503772Szrj const char *
ata_cmd2str(struct ata_request * request)695c1b3d7c5SThomas E. Spanjaard ata_cmd2str(struct ata_request *request)
696c1b3d7c5SThomas E. Spanjaard {
697c1b3d7c5SThomas E. Spanjaard static char buffer[20];
698c1b3d7c5SThomas E. Spanjaard
699c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_ATAPI) {
700c1b3d7c5SThomas E. Spanjaard switch (request->u.atapi.sense.key ?
701c1b3d7c5SThomas E. Spanjaard request->u.atapi.saved_cmd : request->u.atapi.ccb[0]) {
702c1b3d7c5SThomas E. Spanjaard case 0x00: return ("TEST_UNIT_READY");
703c1b3d7c5SThomas E. Spanjaard case 0x01: return ("REZERO");
704c1b3d7c5SThomas E. Spanjaard case 0x03: return ("REQUEST_SENSE");
705c1b3d7c5SThomas E. Spanjaard case 0x04: return ("FORMAT");
706c1b3d7c5SThomas E. Spanjaard case 0x08: return ("READ");
707c1b3d7c5SThomas E. Spanjaard case 0x0a: return ("WRITE");
708c1b3d7c5SThomas E. Spanjaard case 0x10: return ("WEOF");
709c1b3d7c5SThomas E. Spanjaard case 0x11: return ("SPACE");
710c1b3d7c5SThomas E. Spanjaard case 0x12: return ("INQUIRY");
711c1b3d7c5SThomas E. Spanjaard case 0x15: return ("MODE_SELECT");
712c1b3d7c5SThomas E. Spanjaard case 0x19: return ("ERASE");
713c1b3d7c5SThomas E. Spanjaard case 0x1a: return ("MODE_SENSE");
714c1b3d7c5SThomas E. Spanjaard case 0x1b: return ("START_STOP");
715c1b3d7c5SThomas E. Spanjaard case 0x1e: return ("PREVENT_ALLOW");
716c1b3d7c5SThomas E. Spanjaard case 0x23: return ("ATAPI_READ_FORMAT_CAPACITIES");
717c1b3d7c5SThomas E. Spanjaard case 0x25: return ("READ_CAPACITY");
718c1b3d7c5SThomas E. Spanjaard case 0x28: return ("READ_BIG");
719c1b3d7c5SThomas E. Spanjaard case 0x2a: return ("WRITE_BIG");
720c1b3d7c5SThomas E. Spanjaard case 0x2b: return ("LOCATE");
721c1b3d7c5SThomas E. Spanjaard case 0x34: return ("READ_POSITION");
722c1b3d7c5SThomas E. Spanjaard case 0x35: return ("SYNCHRONIZE_CACHE");
723c1b3d7c5SThomas E. Spanjaard case 0x3b: return ("WRITE_BUFFER");
724c1b3d7c5SThomas E. Spanjaard case 0x3c: return ("READ_BUFFER");
725c1b3d7c5SThomas E. Spanjaard case 0x42: return ("READ_SUBCHANNEL");
726c1b3d7c5SThomas E. Spanjaard case 0x43: return ("READ_TOC");
727c1b3d7c5SThomas E. Spanjaard case 0x45: return ("PLAY_10");
728c1b3d7c5SThomas E. Spanjaard case 0x47: return ("PLAY_MSF");
729c1b3d7c5SThomas E. Spanjaard case 0x48: return ("PLAY_TRACK");
730c1b3d7c5SThomas E. Spanjaard case 0x4b: return ("PAUSE");
731c1b3d7c5SThomas E. Spanjaard case 0x51: return ("READ_DISK_INFO");
732c1b3d7c5SThomas E. Spanjaard case 0x52: return ("READ_TRACK_INFO");
733c1b3d7c5SThomas E. Spanjaard case 0x53: return ("RESERVE_TRACK");
734c1b3d7c5SThomas E. Spanjaard case 0x54: return ("SEND_OPC_INFO");
735c1b3d7c5SThomas E. Spanjaard case 0x55: return ("MODE_SELECT_BIG");
736c1b3d7c5SThomas E. Spanjaard case 0x58: return ("REPAIR_TRACK");
737c1b3d7c5SThomas E. Spanjaard case 0x59: return ("READ_MASTER_CUE");
738c1b3d7c5SThomas E. Spanjaard case 0x5a: return ("MODE_SENSE_BIG");
739c1b3d7c5SThomas E. Spanjaard case 0x5b: return ("CLOSE_TRACK/SESSION");
740c1b3d7c5SThomas E. Spanjaard case 0x5c: return ("READ_BUFFER_CAPACITY");
741c1b3d7c5SThomas E. Spanjaard case 0x5d: return ("SEND_CUE_SHEET");
742d55cd0cbSMatthew Dillon case 0x96: return ("READ_CAPACITY_16");
743c1b3d7c5SThomas E. Spanjaard case 0xa1: return ("BLANK_CMD");
744c1b3d7c5SThomas E. Spanjaard case 0xa3: return ("SEND_KEY");
745c1b3d7c5SThomas E. Spanjaard case 0xa4: return ("REPORT_KEY");
746c1b3d7c5SThomas E. Spanjaard case 0xa5: return ("PLAY_12");
747c1b3d7c5SThomas E. Spanjaard case 0xa6: return ("LOAD_UNLOAD");
748c1b3d7c5SThomas E. Spanjaard case 0xad: return ("READ_DVD_STRUCTURE");
749c1b3d7c5SThomas E. Spanjaard case 0xb4: return ("PLAY_CD");
750c1b3d7c5SThomas E. Spanjaard case 0xbb: return ("SET_SPEED");
751c1b3d7c5SThomas E. Spanjaard case 0xbd: return ("MECH_STATUS");
752c1b3d7c5SThomas E. Spanjaard case 0xbe: return ("READ_CD");
753c1b3d7c5SThomas E. Spanjaard case 0xff: return ("POLL_DSC");
754c1b3d7c5SThomas E. Spanjaard }
755c1b3d7c5SThomas E. Spanjaard }
756c1b3d7c5SThomas E. Spanjaard else {
757c1b3d7c5SThomas E. Spanjaard switch (request->u.ata.command) {
758c1b3d7c5SThomas E. Spanjaard case 0x00: return ("NOP");
759c1b3d7c5SThomas E. Spanjaard case 0x08: return ("DEVICE_RESET");
760c1b3d7c5SThomas E. Spanjaard case 0x20: return ("READ");
761c1b3d7c5SThomas E. Spanjaard case 0x24: return ("READ48");
762c1b3d7c5SThomas E. Spanjaard case 0x25: return ("READ_DMA48");
763c1b3d7c5SThomas E. Spanjaard case 0x26: return ("READ_DMA_QUEUED48");
764bb15467aSzrj case 0x27: return ("READ_NATIVE_MAX_ADDRESS48");
765c1b3d7c5SThomas E. Spanjaard case 0x29: return ("READ_MUL48");
766c1b3d7c5SThomas E. Spanjaard case 0x30: return ("WRITE");
767c1b3d7c5SThomas E. Spanjaard case 0x34: return ("WRITE48");
768c1b3d7c5SThomas E. Spanjaard case 0x35: return ("WRITE_DMA48");
769c1b3d7c5SThomas E. Spanjaard case 0x36: return ("WRITE_DMA_QUEUED48");
770c1b3d7c5SThomas E. Spanjaard case 0x39: return ("WRITE_MUL48");
771c1b3d7c5SThomas E. Spanjaard case 0x70: return ("SEEK");
772c1b3d7c5SThomas E. Spanjaard case 0xa0: return ("PACKET_CMD");
773c1b3d7c5SThomas E. Spanjaard case 0xa1: return ("ATAPI_IDENTIFY");
774c1b3d7c5SThomas E. Spanjaard case 0xa2: return ("SERVICE");
77587870bc8SMatthew Dillon case 0xb0: return ("SMART");
776c1b3d7c5SThomas E. Spanjaard case 0xc0: return ("CFA ERASE");
777c1b3d7c5SThomas E. Spanjaard case 0xc4: return ("READ_MUL");
778c1b3d7c5SThomas E. Spanjaard case 0xc5: return ("WRITE_MUL");
779c1b3d7c5SThomas E. Spanjaard case 0xc6: return ("SET_MULTI");
780c1b3d7c5SThomas E. Spanjaard case 0xc7: return ("READ_DMA_QUEUED");
781c1b3d7c5SThomas E. Spanjaard case 0xc8: return ("READ_DMA");
782c1b3d7c5SThomas E. Spanjaard case 0xca: return ("WRITE_DMA");
783c1b3d7c5SThomas E. Spanjaard case 0xcc: return ("WRITE_DMA_QUEUED");
784c1b3d7c5SThomas E. Spanjaard case 0xe6: return ("SLEEP");
785c1b3d7c5SThomas E. Spanjaard case 0xe7: return ("FLUSHCACHE");
786c1b3d7c5SThomas E. Spanjaard case 0xea: return ("FLUSHCACHE48");
787c1b3d7c5SThomas E. Spanjaard case 0xec: return ("ATA_IDENTIFY");
788c1b3d7c5SThomas E. Spanjaard case 0xef:
789c1b3d7c5SThomas E. Spanjaard switch (request->u.ata.feature) {
790c1b3d7c5SThomas E. Spanjaard case 0x03: return ("SETFEATURES SET TRANSFER MODE");
791c1b3d7c5SThomas E. Spanjaard case 0x02: return ("SETFEATURES ENABLE WCACHE");
792c1b3d7c5SThomas E. Spanjaard case 0x82: return ("SETFEATURES DISABLE WCACHE");
793c1b3d7c5SThomas E. Spanjaard case 0xaa: return ("SETFEATURES ENABLE RCACHE");
794c1b3d7c5SThomas E. Spanjaard case 0x55: return ("SETFEATURES DISABLE RCACHE");
795c1b3d7c5SThomas E. Spanjaard }
796f8c7a42dSMatthew Dillon ksprintf(buffer, "SETFEATURES 0x%02x", request->u.ata.feature);
797c1b3d7c5SThomas E. Spanjaard return buffer;
798bb15467aSzrj case 0xf8: return ("READ_NATIVE_MAX_ADDRESS");
799c1b3d7c5SThomas E. Spanjaard }
800c1b3d7c5SThomas E. Spanjaard }
801f8c7a42dSMatthew Dillon ksprintf(buffer, "unknown CMD (0x%02x)", request->u.ata.command);
802c1b3d7c5SThomas E. Spanjaard return buffer;
803c1b3d7c5SThomas E. Spanjaard }
804c1b3d7c5SThomas E. Spanjaard
805c1b3d7c5SThomas E. Spanjaard static char *
ata_skey2str(u_int8_t skey)806c1b3d7c5SThomas E. Spanjaard ata_skey2str(u_int8_t skey)
807c1b3d7c5SThomas E. Spanjaard {
808c1b3d7c5SThomas E. Spanjaard switch (skey) {
809c1b3d7c5SThomas E. Spanjaard case 0x00: return ("NO SENSE");
810c1b3d7c5SThomas E. Spanjaard case 0x01: return ("RECOVERED ERROR");
811c1b3d7c5SThomas E. Spanjaard case 0x02: return ("NOT READY");
812c1b3d7c5SThomas E. Spanjaard case 0x03: return ("MEDIUM ERROR");
813c1b3d7c5SThomas E. Spanjaard case 0x04: return ("HARDWARE ERROR");
814c1b3d7c5SThomas E. Spanjaard case 0x05: return ("ILLEGAL REQUEST");
815c1b3d7c5SThomas E. Spanjaard case 0x06: return ("UNIT ATTENTION");
816c1b3d7c5SThomas E. Spanjaard case 0x07: return ("DATA PROTECT");
817c1b3d7c5SThomas E. Spanjaard case 0x08: return ("BLANK CHECK");
818c1b3d7c5SThomas E. Spanjaard case 0x09: return ("VENDOR SPECIFIC");
819c1b3d7c5SThomas E. Spanjaard case 0x0a: return ("COPY ABORTED");
820c1b3d7c5SThomas E. Spanjaard case 0x0b: return ("ABORTED COMMAND");
821c1b3d7c5SThomas E. Spanjaard case 0x0c: return ("EQUAL");
822c1b3d7c5SThomas E. Spanjaard case 0x0d: return ("VOLUME OVERFLOW");
823c1b3d7c5SThomas E. Spanjaard case 0x0e: return ("MISCOMPARE");
824c1b3d7c5SThomas E. Spanjaard case 0x0f: return ("RESERVED");
825c1b3d7c5SThomas E. Spanjaard default: return("UNKNOWN");
826c1b3d7c5SThomas E. Spanjaard }
827c1b3d7c5SThomas E. Spanjaard }
828