scsipi_base.c revision 1.178.2.2 1 1.178.2.2 christos /* $NetBSD: scsipi_base.c,v 1.178.2.2 2017/07/14 17:50:12 christos Exp $ */
2 1.178.2.2 christos
3 1.178.2.2 christos /*-
4 1.178.2.2 christos * Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc.
5 1.178.2.2 christos * All rights reserved.
6 1.178.2.2 christos *
7 1.178.2.2 christos * This code is derived from software contributed to The NetBSD Foundation
8 1.178.2.2 christos * by Charles M. Hannum; by Jason R. Thorpe of the Numerical Aerospace
9 1.178.2.2 christos * Simulation Facility, NASA Ames Research Center.
10 1.178.2.2 christos *
11 1.178.2.2 christos * Redistribution and use in source and binary forms, with or without
12 1.178.2.2 christos * modification, are permitted provided that the following conditions
13 1.178.2.2 christos * are met:
14 1.178.2.2 christos * 1. Redistributions of source code must retain the above copyright
15 1.178.2.2 christos * notice, this list of conditions and the following disclaimer.
16 1.178.2.2 christos * 2. Redistributions in binary form must reproduce the above copyright
17 1.178.2.2 christos * notice, this list of conditions and the following disclaimer in the
18 1.178.2.2 christos * documentation and/or other materials provided with the distribution.
19 1.178.2.2 christos *
20 1.178.2.2 christos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 1.178.2.2 christos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 1.178.2.2 christos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 1.178.2.2 christos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 1.178.2.2 christos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 1.178.2.2 christos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 1.178.2.2 christos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 1.178.2.2 christos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 1.178.2.2 christos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 1.178.2.2 christos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 1.178.2.2 christos * POSSIBILITY OF SUCH DAMAGE.
31 1.178.2.2 christos */
32 1.178.2.2 christos
33 1.178.2.2 christos #include <sys/cdefs.h>
34 1.178.2.2 christos __KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.178.2.2 2017/07/14 17:50:12 christos Exp $");
35 1.178.2.2 christos
36 1.178.2.2 christos #ifdef _KERNEL_OPT
37 1.178.2.2 christos #include "opt_scsi.h"
38 1.178.2.2 christos #endif
39 1.178.2.2 christos
40 1.178.2.2 christos #include <sys/param.h>
41 1.178.2.2 christos #include <sys/systm.h>
42 1.178.2.2 christos #include <sys/kernel.h>
43 1.178.2.2 christos #include <sys/buf.h>
44 1.178.2.2 christos #include <sys/uio.h>
45 1.178.2.2 christos #include <sys/malloc.h>
46 1.178.2.2 christos #include <sys/pool.h>
47 1.178.2.2 christos #include <sys/errno.h>
48 1.178.2.2 christos #include <sys/device.h>
49 1.178.2.2 christos #include <sys/proc.h>
50 1.178.2.2 christos #include <sys/kthread.h>
51 1.178.2.2 christos #include <sys/hash.h>
52 1.178.2.2 christos #include <sys/atomic.h>
53 1.178.2.2 christos
54 1.178.2.2 christos #include <dev/scsipi/scsi_spc.h>
55 1.178.2.2 christos #include <dev/scsipi/scsipi_all.h>
56 1.178.2.2 christos #include <dev/scsipi/scsipi_disk.h>
57 1.178.2.2 christos #include <dev/scsipi/scsipiconf.h>
58 1.178.2.2 christos #include <dev/scsipi/scsipi_base.h>
59 1.178.2.2 christos
60 1.178.2.2 christos #include <dev/scsipi/scsi_all.h>
61 1.178.2.2 christos #include <dev/scsipi/scsi_message.h>
62 1.178.2.2 christos
63 1.178.2.2 christos #include <machine/param.h>
64 1.178.2.2 christos
65 1.178.2.2 christos static int scsipi_complete(struct scsipi_xfer *);
66 1.178.2.2 christos static void scsipi_request_sense(struct scsipi_xfer *);
67 1.178.2.2 christos static int scsipi_enqueue(struct scsipi_xfer *);
68 1.178.2.2 christos static void scsipi_run_queue(struct scsipi_channel *chan);
69 1.178.2.2 christos
70 1.178.2.2 christos static void scsipi_completion_thread(void *);
71 1.178.2.2 christos
72 1.178.2.2 christos static void scsipi_get_tag(struct scsipi_xfer *);
73 1.178.2.2 christos static void scsipi_put_tag(struct scsipi_xfer *);
74 1.178.2.2 christos
75 1.178.2.2 christos static int scsipi_get_resource(struct scsipi_channel *);
76 1.178.2.2 christos static void scsipi_put_resource(struct scsipi_channel *);
77 1.178.2.2 christos
78 1.178.2.2 christos static void scsipi_async_event_max_openings(struct scsipi_channel *,
79 1.178.2.2 christos struct scsipi_max_openings *);
80 1.178.2.2 christos static void scsipi_async_event_channel_reset(struct scsipi_channel *);
81 1.178.2.2 christos
82 1.178.2.2 christos static void scsipi_channel_freeze_locked(struct scsipi_channel *, int);
83 1.178.2.2 christos
84 1.178.2.2 christos static void scsipi_adapter_lock(struct scsipi_adapter *adapt);
85 1.178.2.2 christos static void scsipi_adapter_unlock(struct scsipi_adapter *adapt);
86 1.178.2.2 christos
87 1.178.2.2 christos static struct pool scsipi_xfer_pool;
88 1.178.2.2 christos
89 1.178.2.2 christos int scsipi_xs_count = 0;
90 1.178.2.2 christos
91 1.178.2.2 christos /*
92 1.178.2.2 christos * scsipi_init:
93 1.178.2.2 christos *
94 1.178.2.2 christos * Called when a scsibus or atapibus is attached to the system
95 1.178.2.2 christos * to initialize shared data structures.
96 1.178.2.2 christos */
97 1.178.2.2 christos void
98 1.178.2.2 christos scsipi_init(void)
99 1.178.2.2 christos {
100 1.178.2.2 christos static int scsipi_init_done;
101 1.178.2.2 christos
102 1.178.2.2 christos if (scsipi_init_done)
103 1.178.2.2 christos return;
104 1.178.2.2 christos scsipi_init_done = 1;
105 1.178.2.2 christos
106 1.178.2.2 christos /* Initialize the scsipi_xfer pool. */
107 1.178.2.2 christos pool_init(&scsipi_xfer_pool, sizeof(struct scsipi_xfer), 0,
108 1.178.2.2 christos 0, 0, "scxspl", NULL, IPL_BIO);
109 1.178.2.2 christos if (pool_prime(&scsipi_xfer_pool,
110 1.178.2.2 christos PAGE_SIZE / sizeof(struct scsipi_xfer)) == ENOMEM) {
111 1.178.2.2 christos printf("WARNING: not enough memory for scsipi_xfer_pool\n");
112 1.178.2.2 christos }
113 1.178.2.2 christos
114 1.178.2.2 christos scsipi_ioctl_init();
115 1.178.2.2 christos }
116 1.178.2.2 christos
117 1.178.2.2 christos /*
118 1.178.2.2 christos * scsipi_channel_init:
119 1.178.2.2 christos *
120 1.178.2.2 christos * Initialize a scsipi_channel when it is attached.
121 1.178.2.2 christos */
122 1.178.2.2 christos int
123 1.178.2.2 christos scsipi_channel_init(struct scsipi_channel *chan)
124 1.178.2.2 christos {
125 1.178.2.2 christos struct scsipi_adapter *adapt = chan->chan_adapter;
126 1.178.2.2 christos int i;
127 1.178.2.2 christos
128 1.178.2.2 christos /* Initialize shared data. */
129 1.178.2.2 christos scsipi_init();
130 1.178.2.2 christos
131 1.178.2.2 christos /* Initialize the queues. */
132 1.178.2.2 christos TAILQ_INIT(&chan->chan_queue);
133 1.178.2.2 christos TAILQ_INIT(&chan->chan_complete);
134 1.178.2.2 christos
135 1.178.2.2 christos for (i = 0; i < SCSIPI_CHAN_PERIPH_BUCKETS; i++)
136 1.178.2.2 christos LIST_INIT(&chan->chan_periphtab[i]);
137 1.178.2.2 christos
138 1.178.2.2 christos /*
139 1.178.2.2 christos * Create the asynchronous completion thread.
140 1.178.2.2 christos */
141 1.178.2.2 christos if (kthread_create(PRI_NONE, 0, NULL, scsipi_completion_thread, chan,
142 1.178.2.2 christos &chan->chan_thread, "%s", chan->chan_name)) {
143 1.178.2.2 christos aprint_error_dev(adapt->adapt_dev, "unable to create completion thread for "
144 1.178.2.2 christos "channel %d\n", chan->chan_channel);
145 1.178.2.2 christos panic("scsipi_channel_init");
146 1.178.2.2 christos }
147 1.178.2.2 christos
148 1.178.2.2 christos return 0;
149 1.178.2.2 christos }
150 1.178.2.2 christos
151 1.178.2.2 christos /*
152 1.178.2.2 christos * scsipi_channel_shutdown:
153 1.178.2.2 christos *
154 1.178.2.2 christos * Shutdown a scsipi_channel.
155 1.178.2.2 christos */
156 1.178.2.2 christos void
157 1.178.2.2 christos scsipi_channel_shutdown(struct scsipi_channel *chan)
158 1.178.2.2 christos {
159 1.178.2.2 christos
160 1.178.2.2 christos mutex_enter(chan_mtx(chan));
161 1.178.2.2 christos /*
162 1.178.2.2 christos * Shut down the completion thread.
163 1.178.2.2 christos */
164 1.178.2.2 christos chan->chan_tflags |= SCSIPI_CHANT_SHUTDOWN;
165 1.178.2.2 christos cv_broadcast(chan_cv_complete(chan));
166 1.178.2.2 christos
167 1.178.2.2 christos /*
168 1.178.2.2 christos * Now wait for the thread to exit.
169 1.178.2.2 christos */
170 1.178.2.2 christos while (chan->chan_thread != NULL)
171 1.178.2.2 christos cv_wait(chan_cv_thread(chan), chan_mtx(chan));
172 1.178.2.2 christos mutex_exit(chan_mtx(chan));
173 1.178.2.2 christos }
174 1.178.2.2 christos
175 1.178.2.2 christos static uint32_t
176 1.178.2.2 christos scsipi_chan_periph_hash(uint64_t t, uint64_t l)
177 1.178.2.2 christos {
178 1.178.2.2 christos uint32_t hash;
179 1.178.2.2 christos
180 1.178.2.2 christos hash = hash32_buf(&t, sizeof(t), HASH32_BUF_INIT);
181 1.178.2.2 christos hash = hash32_buf(&l, sizeof(l), hash);
182 1.178.2.2 christos
183 1.178.2.2 christos return hash & SCSIPI_CHAN_PERIPH_HASHMASK;
184 1.178.2.2 christos }
185 1.178.2.2 christos
186 1.178.2.2 christos /*
187 1.178.2.2 christos * scsipi_insert_periph:
188 1.178.2.2 christos *
189 1.178.2.2 christos * Insert a periph into the channel.
190 1.178.2.2 christos */
191 1.178.2.2 christos void
192 1.178.2.2 christos scsipi_insert_periph(struct scsipi_channel *chan, struct scsipi_periph *periph)
193 1.178.2.2 christos {
194 1.178.2.2 christos uint32_t hash;
195 1.178.2.2 christos
196 1.178.2.2 christos hash = scsipi_chan_periph_hash(periph->periph_target,
197 1.178.2.2 christos periph->periph_lun);
198 1.178.2.2 christos
199 1.178.2.2 christos mutex_enter(chan_mtx(chan));
200 1.178.2.2 christos LIST_INSERT_HEAD(&chan->chan_periphtab[hash], periph, periph_hash);
201 1.178.2.2 christos mutex_exit(chan_mtx(chan));
202 1.178.2.2 christos }
203 1.178.2.2 christos
204 1.178.2.2 christos /*
205 1.178.2.2 christos * scsipi_remove_periph:
206 1.178.2.2 christos *
207 1.178.2.2 christos * Remove a periph from the channel.
208 1.178.2.2 christos */
209 1.178.2.2 christos void
210 1.178.2.2 christos scsipi_remove_periph(struct scsipi_channel *chan,
211 1.178.2.2 christos struct scsipi_periph *periph)
212 1.178.2.2 christos {
213 1.178.2.2 christos
214 1.178.2.2 christos LIST_REMOVE(periph, periph_hash);
215 1.178.2.2 christos }
216 1.178.2.2 christos
217 1.178.2.2 christos /*
218 1.178.2.2 christos * scsipi_lookup_periph:
219 1.178.2.2 christos *
220 1.178.2.2 christos * Lookup a periph on the specified channel.
221 1.178.2.2 christos */
222 1.178.2.2 christos static struct scsipi_periph *
223 1.178.2.2 christos scsipi_lookup_periph_internal(struct scsipi_channel *chan, int target, int lun, bool lock)
224 1.178.2.2 christos {
225 1.178.2.2 christos struct scsipi_periph *periph;
226 1.178.2.2 christos uint32_t hash;
227 1.178.2.2 christos
228 1.178.2.2 christos if (target >= chan->chan_ntargets ||
229 1.178.2.2 christos lun >= chan->chan_nluns)
230 1.178.2.2 christos return NULL;
231 1.178.2.2 christos
232 1.178.2.2 christos hash = scsipi_chan_periph_hash(target, lun);
233 1.178.2.2 christos
234 1.178.2.2 christos if (lock)
235 1.178.2.2 christos mutex_enter(chan_mtx(chan));
236 1.178.2.2 christos LIST_FOREACH(periph, &chan->chan_periphtab[hash], periph_hash) {
237 1.178.2.2 christos if (periph->periph_target == target &&
238 1.178.2.2 christos periph->periph_lun == lun)
239 1.178.2.2 christos break;
240 1.178.2.2 christos }
241 1.178.2.2 christos if (lock)
242 1.178.2.2 christos mutex_exit(chan_mtx(chan));
243 1.178.2.2 christos
244 1.178.2.2 christos return periph;
245 1.178.2.2 christos }
246 1.178.2.2 christos
247 1.178.2.2 christos struct scsipi_periph *
248 1.178.2.2 christos scsipi_lookup_periph_locked(struct scsipi_channel *chan, int target, int lun)
249 1.178.2.2 christos {
250 1.178.2.2 christos return scsipi_lookup_periph_internal(chan, target, lun, false);
251 1.178.2.2 christos }
252 1.178.2.2 christos
253 1.178.2.2 christos struct scsipi_periph *
254 1.178.2.2 christos scsipi_lookup_periph(struct scsipi_channel *chan, int target, int lun)
255 1.178.2.2 christos {
256 1.178.2.2 christos return scsipi_lookup_periph_internal(chan, target, lun, true);
257 1.178.2.2 christos }
258 1.178.2.2 christos
259 1.178.2.2 christos /*
260 1.178.2.2 christos * scsipi_get_resource:
261 1.178.2.2 christos *
262 1.178.2.2 christos * Allocate a single xfer `resource' from the channel.
263 1.178.2.2 christos *
264 1.178.2.2 christos * NOTE: Must be called with channel lock held
265 1.178.2.2 christos */
266 1.178.2.2 christos static int
267 1.178.2.2 christos scsipi_get_resource(struct scsipi_channel *chan)
268 1.178.2.2 christos {
269 1.178.2.2 christos struct scsipi_adapter *adapt = chan->chan_adapter;
270 1.178.2.2 christos
271 1.178.2.2 christos if (chan->chan_flags & SCSIPI_CHAN_OPENINGS) {
272 1.178.2.2 christos if (chan->chan_openings > 0) {
273 1.178.2.2 christos chan->chan_openings--;
274 1.178.2.2 christos return 1;
275 1.178.2.2 christos }
276 1.178.2.2 christos return 0;
277 1.178.2.2 christos }
278 1.178.2.2 christos
279 1.178.2.2 christos if (adapt->adapt_openings > 0) {
280 1.178.2.2 christos adapt->adapt_openings--;
281 1.178.2.2 christos return 1;
282 1.178.2.2 christos }
283 1.178.2.2 christos return 0;
284 1.178.2.2 christos }
285 1.178.2.2 christos
286 1.178.2.2 christos /*
287 1.178.2.2 christos * scsipi_grow_resources:
288 1.178.2.2 christos *
289 1.178.2.2 christos * Attempt to grow resources for a channel. If this succeeds,
290 1.178.2.2 christos * we allocate one for our caller.
291 1.178.2.2 christos *
292 1.178.2.2 christos * NOTE: Must be called with channel lock held
293 1.178.2.2 christos */
294 1.178.2.2 christos static inline int
295 1.178.2.2 christos scsipi_grow_resources(struct scsipi_channel *chan)
296 1.178.2.2 christos {
297 1.178.2.2 christos
298 1.178.2.2 christos if (chan->chan_flags & SCSIPI_CHAN_CANGROW) {
299 1.178.2.2 christos if ((chan->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
300 1.178.2.2 christos mutex_exit(chan_mtx(chan));
301 1.178.2.2 christos scsipi_adapter_request(chan,
302 1.178.2.2 christos ADAPTER_REQ_GROW_RESOURCES, NULL);
303 1.178.2.2 christos mutex_enter(chan_mtx(chan));
304 1.178.2.2 christos return scsipi_get_resource(chan);
305 1.178.2.2 christos }
306 1.178.2.2 christos /*
307 1.178.2.2 christos * ask the channel thread to do it. It'll have to thaw the
308 1.178.2.2 christos * queue
309 1.178.2.2 christos */
310 1.178.2.2 christos scsipi_channel_freeze_locked(chan, 1);
311 1.178.2.2 christos chan->chan_tflags |= SCSIPI_CHANT_GROWRES;
312 1.178.2.2 christos cv_broadcast(chan_cv_complete(chan));
313 1.178.2.2 christos return 0;
314 1.178.2.2 christos }
315 1.178.2.2 christos
316 1.178.2.2 christos return 0;
317 1.178.2.2 christos }
318 1.178.2.2 christos
319 1.178.2.2 christos /*
320 1.178.2.2 christos * scsipi_put_resource:
321 1.178.2.2 christos *
322 1.178.2.2 christos * Free a single xfer `resource' to the channel.
323 1.178.2.2 christos *
324 1.178.2.2 christos * NOTE: Must be called with channel lock held
325 1.178.2.2 christos */
326 1.178.2.2 christos static void
327 1.178.2.2 christos scsipi_put_resource(struct scsipi_channel *chan)
328 1.178.2.2 christos {
329 1.178.2.2 christos struct scsipi_adapter *adapt = chan->chan_adapter;
330 1.178.2.2 christos
331 1.178.2.2 christos if (chan->chan_flags & SCSIPI_CHAN_OPENINGS)
332 1.178.2.2 christos chan->chan_openings++;
333 1.178.2.2 christos else
334 1.178.2.2 christos adapt->adapt_openings++;
335 1.178.2.2 christos }
336 1.178.2.2 christos
337 1.178.2.2 christos /*
338 1.178.2.2 christos * scsipi_get_tag:
339 1.178.2.2 christos *
340 1.178.2.2 christos * Get a tag ID for the specified xfer.
341 1.178.2.2 christos *
342 1.178.2.2 christos * NOTE: Must be called with channel lock held
343 1.178.2.2 christos */
344 1.178.2.2 christos static void
345 1.178.2.2 christos scsipi_get_tag(struct scsipi_xfer *xs)
346 1.178.2.2 christos {
347 1.178.2.2 christos struct scsipi_periph *periph = xs->xs_periph;
348 1.178.2.2 christos int bit, tag;
349 1.178.2.2 christos u_int word;
350 1.178.2.2 christos
351 1.178.2.2 christos bit = 0; /* XXX gcc */
352 1.178.2.2 christos for (word = 0; word < PERIPH_NTAGWORDS; word++) {
353 1.178.2.2 christos bit = ffs(periph->periph_freetags[word]);
354 1.178.2.2 christos if (bit != 0)
355 1.178.2.2 christos break;
356 1.178.2.2 christos }
357 1.178.2.2 christos #ifdef DIAGNOSTIC
358 1.178.2.2 christos if (word == PERIPH_NTAGWORDS) {
359 1.178.2.2 christos scsipi_printaddr(periph);
360 1.178.2.2 christos printf("no free tags\n");
361 1.178.2.2 christos panic("scsipi_get_tag");
362 1.178.2.2 christos }
363 1.178.2.2 christos #endif
364 1.178.2.2 christos
365 1.178.2.2 christos bit -= 1;
366 1.178.2.2 christos periph->periph_freetags[word] &= ~(1 << bit);
367 1.178.2.2 christos tag = (word << 5) | bit;
368 1.178.2.2 christos
369 1.178.2.2 christos /* XXX Should eventually disallow this completely. */
370 1.178.2.2 christos if (tag >= periph->periph_openings) {
371 1.178.2.2 christos scsipi_printaddr(periph);
372 1.178.2.2 christos printf("WARNING: tag %d greater than available openings %d\n",
373 1.178.2.2 christos tag, periph->periph_openings);
374 1.178.2.2 christos }
375 1.178.2.2 christos
376 1.178.2.2 christos xs->xs_tag_id = tag;
377 1.178.2.2 christos }
378 1.178.2.2 christos
379 1.178.2.2 christos /*
380 1.178.2.2 christos * scsipi_put_tag:
381 1.178.2.2 christos *
382 1.178.2.2 christos * Put the tag ID for the specified xfer back into the pool.
383 1.178.2.2 christos *
384 1.178.2.2 christos * NOTE: Must be called with channel lock held
385 1.178.2.2 christos */
386 1.178.2.2 christos static void
387 1.178.2.2 christos scsipi_put_tag(struct scsipi_xfer *xs)
388 1.178.2.2 christos {
389 1.178.2.2 christos struct scsipi_periph *periph = xs->xs_periph;
390 1.178.2.2 christos int word, bit;
391 1.178.2.2 christos
392 1.178.2.2 christos word = xs->xs_tag_id >> 5;
393 1.178.2.2 christos bit = xs->xs_tag_id & 0x1f;
394 1.178.2.2 christos
395 1.178.2.2 christos periph->periph_freetags[word] |= (1 << bit);
396 1.178.2.2 christos }
397 1.178.2.2 christos
398 1.178.2.2 christos /*
399 1.178.2.2 christos * scsipi_get_xs:
400 1.178.2.2 christos *
401 1.178.2.2 christos * Allocate an xfer descriptor and associate it with the
402 1.178.2.2 christos * specified peripheral. If the peripheral has no more
403 1.178.2.2 christos * available command openings, we either block waiting for
404 1.178.2.2 christos * one to become available, or fail.
405 1.178.2.2 christos *
406 1.178.2.2 christos * When this routine is called with the channel lock held
407 1.178.2.2 christos * the flags must include XS_CTL_NOSLEEP.
408 1.178.2.2 christos */
409 1.178.2.2 christos struct scsipi_xfer *
410 1.178.2.2 christos scsipi_get_xs(struct scsipi_periph *periph, int flags)
411 1.178.2.2 christos {
412 1.178.2.2 christos struct scsipi_xfer *xs;
413 1.178.2.2 christos bool lock = (flags & XS_CTL_NOSLEEP) == 0;
414 1.178.2.2 christos
415 1.178.2.2 christos SC_DEBUG(periph, SCSIPI_DB3, ("scsipi_get_xs\n"));
416 1.178.2.2 christos
417 1.178.2.2 christos KASSERT(!cold);
418 1.178.2.2 christos
419 1.178.2.2 christos #ifdef DIAGNOSTIC
420 1.178.2.2 christos /*
421 1.178.2.2 christos * URGENT commands can never be ASYNC.
422 1.178.2.2 christos */
423 1.178.2.2 christos if ((flags & (XS_CTL_URGENT|XS_CTL_ASYNC)) ==
424 1.178.2.2 christos (XS_CTL_URGENT|XS_CTL_ASYNC)) {
425 1.178.2.2 christos scsipi_printaddr(periph);
426 1.178.2.2 christos printf("URGENT and ASYNC\n");
427 1.178.2.2 christos panic("scsipi_get_xs");
428 1.178.2.2 christos }
429 1.178.2.2 christos #endif
430 1.178.2.2 christos
431 1.178.2.2 christos /*
432 1.178.2.2 christos * Wait for a command opening to become available. Rules:
433 1.178.2.2 christos *
434 1.178.2.2 christos * - All xfers must wait for an available opening.
435 1.178.2.2 christos * Exception: URGENT xfers can proceed when
436 1.178.2.2 christos * active == openings, because we use the opening
437 1.178.2.2 christos * of the command we're recovering for.
438 1.178.2.2 christos * - if the periph has sense pending, only URGENT & REQSENSE
439 1.178.2.2 christos * xfers may proceed.
440 1.178.2.2 christos *
441 1.178.2.2 christos * - If the periph is recovering, only URGENT xfers may
442 1.178.2.2 christos * proceed.
443 1.178.2.2 christos *
444 1.178.2.2 christos * - If the periph is currently executing a recovery
445 1.178.2.2 christos * command, URGENT commands must block, because only
446 1.178.2.2 christos * one recovery command can execute at a time.
447 1.178.2.2 christos */
448 1.178.2.2 christos if (lock)
449 1.178.2.2 christos mutex_enter(chan_mtx(periph->periph_channel));
450 1.178.2.2 christos for (;;) {
451 1.178.2.2 christos if (flags & XS_CTL_URGENT) {
452 1.178.2.2 christos if (periph->periph_active > periph->periph_openings)
453 1.178.2.2 christos goto wait_for_opening;
454 1.178.2.2 christos if (periph->periph_flags & PERIPH_SENSE) {
455 1.178.2.2 christos if ((flags & XS_CTL_REQSENSE) == 0)
456 1.178.2.2 christos goto wait_for_opening;
457 1.178.2.2 christos } else {
458 1.178.2.2 christos if ((periph->periph_flags &
459 1.178.2.2 christos PERIPH_RECOVERY_ACTIVE) != 0)
460 1.178.2.2 christos goto wait_for_opening;
461 1.178.2.2 christos periph->periph_flags |= PERIPH_RECOVERY_ACTIVE;
462 1.178.2.2 christos }
463 1.178.2.2 christos break;
464 1.178.2.2 christos }
465 1.178.2.2 christos if (periph->periph_active >= periph->periph_openings ||
466 1.178.2.2 christos (periph->periph_flags & PERIPH_RECOVERING) != 0)
467 1.178.2.2 christos goto wait_for_opening;
468 1.178.2.2 christos periph->periph_active++;
469 1.178.2.2 christos break;
470 1.178.2.2 christos
471 1.178.2.2 christos wait_for_opening:
472 1.178.2.2 christos if (flags & XS_CTL_NOSLEEP) {
473 1.178.2.2 christos KASSERT(!lock);
474 1.178.2.2 christos return NULL;
475 1.178.2.2 christos }
476 1.178.2.2 christos KASSERT(lock);
477 1.178.2.2 christos SC_DEBUG(periph, SCSIPI_DB3, ("sleeping\n"));
478 1.178.2.2 christos periph->periph_flags |= PERIPH_WAITING;
479 1.178.2.2 christos cv_wait(periph_cv_periph(periph),
480 1.178.2.2 christos chan_mtx(periph->periph_channel));
481 1.178.2.2 christos }
482 1.178.2.2 christos if (lock)
483 1.178.2.2 christos mutex_exit(chan_mtx(periph->periph_channel));
484 1.178.2.2 christos
485 1.178.2.2 christos SC_DEBUG(periph, SCSIPI_DB3, ("calling pool_get\n"));
486 1.178.2.2 christos xs = pool_get(&scsipi_xfer_pool,
487 1.178.2.2 christos ((flags & XS_CTL_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK));
488 1.178.2.2 christos if (xs == NULL) {
489 1.178.2.2 christos if (lock)
490 1.178.2.2 christos mutex_enter(chan_mtx(periph->periph_channel));
491 1.178.2.2 christos if (flags & XS_CTL_URGENT) {
492 1.178.2.2 christos if ((flags & XS_CTL_REQSENSE) == 0)
493 1.178.2.2 christos periph->periph_flags &= ~PERIPH_RECOVERY_ACTIVE;
494 1.178.2.2 christos } else
495 1.178.2.2 christos periph->periph_active--;
496 1.178.2.2 christos if (lock)
497 1.178.2.2 christos mutex_exit(chan_mtx(periph->periph_channel));
498 1.178.2.2 christos scsipi_printaddr(periph);
499 1.178.2.2 christos printf("unable to allocate %sscsipi_xfer\n",
500 1.178.2.2 christos (flags & XS_CTL_URGENT) ? "URGENT " : "");
501 1.178.2.2 christos }
502 1.178.2.2 christos
503 1.178.2.2 christos SC_DEBUG(periph, SCSIPI_DB3, ("returning\n"));
504 1.178.2.2 christos
505 1.178.2.2 christos if (xs != NULL) {
506 1.178.2.2 christos memset(xs, 0, sizeof(*xs));
507 1.178.2.2 christos callout_init(&xs->xs_callout, 0);
508 1.178.2.2 christos xs->xs_periph = periph;
509 1.178.2.2 christos xs->xs_control = flags;
510 1.178.2.2 christos xs->xs_status = 0;
511 1.178.2.2 christos if ((flags & XS_CTL_NOSLEEP) == 0)
512 1.178.2.2 christos mutex_enter(chan_mtx(periph->periph_channel));
513 1.178.2.2 christos TAILQ_INSERT_TAIL(&periph->periph_xferq, xs, device_q);
514 1.178.2.2 christos if ((flags & XS_CTL_NOSLEEP) == 0)
515 1.178.2.2 christos mutex_exit(chan_mtx(periph->periph_channel));
516 1.178.2.2 christos }
517 1.178.2.2 christos return xs;
518 1.178.2.2 christos }
519 1.178.2.2 christos
520 1.178.2.2 christos /*
521 1.178.2.2 christos * scsipi_put_xs:
522 1.178.2.2 christos *
523 1.178.2.2 christos * Release an xfer descriptor, decreasing the outstanding command
524 1.178.2.2 christos * count for the peripheral. If there is a thread waiting for
525 1.178.2.2 christos * an opening, wake it up. If not, kick any queued I/O the
526 1.178.2.2 christos * peripheral may have.
527 1.178.2.2 christos *
528 1.178.2.2 christos * NOTE: Must be called with channel lock held
529 1.178.2.2 christos */
530 1.178.2.2 christos void
531 1.178.2.2 christos scsipi_put_xs(struct scsipi_xfer *xs)
532 1.178.2.2 christos {
533 1.178.2.2 christos struct scsipi_periph *periph = xs->xs_periph;
534 1.178.2.2 christos int flags = xs->xs_control;
535 1.178.2.2 christos
536 1.178.2.2 christos SC_DEBUG(periph, SCSIPI_DB3, ("scsipi_free_xs\n"));
537 1.178.2.2 christos
538 1.178.2.2 christos TAILQ_REMOVE(&periph->periph_xferq, xs, device_q);
539 1.178.2.2 christos callout_destroy(&xs->xs_callout);
540 1.178.2.2 christos pool_put(&scsipi_xfer_pool, xs);
541 1.178.2.2 christos
542 1.178.2.2 christos #ifdef DIAGNOSTIC
543 1.178.2.2 christos if ((periph->periph_flags & PERIPH_RECOVERY_ACTIVE) != 0 &&
544 1.178.2.2 christos periph->periph_active == 0) {
545 1.178.2.2 christos scsipi_printaddr(periph);
546 1.178.2.2 christos printf("recovery without a command to recovery for\n");
547 1.178.2.2 christos panic("scsipi_put_xs");
548 1.178.2.2 christos }
549 1.178.2.2 christos #endif
550 1.178.2.2 christos
551 1.178.2.2 christos if (flags & XS_CTL_URGENT) {
552 1.178.2.2 christos if ((flags & XS_CTL_REQSENSE) == 0)
553 1.178.2.2 christos periph->periph_flags &= ~PERIPH_RECOVERY_ACTIVE;
554 1.178.2.2 christos } else
555 1.178.2.2 christos periph->periph_active--;
556 1.178.2.2 christos if (periph->periph_active == 0 &&
557 1.178.2.2 christos (periph->periph_flags & PERIPH_WAITDRAIN) != 0) {
558 1.178.2.2 christos periph->periph_flags &= ~PERIPH_WAITDRAIN;
559 1.178.2.2 christos cv_broadcast(periph_cv_active(periph));
560 1.178.2.2 christos }
561 1.178.2.2 christos
562 1.178.2.2 christos if (periph->periph_flags & PERIPH_WAITING) {
563 1.178.2.2 christos periph->periph_flags &= ~PERIPH_WAITING;
564 1.178.2.2 christos cv_broadcast(periph_cv_periph(periph));
565 1.178.2.2 christos } else {
566 1.178.2.2 christos if (periph->periph_switch->psw_start != NULL &&
567 1.178.2.2 christos device_is_active(periph->periph_dev)) {
568 1.178.2.2 christos SC_DEBUG(periph, SCSIPI_DB2,
569 1.178.2.2 christos ("calling private start()\n"));
570 1.178.2.2 christos (*periph->periph_switch->psw_start)(periph);
571 1.178.2.2 christos }
572 1.178.2.2 christos }
573 1.178.2.2 christos }
574 1.178.2.2 christos
575 1.178.2.2 christos /*
576 1.178.2.2 christos * scsipi_channel_freeze:
577 1.178.2.2 christos *
578 1.178.2.2 christos * Freeze a channel's xfer queue.
579 1.178.2.2 christos */
580 1.178.2.2 christos void
581 1.178.2.2 christos scsipi_channel_freeze(struct scsipi_channel *chan, int count)
582 1.178.2.2 christos {
583 1.178.2.2 christos bool lock = chan_running(chan) > 0;
584 1.178.2.2 christos
585 1.178.2.2 christos if (lock)
586 1.178.2.2 christos mutex_enter(chan_mtx(chan));
587 1.178.2.2 christos chan->chan_qfreeze += count;
588 1.178.2.2 christos if (lock)
589 1.178.2.2 christos mutex_exit(chan_mtx(chan));
590 1.178.2.2 christos }
591 1.178.2.2 christos
592 1.178.2.2 christos static void
593 1.178.2.2 christos scsipi_channel_freeze_locked(struct scsipi_channel *chan, int count)
594 1.178.2.2 christos {
595 1.178.2.2 christos
596 1.178.2.2 christos chan->chan_qfreeze += count;
597 1.178.2.2 christos }
598 1.178.2.2 christos
599 1.178.2.2 christos /*
600 1.178.2.2 christos * scsipi_channel_thaw:
601 1.178.2.2 christos *
602 1.178.2.2 christos * Thaw a channel's xfer queue.
603 1.178.2.2 christos */
604 1.178.2.2 christos void
605 1.178.2.2 christos scsipi_channel_thaw(struct scsipi_channel *chan, int count)
606 1.178.2.2 christos {
607 1.178.2.2 christos bool lock = chan_running(chan) > 0;
608 1.178.2.2 christos
609 1.178.2.2 christos if (lock)
610 1.178.2.2 christos mutex_enter(chan_mtx(chan));
611 1.178.2.2 christos chan->chan_qfreeze -= count;
612 1.178.2.2 christos /*
613 1.178.2.2 christos * Don't let the freeze count go negative.
614 1.178.2.2 christos *
615 1.178.2.2 christos * Presumably the adapter driver could keep track of this,
616 1.178.2.2 christos * but it might just be easier to do this here so as to allow
617 1.178.2.2 christos * multiple callers, including those outside the adapter driver.
618 1.178.2.2 christos */
619 1.178.2.2 christos if (chan->chan_qfreeze < 0) {
620 1.178.2.2 christos chan->chan_qfreeze = 0;
621 1.178.2.2 christos }
622 1.178.2.2 christos if (lock)
623 1.178.2.2 christos mutex_exit(chan_mtx(chan));
624 1.178.2.2 christos
625 1.178.2.2 christos /*
626 1.178.2.2 christos * until the channel is running
627 1.178.2.2 christos */
628 1.178.2.2 christos if (!lock)
629 1.178.2.2 christos return;
630 1.178.2.2 christos
631 1.178.2.2 christos /*
632 1.178.2.2 christos * Kick the channel's queue here. Note, we may be running in
633 1.178.2.2 christos * interrupt context (softclock or HBA's interrupt), so the adapter
634 1.178.2.2 christos * driver had better not sleep.
635 1.178.2.2 christos */
636 1.178.2.2 christos if (chan->chan_qfreeze == 0)
637 1.178.2.2 christos scsipi_run_queue(chan);
638 1.178.2.2 christos }
639 1.178.2.2 christos
640 1.178.2.2 christos /*
641 1.178.2.2 christos * scsipi_channel_timed_thaw:
642 1.178.2.2 christos *
643 1.178.2.2 christos * Thaw a channel after some time has expired. This will also
644 1.178.2.2 christos * run the channel's queue if the freeze count has reached 0.
645 1.178.2.2 christos */
646 1.178.2.2 christos void
647 1.178.2.2 christos scsipi_channel_timed_thaw(void *arg)
648 1.178.2.2 christos {
649 1.178.2.2 christos struct scsipi_channel *chan = arg;
650 1.178.2.2 christos
651 1.178.2.2 christos scsipi_channel_thaw(chan, 1);
652 1.178.2.2 christos }
653 1.178.2.2 christos
654 1.178.2.2 christos /*
655 1.178.2.2 christos * scsipi_periph_freeze:
656 1.178.2.2 christos *
657 1.178.2.2 christos * Freeze a device's xfer queue.
658 1.178.2.2 christos */
659 1.178.2.2 christos void
660 1.178.2.2 christos scsipi_periph_freeze_locked(struct scsipi_periph *periph, int count)
661 1.178.2.2 christos {
662 1.178.2.2 christos
663 1.178.2.2 christos periph->periph_qfreeze += count;
664 1.178.2.2 christos }
665 1.178.2.2 christos
666 1.178.2.2 christos /*
667 1.178.2.2 christos * scsipi_periph_thaw:
668 1.178.2.2 christos *
669 1.178.2.2 christos * Thaw a device's xfer queue.
670 1.178.2.2 christos */
671 1.178.2.2 christos void
672 1.178.2.2 christos scsipi_periph_thaw_locked(struct scsipi_periph *periph, int count)
673 1.178.2.2 christos {
674 1.178.2.2 christos
675 1.178.2.2 christos periph->periph_qfreeze -= count;
676 1.178.2.2 christos #ifdef DIAGNOSTIC
677 1.178.2.2 christos if (periph->periph_qfreeze < 0) {
678 1.178.2.2 christos static const char pc[] = "periph freeze count < 0";
679 1.178.2.2 christos scsipi_printaddr(periph);
680 1.178.2.2 christos printf("%s\n", pc);
681 1.178.2.2 christos panic(pc);
682 1.178.2.2 christos }
683 1.178.2.2 christos #endif
684 1.178.2.2 christos if (periph->periph_qfreeze == 0 &&
685 1.178.2.2 christos (periph->periph_flags & PERIPH_WAITING) != 0)
686 1.178.2.2 christos cv_broadcast(periph_cv_periph(periph));
687 1.178.2.2 christos }
688 1.178.2.2 christos
689 1.178.2.2 christos void
690 1.178.2.2 christos scsipi_periph_freeze(struct scsipi_periph *periph, int count)
691 1.178.2.2 christos {
692 1.178.2.2 christos
693 1.178.2.2 christos mutex_enter(chan_mtx(periph->periph_channel));
694 1.178.2.2 christos scsipi_periph_freeze_locked(periph, count);
695 1.178.2.2 christos mutex_exit(chan_mtx(periph->periph_channel));
696 1.178.2.2 christos }
697 1.178.2.2 christos
698 1.178.2.2 christos void
699 1.178.2.2 christos scsipi_periph_thaw(struct scsipi_periph *periph, int count)
700 1.178.2.2 christos {
701 1.178.2.2 christos
702 1.178.2.2 christos mutex_enter(chan_mtx(periph->periph_channel));
703 1.178.2.2 christos scsipi_periph_thaw_locked(periph, count);
704 1.178.2.2 christos mutex_exit(chan_mtx(periph->periph_channel));
705 1.178.2.2 christos }
706 1.178.2.2 christos
707 1.178.2.2 christos /*
708 1.178.2.2 christos * scsipi_periph_timed_thaw:
709 1.178.2.2 christos *
710 1.178.2.2 christos * Thaw a device after some time has expired.
711 1.178.2.2 christos */
712 1.178.2.2 christos void
713 1.178.2.2 christos scsipi_periph_timed_thaw(void *arg)
714 1.178.2.2 christos {
715 1.178.2.2 christos struct scsipi_periph *periph = arg;
716 1.178.2.2 christos struct scsipi_channel *chan = periph->periph_channel;
717 1.178.2.2 christos
718 1.178.2.2 christos callout_stop(&periph->periph_callout);
719 1.178.2.2 christos
720 1.178.2.2 christos mutex_enter(chan_mtx(chan));
721 1.178.2.2 christos scsipi_periph_thaw_locked(periph, 1);
722 1.178.2.2 christos if ((periph->periph_channel->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
723 1.178.2.2 christos /*
724 1.178.2.2 christos * Kick the channel's queue here. Note, we're running in
725 1.178.2.2 christos * interrupt context (softclock), so the adapter driver
726 1.178.2.2 christos * had better not sleep.
727 1.178.2.2 christos */
728 1.178.2.2 christos mutex_exit(chan_mtx(chan));
729 1.178.2.2 christos scsipi_run_queue(periph->periph_channel);
730 1.178.2.2 christos } else {
731 1.178.2.2 christos /*
732 1.178.2.2 christos * Tell the completion thread to kick the channel's queue here.
733 1.178.2.2 christos */
734 1.178.2.2 christos periph->periph_channel->chan_tflags |= SCSIPI_CHANT_KICK;
735 1.178.2.2 christos cv_broadcast(chan_cv_complete(chan));
736 1.178.2.2 christos mutex_exit(chan_mtx(chan));
737 1.178.2.2 christos }
738 1.178.2.2 christos }
739 1.178.2.2 christos
740 1.178.2.2 christos /*
741 1.178.2.2 christos * scsipi_wait_drain:
742 1.178.2.2 christos *
743 1.178.2.2 christos * Wait for a periph's pending xfers to drain.
744 1.178.2.2 christos */
745 1.178.2.2 christos void
746 1.178.2.2 christos scsipi_wait_drain(struct scsipi_periph *periph)
747 1.178.2.2 christos {
748 1.178.2.2 christos struct scsipi_channel *chan = periph->periph_channel;
749 1.178.2.2 christos
750 1.178.2.2 christos mutex_enter(chan_mtx(chan));
751 1.178.2.2 christos while (periph->periph_active != 0) {
752 1.178.2.2 christos periph->periph_flags |= PERIPH_WAITDRAIN;
753 1.178.2.2 christos cv_wait(periph_cv_active(periph), chan_mtx(chan));
754 1.178.2.2 christos }
755 1.178.2.2 christos mutex_exit(chan_mtx(chan));
756 1.178.2.2 christos }
757 1.178.2.2 christos
758 1.178.2.2 christos /*
759 1.178.2.2 christos * scsipi_kill_pending:
760 1.178.2.2 christos *
761 1.178.2.2 christos * Kill off all pending xfers for a periph.
762 1.178.2.2 christos *
763 1.178.2.2 christos * NOTE: Must be called with channel lock held
764 1.178.2.2 christos */
765 1.178.2.2 christos void
766 1.178.2.2 christos scsipi_kill_pending(struct scsipi_periph *periph)
767 1.178.2.2 christos {
768 1.178.2.2 christos struct scsipi_channel *chan = periph->periph_channel;
769 1.178.2.2 christos
770 1.178.2.2 christos (*chan->chan_bustype->bustype_kill_pending)(periph);
771 1.178.2.2 christos while (periph->periph_active != 0) {
772 1.178.2.2 christos periph->periph_flags |= PERIPH_WAITDRAIN;
773 1.178.2.2 christos cv_wait(periph_cv_active(periph), chan_mtx(chan));
774 1.178.2.2 christos }
775 1.178.2.2 christos }
776 1.178.2.2 christos
777 1.178.2.2 christos /*
778 1.178.2.2 christos * scsipi_print_cdb:
779 1.178.2.2 christos * prints a command descriptor block (for debug purpose, error messages,
780 1.178.2.2 christos * SCSIVERBOSE, ...)
781 1.178.2.2 christos */
782 1.178.2.2 christos void
783 1.178.2.2 christos scsipi_print_cdb(struct scsipi_generic *cmd)
784 1.178.2.2 christos {
785 1.178.2.2 christos int i, j;
786 1.178.2.2 christos
787 1.178.2.2 christos printf("0x%02x", cmd->opcode);
788 1.178.2.2 christos
789 1.178.2.2 christos switch (CDB_GROUPID(cmd->opcode)) {
790 1.178.2.2 christos case CDB_GROUPID_0:
791 1.178.2.2 christos j = CDB_GROUP0;
792 1.178.2.2 christos break;
793 1.178.2.2 christos case CDB_GROUPID_1:
794 1.178.2.2 christos j = CDB_GROUP1;
795 1.178.2.2 christos break;
796 1.178.2.2 christos case CDB_GROUPID_2:
797 1.178.2.2 christos j = CDB_GROUP2;
798 1.178.2.2 christos break;
799 1.178.2.2 christos case CDB_GROUPID_3:
800 1.178.2.2 christos j = CDB_GROUP3;
801 1.178.2.2 christos break;
802 1.178.2.2 christos case CDB_GROUPID_4:
803 1.178.2.2 christos j = CDB_GROUP4;
804 1.178.2.2 christos break;
805 1.178.2.2 christos case CDB_GROUPID_5:
806 1.178.2.2 christos j = CDB_GROUP5;
807 1.178.2.2 christos break;
808 1.178.2.2 christos case CDB_GROUPID_6:
809 1.178.2.2 christos j = CDB_GROUP6;
810 1.178.2.2 christos break;
811 1.178.2.2 christos case CDB_GROUPID_7:
812 1.178.2.2 christos j = CDB_GROUP7;
813 1.178.2.2 christos break;
814 1.178.2.2 christos default:
815 1.178.2.2 christos j = 0;
816 1.178.2.2 christos }
817 1.178.2.2 christos if (j == 0)
818 1.178.2.2 christos j = sizeof (cmd->bytes);
819 1.178.2.2 christos for (i = 0; i < j-1; i++) /* already done the opcode */
820 1.178.2.2 christos printf(" %02x", cmd->bytes[i]);
821 1.178.2.2 christos }
822 1.178.2.2 christos
823 1.178.2.2 christos /*
824 1.178.2.2 christos * scsipi_interpret_sense:
825 1.178.2.2 christos *
826 1.178.2.2 christos * Look at the returned sense and act on the error, determining
827 1.178.2.2 christos * the unix error number to pass back. (0 = report no error)
828 1.178.2.2 christos *
829 1.178.2.2 christos * NOTE: If we return ERESTART, we are expected to haved
830 1.178.2.2 christos * thawed the device!
831 1.178.2.2 christos *
832 1.178.2.2 christos * THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES.
833 1.178.2.2 christos */
834 1.178.2.2 christos int
835 1.178.2.2 christos scsipi_interpret_sense(struct scsipi_xfer *xs)
836 1.178.2.2 christos {
837 1.178.2.2 christos struct scsi_sense_data *sense;
838 1.178.2.2 christos struct scsipi_periph *periph = xs->xs_periph;
839 1.178.2.2 christos u_int8_t key;
840 1.178.2.2 christos int error;
841 1.178.2.2 christos u_int32_t info;
842 1.178.2.2 christos static const char *error_mes[] = {
843 1.178.2.2 christos "soft error (corrected)",
844 1.178.2.2 christos "not ready", "medium error",
845 1.178.2.2 christos "non-media hardware failure", "illegal request",
846 1.178.2.2 christos "unit attention", "readonly device",
847 1.178.2.2 christos "no data found", "vendor unique",
848 1.178.2.2 christos "copy aborted", "command aborted",
849 1.178.2.2 christos "search returned equal", "volume overflow",
850 1.178.2.2 christos "verify miscompare", "unknown error key"
851 1.178.2.2 christos };
852 1.178.2.2 christos
853 1.178.2.2 christos sense = &xs->sense.scsi_sense;
854 1.178.2.2 christos #ifdef SCSIPI_DEBUG
855 1.178.2.2 christos if (periph->periph_flags & SCSIPI_DB1) {
856 1.178.2.2 christos int count;
857 1.178.2.2 christos scsipi_printaddr(periph);
858 1.178.2.2 christos printf(" sense debug information:\n");
859 1.178.2.2 christos printf("\tcode 0x%x valid %d\n",
860 1.178.2.2 christos SSD_RCODE(sense->response_code),
861 1.178.2.2 christos sense->response_code & SSD_RCODE_VALID ? 1 : 0);
862 1.178.2.2 christos printf("\tseg 0x%x key 0x%x ili 0x%x eom 0x%x fmark 0x%x\n",
863 1.178.2.2 christos sense->segment,
864 1.178.2.2 christos SSD_SENSE_KEY(sense->flags),
865 1.178.2.2 christos sense->flags & SSD_ILI ? 1 : 0,
866 1.178.2.2 christos sense->flags & SSD_EOM ? 1 : 0,
867 1.178.2.2 christos sense->flags & SSD_FILEMARK ? 1 : 0);
868 1.178.2.2 christos printf("\ninfo: 0x%x 0x%x 0x%x 0x%x followed by %d "
869 1.178.2.2 christos "extra bytes\n",
870 1.178.2.2 christos sense->info[0],
871 1.178.2.2 christos sense->info[1],
872 1.178.2.2 christos sense->info[2],
873 1.178.2.2 christos sense->info[3],
874 1.178.2.2 christos sense->extra_len);
875 1.178.2.2 christos printf("\textra: ");
876 1.178.2.2 christos for (count = 0; count < SSD_ADD_BYTES_LIM(sense); count++)
877 1.178.2.2 christos printf("0x%x ", sense->csi[count]);
878 1.178.2.2 christos printf("\n");
879 1.178.2.2 christos }
880 1.178.2.2 christos #endif
881 1.178.2.2 christos
882 1.178.2.2 christos /*
883 1.178.2.2 christos * If the periph has its own error handler, call it first.
884 1.178.2.2 christos * If it returns a legit error value, return that, otherwise
885 1.178.2.2 christos * it wants us to continue with normal error processing.
886 1.178.2.2 christos */
887 1.178.2.2 christos if (periph->periph_switch->psw_error != NULL) {
888 1.178.2.2 christos SC_DEBUG(periph, SCSIPI_DB2,
889 1.178.2.2 christos ("calling private err_handler()\n"));
890 1.178.2.2 christos error = (*periph->periph_switch->psw_error)(xs);
891 1.178.2.2 christos if (error != EJUSTRETURN)
892 1.178.2.2 christos return error;
893 1.178.2.2 christos }
894 1.178.2.2 christos /* otherwise use the default */
895 1.178.2.2 christos switch (SSD_RCODE(sense->response_code)) {
896 1.178.2.2 christos
897 1.178.2.2 christos /*
898 1.178.2.2 christos * Old SCSI-1 and SASI devices respond with
899 1.178.2.2 christos * codes other than 70.
900 1.178.2.2 christos */
901 1.178.2.2 christos case 0x00: /* no error (command completed OK) */
902 1.178.2.2 christos return 0;
903 1.178.2.2 christos case 0x04: /* drive not ready after it was selected */
904 1.178.2.2 christos if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
905 1.178.2.2 christos periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
906 1.178.2.2 christos if ((xs->xs_control & XS_CTL_IGNORE_NOT_READY) != 0)
907 1.178.2.2 christos return 0;
908 1.178.2.2 christos /* XXX - display some sort of error here? */
909 1.178.2.2 christos return EIO;
910 1.178.2.2 christos case 0x20: /* invalid command */
911 1.178.2.2 christos if ((xs->xs_control &
912 1.178.2.2 christos XS_CTL_IGNORE_ILLEGAL_REQUEST) != 0)
913 1.178.2.2 christos return 0;
914 1.178.2.2 christos return EINVAL;
915 1.178.2.2 christos case 0x25: /* invalid LUN (Adaptec ACB-4000) */
916 1.178.2.2 christos return EACCES;
917 1.178.2.2 christos
918 1.178.2.2 christos /*
919 1.178.2.2 christos * If it's code 70, use the extended stuff and
920 1.178.2.2 christos * interpret the key
921 1.178.2.2 christos */
922 1.178.2.2 christos case 0x71: /* delayed error */
923 1.178.2.2 christos scsipi_printaddr(periph);
924 1.178.2.2 christos key = SSD_SENSE_KEY(sense->flags);
925 1.178.2.2 christos printf(" DEFERRED ERROR, key = 0x%x\n", key);
926 1.178.2.2 christos /* FALLTHROUGH */
927 1.178.2.2 christos case 0x70:
928 1.178.2.2 christos if ((sense->response_code & SSD_RCODE_VALID) != 0)
929 1.178.2.2 christos info = _4btol(sense->info);
930 1.178.2.2 christos else
931 1.178.2.2 christos info = 0;
932 1.178.2.2 christos key = SSD_SENSE_KEY(sense->flags);
933 1.178.2.2 christos
934 1.178.2.2 christos switch (key) {
935 1.178.2.2 christos case SKEY_NO_SENSE:
936 1.178.2.2 christos case SKEY_RECOVERED_ERROR:
937 1.178.2.2 christos if (xs->resid == xs->datalen && xs->datalen) {
938 1.178.2.2 christos /*
939 1.178.2.2 christos * Why is this here?
940 1.178.2.2 christos */
941 1.178.2.2 christos xs->resid = 0; /* not short read */
942 1.178.2.2 christos }
943 1.178.2.2 christos case SKEY_EQUAL:
944 1.178.2.2 christos error = 0;
945 1.178.2.2 christos break;
946 1.178.2.2 christos case SKEY_NOT_READY:
947 1.178.2.2 christos if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
948 1.178.2.2 christos periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
949 1.178.2.2 christos if ((xs->xs_control & XS_CTL_IGNORE_NOT_READY) != 0)
950 1.178.2.2 christos return 0;
951 1.178.2.2 christos if (sense->asc == 0x3A) {
952 1.178.2.2 christos error = ENODEV; /* Medium not present */
953 1.178.2.2 christos if (xs->xs_control & XS_CTL_SILENT_NODEV)
954 1.178.2.2 christos return error;
955 1.178.2.2 christos } else
956 1.178.2.2 christos error = EIO;
957 1.178.2.2 christos if ((xs->xs_control & XS_CTL_SILENT) != 0)
958 1.178.2.2 christos return error;
959 1.178.2.2 christos break;
960 1.178.2.2 christos case SKEY_ILLEGAL_REQUEST:
961 1.178.2.2 christos if ((xs->xs_control &
962 1.178.2.2 christos XS_CTL_IGNORE_ILLEGAL_REQUEST) != 0)
963 1.178.2.2 christos return 0;
964 1.178.2.2 christos /*
965 1.178.2.2 christos * Handle the case where a device reports
966 1.178.2.2 christos * Logical Unit Not Supported during discovery.
967 1.178.2.2 christos */
968 1.178.2.2 christos if ((xs->xs_control & XS_CTL_DISCOVERY) != 0 &&
969 1.178.2.2 christos sense->asc == 0x25 &&
970 1.178.2.2 christos sense->ascq == 0x00)
971 1.178.2.2 christos return EINVAL;
972 1.178.2.2 christos if ((xs->xs_control & XS_CTL_SILENT) != 0)
973 1.178.2.2 christos return EIO;
974 1.178.2.2 christos error = EINVAL;
975 1.178.2.2 christos break;
976 1.178.2.2 christos case SKEY_UNIT_ATTENTION:
977 1.178.2.2 christos if (sense->asc == 0x29 &&
978 1.178.2.2 christos sense->ascq == 0x00) {
979 1.178.2.2 christos /* device or bus reset */
980 1.178.2.2 christos return ERESTART;
981 1.178.2.2 christos }
982 1.178.2.2 christos if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
983 1.178.2.2 christos periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
984 1.178.2.2 christos if ((xs->xs_control &
985 1.178.2.2 christos XS_CTL_IGNORE_MEDIA_CHANGE) != 0 ||
986 1.178.2.2 christos /* XXX Should reupload any transient state. */
987 1.178.2.2 christos (periph->periph_flags &
988 1.178.2.2 christos PERIPH_REMOVABLE) == 0) {
989 1.178.2.2 christos return ERESTART;
990 1.178.2.2 christos }
991 1.178.2.2 christos if ((xs->xs_control & XS_CTL_SILENT) != 0)
992 1.178.2.2 christos return EIO;
993 1.178.2.2 christos error = EIO;
994 1.178.2.2 christos break;
995 1.178.2.2 christos case SKEY_DATA_PROTECT:
996 1.178.2.2 christos error = EROFS;
997 1.178.2.2 christos break;
998 1.178.2.2 christos case SKEY_BLANK_CHECK:
999 1.178.2.2 christos error = 0;
1000 1.178.2.2 christos break;
1001 1.178.2.2 christos case SKEY_ABORTED_COMMAND:
1002 1.178.2.2 christos if (xs->xs_retries != 0) {
1003 1.178.2.2 christos xs->xs_retries--;
1004 1.178.2.2 christos error = ERESTART;
1005 1.178.2.2 christos } else
1006 1.178.2.2 christos error = EIO;
1007 1.178.2.2 christos break;
1008 1.178.2.2 christos case SKEY_VOLUME_OVERFLOW:
1009 1.178.2.2 christos error = ENOSPC;
1010 1.178.2.2 christos break;
1011 1.178.2.2 christos default:
1012 1.178.2.2 christos error = EIO;
1013 1.178.2.2 christos break;
1014 1.178.2.2 christos }
1015 1.178.2.2 christos
1016 1.178.2.2 christos /* Print verbose decode if appropriate and possible */
1017 1.178.2.2 christos if ((key == 0) ||
1018 1.178.2.2 christos ((xs->xs_control & XS_CTL_SILENT) != 0) ||
1019 1.178.2.2 christos (scsipi_print_sense(xs, 0) != 0))
1020 1.178.2.2 christos return error;
1021 1.178.2.2 christos
1022 1.178.2.2 christos /* Print brief(er) sense information */
1023 1.178.2.2 christos scsipi_printaddr(periph);
1024 1.178.2.2 christos printf("%s", error_mes[key - 1]);
1025 1.178.2.2 christos if ((sense->response_code & SSD_RCODE_VALID) != 0) {
1026 1.178.2.2 christos switch (key) {
1027 1.178.2.2 christos case SKEY_NOT_READY:
1028 1.178.2.2 christos case SKEY_ILLEGAL_REQUEST:
1029 1.178.2.2 christos case SKEY_UNIT_ATTENTION:
1030 1.178.2.2 christos case SKEY_DATA_PROTECT:
1031 1.178.2.2 christos break;
1032 1.178.2.2 christos case SKEY_BLANK_CHECK:
1033 1.178.2.2 christos printf(", requested size: %d (decimal)",
1034 1.178.2.2 christos info);
1035 1.178.2.2 christos break;
1036 1.178.2.2 christos case SKEY_ABORTED_COMMAND:
1037 1.178.2.2 christos if (xs->xs_retries)
1038 1.178.2.2 christos printf(", retrying");
1039 1.178.2.2 christos printf(", cmd 0x%x, info 0x%x",
1040 1.178.2.2 christos xs->cmd->opcode, info);
1041 1.178.2.2 christos break;
1042 1.178.2.2 christos default:
1043 1.178.2.2 christos printf(", info = %d (decimal)", info);
1044 1.178.2.2 christos }
1045 1.178.2.2 christos }
1046 1.178.2.2 christos if (sense->extra_len != 0) {
1047 1.178.2.2 christos int n;
1048 1.178.2.2 christos printf(", data =");
1049 1.178.2.2 christos for (n = 0; n < sense->extra_len; n++)
1050 1.178.2.2 christos printf(" %02x",
1051 1.178.2.2 christos sense->csi[n]);
1052 1.178.2.2 christos }
1053 1.178.2.2 christos printf("\n");
1054 1.178.2.2 christos return error;
1055 1.178.2.2 christos
1056 1.178.2.2 christos /*
1057 1.178.2.2 christos * Some other code, just report it
1058 1.178.2.2 christos */
1059 1.178.2.2 christos default:
1060 1.178.2.2 christos #if defined(SCSIDEBUG) || defined(DEBUG)
1061 1.178.2.2 christos {
1062 1.178.2.2 christos static const char *uc = "undecodable sense error";
1063 1.178.2.2 christos int i;
1064 1.178.2.2 christos u_int8_t *cptr = (u_int8_t *) sense;
1065 1.178.2.2 christos scsipi_printaddr(periph);
1066 1.178.2.2 christos if (xs->cmd == &xs->cmdstore) {
1067 1.178.2.2 christos printf("%s for opcode 0x%x, data=",
1068 1.178.2.2 christos uc, xs->cmdstore.opcode);
1069 1.178.2.2 christos } else {
1070 1.178.2.2 christos printf("%s, data=", uc);
1071 1.178.2.2 christos }
1072 1.178.2.2 christos for (i = 0; i < sizeof (sense); i++)
1073 1.178.2.2 christos printf(" 0x%02x", *(cptr++) & 0xff);
1074 1.178.2.2 christos printf("\n");
1075 1.178.2.2 christos }
1076 1.178.2.2 christos #else
1077 1.178.2.2 christos scsipi_printaddr(periph);
1078 1.178.2.2 christos printf("Sense Error Code 0x%x",
1079 1.178.2.2 christos SSD_RCODE(sense->response_code));
1080 1.178.2.2 christos if ((sense->response_code & SSD_RCODE_VALID) != 0) {
1081 1.178.2.2 christos struct scsi_sense_data_unextended *usense =
1082 1.178.2.2 christos (struct scsi_sense_data_unextended *)sense;
1083 1.178.2.2 christos printf(" at block no. %d (decimal)",
1084 1.178.2.2 christos _3btol(usense->block));
1085 1.178.2.2 christos }
1086 1.178.2.2 christos printf("\n");
1087 1.178.2.2 christos #endif
1088 1.178.2.2 christos return EIO;
1089 1.178.2.2 christos }
1090 1.178.2.2 christos }
1091 1.178.2.2 christos
1092 1.178.2.2 christos /*
1093 1.178.2.2 christos * scsipi_test_unit_ready:
1094 1.178.2.2 christos *
1095 1.178.2.2 christos * Issue a `test unit ready' request.
1096 1.178.2.2 christos */
1097 1.178.2.2 christos int
1098 1.178.2.2 christos scsipi_test_unit_ready(struct scsipi_periph *periph, int flags)
1099 1.178.2.2 christos {
1100 1.178.2.2 christos struct scsi_test_unit_ready cmd;
1101 1.178.2.2 christos int retries;
1102 1.178.2.2 christos
1103 1.178.2.2 christos /* some ATAPI drives don't support TEST UNIT READY. Sigh */
1104 1.178.2.2 christos if (periph->periph_quirks & PQUIRK_NOTUR)
1105 1.178.2.2 christos return 0;
1106 1.178.2.2 christos
1107 1.178.2.2 christos if (flags & XS_CTL_DISCOVERY)
1108 1.178.2.2 christos retries = 0;
1109 1.178.2.2 christos else
1110 1.178.2.2 christos retries = SCSIPIRETRIES;
1111 1.178.2.2 christos
1112 1.178.2.2 christos memset(&cmd, 0, sizeof(cmd));
1113 1.178.2.2 christos cmd.opcode = SCSI_TEST_UNIT_READY;
1114 1.178.2.2 christos
1115 1.178.2.2 christos return scsipi_command(periph, (void *)&cmd, sizeof(cmd), 0, 0,
1116 1.178.2.2 christos retries, 10000, NULL, flags);
1117 1.178.2.2 christos }
1118 1.178.2.2 christos
1119 1.178.2.2 christos static const struct scsipi_inquiry3_pattern {
1120 1.178.2.2 christos const char vendor[8];
1121 1.178.2.2 christos const char product[16];
1122 1.178.2.2 christos const char revision[4];
1123 1.178.2.2 christos } scsipi_inquiry3_quirk[] = {
1124 1.178.2.2 christos { "ES-6600 ", "", "" },
1125 1.178.2.2 christos };
1126 1.178.2.2 christos
1127 1.178.2.2 christos static int
1128 1.178.2.2 christos scsipi_inquiry3_ok(const struct scsipi_inquiry_data *ib)
1129 1.178.2.2 christos {
1130 1.178.2.2 christos for (size_t i = 0; i < __arraycount(scsipi_inquiry3_quirk); i++) {
1131 1.178.2.2 christos const struct scsipi_inquiry3_pattern *q =
1132 1.178.2.2 christos &scsipi_inquiry3_quirk[i];
1133 1.178.2.2 christos #define MATCH(field) \
1134 1.178.2.2 christos (q->field[0] ? memcmp(ib->field, q->field, sizeof(ib->field)) == 0 : 1)
1135 1.178.2.2 christos if (MATCH(vendor) && MATCH(product) && MATCH(revision))
1136 1.178.2.2 christos return 0;
1137 1.178.2.2 christos }
1138 1.178.2.2 christos return 1;
1139 1.178.2.2 christos }
1140 1.178.2.2 christos
1141 1.178.2.2 christos /*
1142 1.178.2.2 christos * scsipi_inquire:
1143 1.178.2.2 christos *
1144 1.178.2.2 christos * Ask the device about itself.
1145 1.178.2.2 christos */
1146 1.178.2.2 christos int
1147 1.178.2.2 christos scsipi_inquire(struct scsipi_periph *periph, struct scsipi_inquiry_data *inqbuf,
1148 1.178.2.2 christos int flags)
1149 1.178.2.2 christos {
1150 1.178.2.2 christos struct scsipi_inquiry cmd;
1151 1.178.2.2 christos int error;
1152 1.178.2.2 christos int retries;
1153 1.178.2.2 christos
1154 1.178.2.2 christos if (flags & XS_CTL_DISCOVERY)
1155 1.178.2.2 christos retries = 0;
1156 1.178.2.2 christos else
1157 1.178.2.2 christos retries = SCSIPIRETRIES;
1158 1.178.2.2 christos
1159 1.178.2.2 christos /*
1160 1.178.2.2 christos * If we request more data than the device can provide, it SHOULD just
1161 1.178.2.2 christos * return a short response. However, some devices error with an
1162 1.178.2.2 christos * ILLEGAL REQUEST sense code, and yet others have even more special
1163 1.178.2.2 christos * failture modes (such as the GL641USB flash adapter, which goes loony
1164 1.178.2.2 christos * and sends corrupted CRCs). To work around this, and to bring our
1165 1.178.2.2 christos * behavior more in line with other OSes, we do a shorter inquiry,
1166 1.178.2.2 christos * covering all the SCSI-2 information, first, and then request more
1167 1.178.2.2 christos * data iff the "additional length" field indicates there is more.
1168 1.178.2.2 christos * - mycroft, 2003/10/16
1169 1.178.2.2 christos */
1170 1.178.2.2 christos memset(&cmd, 0, sizeof(cmd));
1171 1.178.2.2 christos cmd.opcode = INQUIRY;
1172 1.178.2.2 christos cmd.length = SCSIPI_INQUIRY_LENGTH_SCSI2;
1173 1.178.2.2 christos error = scsipi_command(periph, (void *)&cmd, sizeof(cmd),
1174 1.178.2.2 christos (void *)inqbuf, SCSIPI_INQUIRY_LENGTH_SCSI2, retries,
1175 1.178.2.2 christos 10000, NULL, flags | XS_CTL_DATA_IN);
1176 1.178.2.2 christos if (!error &&
1177 1.178.2.2 christos inqbuf->additional_length > SCSIPI_INQUIRY_LENGTH_SCSI2 - 4) {
1178 1.178.2.2 christos if (scsipi_inquiry3_ok(inqbuf)) {
1179 1.178.2.2 christos #if 0
1180 1.178.2.2 christos printf("inquire: addlen=%d, retrying\n", inqbuf->additional_length);
1181 1.178.2.2 christos #endif
1182 1.178.2.2 christos cmd.length = SCSIPI_INQUIRY_LENGTH_SCSI3;
1183 1.178.2.2 christos error = scsipi_command(periph, (void *)&cmd, sizeof(cmd),
1184 1.178.2.2 christos (void *)inqbuf, SCSIPI_INQUIRY_LENGTH_SCSI3, retries,
1185 1.178.2.2 christos 10000, NULL, flags | XS_CTL_DATA_IN);
1186 1.178.2.2 christos #if 0
1187 1.178.2.2 christos printf("inquire: error=%d\n", error);
1188 1.178.2.2 christos #endif
1189 1.178.2.2 christos }
1190 1.178.2.2 christos }
1191 1.178.2.2 christos
1192 1.178.2.2 christos #ifdef SCSI_OLD_NOINQUIRY
1193 1.178.2.2 christos /*
1194 1.178.2.2 christos * Kludge for the Adaptec ACB-4000 SCSI->MFM translator.
1195 1.178.2.2 christos * This board doesn't support the INQUIRY command at all.
1196 1.178.2.2 christos */
1197 1.178.2.2 christos if (error == EINVAL || error == EACCES) {
1198 1.178.2.2 christos /*
1199 1.178.2.2 christos * Conjure up an INQUIRY response.
1200 1.178.2.2 christos */
1201 1.178.2.2 christos inqbuf->device = (error == EINVAL ?
1202 1.178.2.2 christos SID_QUAL_LU_PRESENT :
1203 1.178.2.2 christos SID_QUAL_LU_NOTPRESENT) | T_DIRECT;
1204 1.178.2.2 christos inqbuf->dev_qual2 = 0;
1205 1.178.2.2 christos inqbuf->version = 0;
1206 1.178.2.2 christos inqbuf->response_format = SID_FORMAT_SCSI1;
1207 1.178.2.2 christos inqbuf->additional_length = SCSIPI_INQUIRY_LENGTH_SCSI2 - 4;
1208 1.178.2.2 christos inqbuf->flags1 = inqbuf->flags2 = inqbuf->flags3 = 0;
1209 1.178.2.2 christos memcpy(inqbuf->vendor, "ADAPTEC ACB-4000 ", 28);
1210 1.178.2.2 christos error = 0;
1211 1.178.2.2 christos }
1212 1.178.2.2 christos
1213 1.178.2.2 christos /*
1214 1.178.2.2 christos * Kludge for the Emulex MT-02 SCSI->QIC translator.
1215 1.178.2.2 christos * This board gives an empty response to an INQUIRY command.
1216 1.178.2.2 christos */
1217 1.178.2.2 christos else if (error == 0 &&
1218 1.178.2.2 christos inqbuf->device == (SID_QUAL_LU_PRESENT | T_DIRECT) &&
1219 1.178.2.2 christos inqbuf->dev_qual2 == 0 &&
1220 1.178.2.2 christos inqbuf->version == 0 &&
1221 1.178.2.2 christos inqbuf->response_format == SID_FORMAT_SCSI1) {
1222 1.178.2.2 christos /*
1223 1.178.2.2 christos * Fill out the INQUIRY response.
1224 1.178.2.2 christos */
1225 1.178.2.2 christos inqbuf->device = (SID_QUAL_LU_PRESENT | T_SEQUENTIAL);
1226 1.178.2.2 christos inqbuf->dev_qual2 = SID_REMOVABLE;
1227 1.178.2.2 christos inqbuf->additional_length = SCSIPI_INQUIRY_LENGTH_SCSI2 - 4;
1228 1.178.2.2 christos inqbuf->flags1 = inqbuf->flags2 = inqbuf->flags3 = 0;
1229 1.178.2.2 christos memcpy(inqbuf->vendor, "EMULEX MT-02 QIC ", 28);
1230 1.178.2.2 christos }
1231 1.178.2.2 christos #endif /* SCSI_OLD_NOINQUIRY */
1232 1.178.2.2 christos
1233 1.178.2.2 christos return error;
1234 1.178.2.2 christos }
1235 1.178.2.2 christos
1236 1.178.2.2 christos /*
1237 1.178.2.2 christos * scsipi_prevent:
1238 1.178.2.2 christos *
1239 1.178.2.2 christos * Prevent or allow the user to remove the media
1240 1.178.2.2 christos */
1241 1.178.2.2 christos int
1242 1.178.2.2 christos scsipi_prevent(struct scsipi_periph *periph, int type, int flags)
1243 1.178.2.2 christos {
1244 1.178.2.2 christos struct scsi_prevent_allow_medium_removal cmd;
1245 1.178.2.2 christos
1246 1.178.2.2 christos if (periph->periph_quirks & PQUIRK_NODOORLOCK)
1247 1.178.2.2 christos return 0;
1248 1.178.2.2 christos
1249 1.178.2.2 christos memset(&cmd, 0, sizeof(cmd));
1250 1.178.2.2 christos cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL;
1251 1.178.2.2 christos cmd.how = type;
1252 1.178.2.2 christos
1253 1.178.2.2 christos return (scsipi_command(periph, (void *)&cmd, sizeof(cmd), 0, 0,
1254 1.178.2.2 christos SCSIPIRETRIES, 5000, NULL, flags));
1255 1.178.2.2 christos }
1256 1.178.2.2 christos
1257 1.178.2.2 christos /*
1258 1.178.2.2 christos * scsipi_start:
1259 1.178.2.2 christos *
1260 1.178.2.2 christos * Send a START UNIT.
1261 1.178.2.2 christos */
1262 1.178.2.2 christos int
1263 1.178.2.2 christos scsipi_start(struct scsipi_periph *periph, int type, int flags)
1264 1.178.2.2 christos {
1265 1.178.2.2 christos struct scsipi_start_stop cmd;
1266 1.178.2.2 christos
1267 1.178.2.2 christos memset(&cmd, 0, sizeof(cmd));
1268 1.178.2.2 christos cmd.opcode = START_STOP;
1269 1.178.2.2 christos cmd.byte2 = 0x00;
1270 1.178.2.2 christos cmd.how = type;
1271 1.178.2.2 christos
1272 1.178.2.2 christos return scsipi_command(periph, (void *)&cmd, sizeof(cmd), 0, 0,
1273 1.178.2.2 christos SCSIPIRETRIES, (type & SSS_START) ? 60000 : 10000, NULL, flags);
1274 1.178.2.2 christos }
1275 1.178.2.2 christos
1276 1.178.2.2 christos /*
1277 1.178.2.2 christos * scsipi_mode_sense, scsipi_mode_sense_big:
1278 1.178.2.2 christos * get a sense page from a device
1279 1.178.2.2 christos */
1280 1.178.2.2 christos
1281 1.178.2.2 christos int
1282 1.178.2.2 christos scsipi_mode_sense(struct scsipi_periph *periph, int byte2, int page,
1283 1.178.2.2 christos struct scsi_mode_parameter_header_6 *data, int len, int flags, int retries,
1284 1.178.2.2 christos int timeout)
1285 1.178.2.2 christos {
1286 1.178.2.2 christos struct scsi_mode_sense_6 cmd;
1287 1.178.2.2 christos
1288 1.178.2.2 christos memset(&cmd, 0, sizeof(cmd));
1289 1.178.2.2 christos cmd.opcode = SCSI_MODE_SENSE_6;
1290 1.178.2.2 christos cmd.byte2 = byte2;
1291 1.178.2.2 christos cmd.page = page;
1292 1.178.2.2 christos cmd.length = len & 0xff;
1293 1.178.2.2 christos
1294 1.178.2.2 christos return scsipi_command(periph, (void *)&cmd, sizeof(cmd),
1295 1.178.2.2 christos (void *)data, len, retries, timeout, NULL, flags | XS_CTL_DATA_IN);
1296 1.178.2.2 christos }
1297 1.178.2.2 christos
1298 1.178.2.2 christos int
1299 1.178.2.2 christos scsipi_mode_sense_big(struct scsipi_periph *periph, int byte2, int page,
1300 1.178.2.2 christos struct scsi_mode_parameter_header_10 *data, int len, int flags, int retries,
1301 1.178.2.2 christos int timeout)
1302 1.178.2.2 christos {
1303 1.178.2.2 christos struct scsi_mode_sense_10 cmd;
1304 1.178.2.2 christos
1305 1.178.2.2 christos memset(&cmd, 0, sizeof(cmd));
1306 1.178.2.2 christos cmd.opcode = SCSI_MODE_SENSE_10;
1307 1.178.2.2 christos cmd.byte2 = byte2;
1308 1.178.2.2 christos cmd.page = page;
1309 1.178.2.2 christos _lto2b(len, cmd.length);
1310 1.178.2.2 christos
1311 1.178.2.2 christos return scsipi_command(periph, (void *)&cmd, sizeof(cmd),
1312 1.178.2.2 christos (void *)data, len, retries, timeout, NULL, flags | XS_CTL_DATA_IN);
1313 1.178.2.2 christos }
1314 1.178.2.2 christos
1315 1.178.2.2 christos int
1316 1.178.2.2 christos scsipi_mode_select(struct scsipi_periph *periph, int byte2,
1317 1.178.2.2 christos struct scsi_mode_parameter_header_6 *data, int len, int flags, int retries,
1318 1.178.2.2 christos int timeout)
1319 1.178.2.2 christos {
1320 1.178.2.2 christos struct scsi_mode_select_6 cmd;
1321 1.178.2.2 christos
1322 1.178.2.2 christos memset(&cmd, 0, sizeof(cmd));
1323 1.178.2.2 christos cmd.opcode = SCSI_MODE_SELECT_6;
1324 1.178.2.2 christos cmd.byte2 = byte2;
1325 1.178.2.2 christos cmd.length = len & 0xff;
1326 1.178.2.2 christos
1327 1.178.2.2 christos return scsipi_command(periph, (void *)&cmd, sizeof(cmd),
1328 1.178.2.2 christos (void *)data, len, retries, timeout, NULL, flags | XS_CTL_DATA_OUT);
1329 1.178.2.2 christos }
1330 1.178.2.2 christos
1331 1.178.2.2 christos int
1332 1.178.2.2 christos scsipi_mode_select_big(struct scsipi_periph *periph, int byte2,
1333 1.178.2.2 christos struct scsi_mode_parameter_header_10 *data, int len, int flags, int retries,
1334 1.178.2.2 christos int timeout)
1335 1.178.2.2 christos {
1336 1.178.2.2 christos struct scsi_mode_select_10 cmd;
1337 1.178.2.2 christos
1338 1.178.2.2 christos memset(&cmd, 0, sizeof(cmd));
1339 1.178.2.2 christos cmd.opcode = SCSI_MODE_SELECT_10;
1340 1.178.2.2 christos cmd.byte2 = byte2;
1341 1.178.2.2 christos _lto2b(len, cmd.length);
1342 1.178.2.2 christos
1343 1.178.2.2 christos return scsipi_command(periph, (void *)&cmd, sizeof(cmd),
1344 1.178.2.2 christos (void *)data, len, retries, timeout, NULL, flags | XS_CTL_DATA_OUT);
1345 1.178.2.2 christos }
1346 1.178.2.2 christos
1347 1.178.2.2 christos /*
1348 1.178.2.2 christos * scsipi_done:
1349 1.178.2.2 christos *
1350 1.178.2.2 christos * This routine is called by an adapter's interrupt handler when
1351 1.178.2.2 christos * an xfer is completed.
1352 1.178.2.2 christos */
1353 1.178.2.2 christos void
1354 1.178.2.2 christos scsipi_done(struct scsipi_xfer *xs)
1355 1.178.2.2 christos {
1356 1.178.2.2 christos struct scsipi_periph *periph = xs->xs_periph;
1357 1.178.2.2 christos struct scsipi_channel *chan = periph->periph_channel;
1358 1.178.2.2 christos int freezecnt;
1359 1.178.2.2 christos
1360 1.178.2.2 christos SC_DEBUG(periph, SCSIPI_DB2, ("scsipi_done\n"));
1361 1.178.2.2 christos #ifdef SCSIPI_DEBUG
1362 1.178.2.2 christos if (periph->periph_dbflags & SCSIPI_DB1)
1363 1.178.2.2 christos show_scsipi_cmd(xs);
1364 1.178.2.2 christos #endif
1365 1.178.2.2 christos
1366 1.178.2.2 christos mutex_enter(chan_mtx(chan));
1367 1.178.2.2 christos /*
1368 1.178.2.2 christos * The resource this command was using is now free.
1369 1.178.2.2 christos */
1370 1.178.2.2 christos if (xs->xs_status & XS_STS_DONE) {
1371 1.178.2.2 christos /* XXX in certain circumstances, such as a device
1372 1.178.2.2 christos * being detached, a xs that has already been
1373 1.178.2.2 christos * scsipi_done()'d by the main thread will be done'd
1374 1.178.2.2 christos * again by scsibusdetach(). Putting the xs on the
1375 1.178.2.2 christos * chan_complete queue causes list corruption and
1376 1.178.2.2 christos * everyone dies. This prevents that, but perhaps
1377 1.178.2.2 christos * there should be better coordination somewhere such
1378 1.178.2.2 christos * that this won't ever happen (and can be turned into
1379 1.178.2.2 christos * a KASSERT().
1380 1.178.2.2 christos */
1381 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1382 1.178.2.2 christos goto out;
1383 1.178.2.2 christos }
1384 1.178.2.2 christos scsipi_put_resource(chan);
1385 1.178.2.2 christos xs->xs_periph->periph_sent--;
1386 1.178.2.2 christos
1387 1.178.2.2 christos /*
1388 1.178.2.2 christos * If the command was tagged, free the tag.
1389 1.178.2.2 christos */
1390 1.178.2.2 christos if (XS_CTL_TAGTYPE(xs) != 0)
1391 1.178.2.2 christos scsipi_put_tag(xs);
1392 1.178.2.2 christos else
1393 1.178.2.2 christos periph->periph_flags &= ~PERIPH_UNTAG;
1394 1.178.2.2 christos
1395 1.178.2.2 christos /* Mark the command as `done'. */
1396 1.178.2.2 christos xs->xs_status |= XS_STS_DONE;
1397 1.178.2.2 christos
1398 1.178.2.2 christos #ifdef DIAGNOSTIC
1399 1.178.2.2 christos if ((xs->xs_control & (XS_CTL_ASYNC|XS_CTL_POLL)) ==
1400 1.178.2.2 christos (XS_CTL_ASYNC|XS_CTL_POLL))
1401 1.178.2.2 christos panic("scsipi_done: ASYNC and POLL");
1402 1.178.2.2 christos #endif
1403 1.178.2.2 christos
1404 1.178.2.2 christos /*
1405 1.178.2.2 christos * If the xfer had an error of any sort, freeze the
1406 1.178.2.2 christos * periph's queue. Freeze it again if we were requested
1407 1.178.2.2 christos * to do so in the xfer.
1408 1.178.2.2 christos */
1409 1.178.2.2 christos freezecnt = 0;
1410 1.178.2.2 christos if (xs->error != XS_NOERROR)
1411 1.178.2.2 christos freezecnt++;
1412 1.178.2.2 christos if (xs->xs_control & XS_CTL_FREEZE_PERIPH)
1413 1.178.2.2 christos freezecnt++;
1414 1.178.2.2 christos if (freezecnt != 0)
1415 1.178.2.2 christos scsipi_periph_freeze_locked(periph, freezecnt);
1416 1.178.2.2 christos
1417 1.178.2.2 christos /*
1418 1.178.2.2 christos * record the xfer with a pending sense, in case a SCSI reset is
1419 1.178.2.2 christos * received before the thread is waked up.
1420 1.178.2.2 christos */
1421 1.178.2.2 christos if (xs->error == XS_BUSY && xs->status == SCSI_CHECK) {
1422 1.178.2.2 christos periph->periph_flags |= PERIPH_SENSE;
1423 1.178.2.2 christos periph->periph_xscheck = xs;
1424 1.178.2.2 christos }
1425 1.178.2.2 christos
1426 1.178.2.2 christos /*
1427 1.178.2.2 christos * If this was an xfer that was not to complete asynchronously,
1428 1.178.2.2 christos * let the requesting thread perform error checking/handling
1429 1.178.2.2 christos * in its context.
1430 1.178.2.2 christos */
1431 1.178.2.2 christos if ((xs->xs_control & XS_CTL_ASYNC) == 0) {
1432 1.178.2.2 christos /*
1433 1.178.2.2 christos * If it's a polling job, just return, to unwind the
1434 1.178.2.2 christos * call graph. We don't need to restart the queue,
1435 1.178.2.2 christos * because pollings jobs are treated specially, and
1436 1.178.2.2 christos * are really only used during crash dumps anyway
1437 1.178.2.2 christos * (XXX or during boot-time autconfiguration of
1438 1.178.2.2 christos * ATAPI devices).
1439 1.178.2.2 christos */
1440 1.178.2.2 christos if (xs->xs_control & XS_CTL_POLL) {
1441 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1442 1.178.2.2 christos return;
1443 1.178.2.2 christos }
1444 1.178.2.2 christos cv_broadcast(xs_cv(xs));
1445 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1446 1.178.2.2 christos goto out;
1447 1.178.2.2 christos }
1448 1.178.2.2 christos
1449 1.178.2.2 christos /*
1450 1.178.2.2 christos * Catch the extremely common case of I/O completing
1451 1.178.2.2 christos * without error; no use in taking a context switch
1452 1.178.2.2 christos * if we can handle it in interrupt context.
1453 1.178.2.2 christos */
1454 1.178.2.2 christos if (xs->error == XS_NOERROR) {
1455 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1456 1.178.2.2 christos (void) scsipi_complete(xs);
1457 1.178.2.2 christos goto out;
1458 1.178.2.2 christos }
1459 1.178.2.2 christos
1460 1.178.2.2 christos /*
1461 1.178.2.2 christos * There is an error on this xfer. Put it on the channel's
1462 1.178.2.2 christos * completion queue, and wake up the completion thread.
1463 1.178.2.2 christos */
1464 1.178.2.2 christos TAILQ_INSERT_TAIL(&chan->chan_complete, xs, channel_q);
1465 1.178.2.2 christos cv_broadcast(chan_cv_complete(chan));
1466 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1467 1.178.2.2 christos
1468 1.178.2.2 christos out:
1469 1.178.2.2 christos /*
1470 1.178.2.2 christos * If there are more xfers on the channel's queue, attempt to
1471 1.178.2.2 christos * run them.
1472 1.178.2.2 christos */
1473 1.178.2.2 christos scsipi_run_queue(chan);
1474 1.178.2.2 christos }
1475 1.178.2.2 christos
1476 1.178.2.2 christos /*
1477 1.178.2.2 christos * scsipi_complete:
1478 1.178.2.2 christos *
1479 1.178.2.2 christos * Completion of a scsipi_xfer. This is the guts of scsipi_done().
1480 1.178.2.2 christos *
1481 1.178.2.2 christos * NOTE: This routine MUST be called with valid thread context
1482 1.178.2.2 christos * except for the case where the following two conditions are
1483 1.178.2.2 christos * true:
1484 1.178.2.2 christos *
1485 1.178.2.2 christos * xs->error == XS_NOERROR
1486 1.178.2.2 christos * XS_CTL_ASYNC is set in xs->xs_control
1487 1.178.2.2 christos *
1488 1.178.2.2 christos * The semantics of this routine can be tricky, so here is an
1489 1.178.2.2 christos * explanation:
1490 1.178.2.2 christos *
1491 1.178.2.2 christos * 0 Xfer completed successfully.
1492 1.178.2.2 christos *
1493 1.178.2.2 christos * ERESTART Xfer had an error, but was restarted.
1494 1.178.2.2 christos *
1495 1.178.2.2 christos * anything else Xfer had an error, return value is Unix
1496 1.178.2.2 christos * errno.
1497 1.178.2.2 christos *
1498 1.178.2.2 christos * If the return value is anything but ERESTART:
1499 1.178.2.2 christos *
1500 1.178.2.2 christos * - If XS_CTL_ASYNC is set, `xs' has been freed back to
1501 1.178.2.2 christos * the pool.
1502 1.178.2.2 christos * - If there is a buf associated with the xfer,
1503 1.178.2.2 christos * it has been biodone()'d.
1504 1.178.2.2 christos */
1505 1.178.2.2 christos static int
1506 1.178.2.2 christos scsipi_complete(struct scsipi_xfer *xs)
1507 1.178.2.2 christos {
1508 1.178.2.2 christos struct scsipi_periph *periph = xs->xs_periph;
1509 1.178.2.2 christos struct scsipi_channel *chan = periph->periph_channel;
1510 1.178.2.2 christos int error;
1511 1.178.2.2 christos
1512 1.178.2.2 christos #ifdef DIAGNOSTIC
1513 1.178.2.2 christos if ((xs->xs_control & XS_CTL_ASYNC) != 0 && xs->bp == NULL)
1514 1.178.2.2 christos panic("scsipi_complete: XS_CTL_ASYNC but no buf");
1515 1.178.2.2 christos #endif
1516 1.178.2.2 christos /*
1517 1.178.2.2 christos * If command terminated with a CHECK CONDITION, we need to issue a
1518 1.178.2.2 christos * REQUEST_SENSE command. Once the REQUEST_SENSE has been processed
1519 1.178.2.2 christos * we'll have the real status.
1520 1.178.2.2 christos * Must be processed with channel lock held to avoid missing
1521 1.178.2.2 christos * a SCSI bus reset for this command.
1522 1.178.2.2 christos */
1523 1.178.2.2 christos mutex_enter(chan_mtx(chan));
1524 1.178.2.2 christos if (xs->error == XS_BUSY && xs->status == SCSI_CHECK) {
1525 1.178.2.2 christos /* request sense for a request sense ? */
1526 1.178.2.2 christos if (xs->xs_control & XS_CTL_REQSENSE) {
1527 1.178.2.2 christos scsipi_printaddr(periph);
1528 1.178.2.2 christos printf("request sense for a request sense ?\n");
1529 1.178.2.2 christos /* XXX maybe we should reset the device ? */
1530 1.178.2.2 christos /* we've been frozen because xs->error != XS_NOERROR */
1531 1.178.2.2 christos scsipi_periph_thaw_locked(periph, 1);
1532 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1533 1.178.2.2 christos if (xs->resid < xs->datalen) {
1534 1.178.2.2 christos printf("we read %d bytes of sense anyway:\n",
1535 1.178.2.2 christos xs->datalen - xs->resid);
1536 1.178.2.2 christos scsipi_print_sense_data((void *)xs->data, 0);
1537 1.178.2.2 christos }
1538 1.178.2.2 christos return EINVAL;
1539 1.178.2.2 christos }
1540 1.178.2.2 christos mutex_exit(chan_mtx(chan)); // XXX allows other commands to queue or run
1541 1.178.2.2 christos scsipi_request_sense(xs);
1542 1.178.2.2 christos } else
1543 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1544 1.178.2.2 christos
1545 1.178.2.2 christos /*
1546 1.178.2.2 christos * If it's a user level request, bypass all usual completion
1547 1.178.2.2 christos * processing, let the user work it out..
1548 1.178.2.2 christos */
1549 1.178.2.2 christos if ((xs->xs_control & XS_CTL_USERCMD) != 0) {
1550 1.178.2.2 christos SC_DEBUG(periph, SCSIPI_DB3, ("calling user done()\n"));
1551 1.178.2.2 christos mutex_enter(chan_mtx(chan));
1552 1.178.2.2 christos if (xs->error != XS_NOERROR)
1553 1.178.2.2 christos scsipi_periph_thaw_locked(periph, 1);
1554 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1555 1.178.2.2 christos scsipi_user_done(xs);
1556 1.178.2.2 christos SC_DEBUG(periph, SCSIPI_DB3, ("returned from user done()\n "));
1557 1.178.2.2 christos return 0;
1558 1.178.2.2 christos }
1559 1.178.2.2 christos
1560 1.178.2.2 christos switch (xs->error) {
1561 1.178.2.2 christos case XS_NOERROR:
1562 1.178.2.2 christos error = 0;
1563 1.178.2.2 christos break;
1564 1.178.2.2 christos
1565 1.178.2.2 christos case XS_SENSE:
1566 1.178.2.2 christos case XS_SHORTSENSE:
1567 1.178.2.2 christos error = (*chan->chan_bustype->bustype_interpret_sense)(xs);
1568 1.178.2.2 christos break;
1569 1.178.2.2 christos
1570 1.178.2.2 christos case XS_RESOURCE_SHORTAGE:
1571 1.178.2.2 christos /*
1572 1.178.2.2 christos * XXX Should freeze channel's queue.
1573 1.178.2.2 christos */
1574 1.178.2.2 christos scsipi_printaddr(periph);
1575 1.178.2.2 christos printf("adapter resource shortage\n");
1576 1.178.2.2 christos /* FALLTHROUGH */
1577 1.178.2.2 christos
1578 1.178.2.2 christos case XS_BUSY:
1579 1.178.2.2 christos if (xs->error == XS_BUSY && xs->status == SCSI_QUEUE_FULL) {
1580 1.178.2.2 christos struct scsipi_max_openings mo;
1581 1.178.2.2 christos
1582 1.178.2.2 christos /*
1583 1.178.2.2 christos * We set the openings to active - 1, assuming that
1584 1.178.2.2 christos * the command that got us here is the first one that
1585 1.178.2.2 christos * can't fit into the device's queue. If that's not
1586 1.178.2.2 christos * the case, I guess we'll find out soon enough.
1587 1.178.2.2 christos */
1588 1.178.2.2 christos mo.mo_target = periph->periph_target;
1589 1.178.2.2 christos mo.mo_lun = periph->periph_lun;
1590 1.178.2.2 christos if (periph->periph_active < periph->periph_openings)
1591 1.178.2.2 christos mo.mo_openings = periph->periph_active - 1;
1592 1.178.2.2 christos else
1593 1.178.2.2 christos mo.mo_openings = periph->periph_openings - 1;
1594 1.178.2.2 christos #ifdef DIAGNOSTIC
1595 1.178.2.2 christos if (mo.mo_openings < 0) {
1596 1.178.2.2 christos scsipi_printaddr(periph);
1597 1.178.2.2 christos printf("QUEUE FULL resulted in < 0 openings\n");
1598 1.178.2.2 christos panic("scsipi_done");
1599 1.178.2.2 christos }
1600 1.178.2.2 christos #endif
1601 1.178.2.2 christos if (mo.mo_openings == 0) {
1602 1.178.2.2 christos scsipi_printaddr(periph);
1603 1.178.2.2 christos printf("QUEUE FULL resulted in 0 openings\n");
1604 1.178.2.2 christos mo.mo_openings = 1;
1605 1.178.2.2 christos }
1606 1.178.2.2 christos scsipi_async_event(chan, ASYNC_EVENT_MAX_OPENINGS, &mo);
1607 1.178.2.2 christos error = ERESTART;
1608 1.178.2.2 christos } else if (xs->xs_retries != 0) {
1609 1.178.2.2 christos xs->xs_retries--;
1610 1.178.2.2 christos /*
1611 1.178.2.2 christos * Wait one second, and try again.
1612 1.178.2.2 christos */
1613 1.178.2.2 christos mutex_enter(chan_mtx(chan));
1614 1.178.2.2 christos if ((xs->xs_control & XS_CTL_POLL) ||
1615 1.178.2.2 christos (chan->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
1616 1.178.2.2 christos /* XXX: quite extreme */
1617 1.178.2.2 christos kpause("xsbusy", false, hz, chan_mtx(chan));
1618 1.178.2.2 christos } else if (!callout_pending(&periph->periph_callout)) {
1619 1.178.2.2 christos scsipi_periph_freeze_locked(periph, 1);
1620 1.178.2.2 christos callout_reset(&periph->periph_callout,
1621 1.178.2.2 christos hz, scsipi_periph_timed_thaw, periph);
1622 1.178.2.2 christos }
1623 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1624 1.178.2.2 christos error = ERESTART;
1625 1.178.2.2 christos } else
1626 1.178.2.2 christos error = EBUSY;
1627 1.178.2.2 christos break;
1628 1.178.2.2 christos
1629 1.178.2.2 christos case XS_REQUEUE:
1630 1.178.2.2 christos error = ERESTART;
1631 1.178.2.2 christos break;
1632 1.178.2.2 christos
1633 1.178.2.2 christos case XS_SELTIMEOUT:
1634 1.178.2.2 christos case XS_TIMEOUT:
1635 1.178.2.2 christos /*
1636 1.178.2.2 christos * If the device hasn't gone away, honor retry counts.
1637 1.178.2.2 christos *
1638 1.178.2.2 christos * Note that if we're in the middle of probing it,
1639 1.178.2.2 christos * it won't be found because it isn't here yet so
1640 1.178.2.2 christos * we won't honor the retry count in that case.
1641 1.178.2.2 christos */
1642 1.178.2.2 christos if (scsipi_lookup_periph(chan, periph->periph_target,
1643 1.178.2.2 christos periph->periph_lun) && xs->xs_retries != 0) {
1644 1.178.2.2 christos xs->xs_retries--;
1645 1.178.2.2 christos error = ERESTART;
1646 1.178.2.2 christos } else
1647 1.178.2.2 christos error = EIO;
1648 1.178.2.2 christos break;
1649 1.178.2.2 christos
1650 1.178.2.2 christos case XS_RESET:
1651 1.178.2.2 christos if (xs->xs_control & XS_CTL_REQSENSE) {
1652 1.178.2.2 christos /*
1653 1.178.2.2 christos * request sense interrupted by reset: signal it
1654 1.178.2.2 christos * with EINTR return code.
1655 1.178.2.2 christos */
1656 1.178.2.2 christos error = EINTR;
1657 1.178.2.2 christos } else {
1658 1.178.2.2 christos if (xs->xs_retries != 0) {
1659 1.178.2.2 christos xs->xs_retries--;
1660 1.178.2.2 christos error = ERESTART;
1661 1.178.2.2 christos } else
1662 1.178.2.2 christos error = EIO;
1663 1.178.2.2 christos }
1664 1.178.2.2 christos break;
1665 1.178.2.2 christos
1666 1.178.2.2 christos case XS_DRIVER_STUFFUP:
1667 1.178.2.2 christos scsipi_printaddr(periph);
1668 1.178.2.2 christos printf("generic HBA error\n");
1669 1.178.2.2 christos error = EIO;
1670 1.178.2.2 christos break;
1671 1.178.2.2 christos default:
1672 1.178.2.2 christos scsipi_printaddr(periph);
1673 1.178.2.2 christos printf("invalid return code from adapter: %d\n", xs->error);
1674 1.178.2.2 christos error = EIO;
1675 1.178.2.2 christos break;
1676 1.178.2.2 christos }
1677 1.178.2.2 christos
1678 1.178.2.2 christos mutex_enter(chan_mtx(chan));
1679 1.178.2.2 christos if (error == ERESTART) {
1680 1.178.2.2 christos /*
1681 1.178.2.2 christos * If we get here, the periph has been thawed and frozen
1682 1.178.2.2 christos * again if we had to issue recovery commands. Alternatively,
1683 1.178.2.2 christos * it may have been frozen again and in a timed thaw. In
1684 1.178.2.2 christos * any case, we thaw the periph once we re-enqueue the
1685 1.178.2.2 christos * command. Once the periph is fully thawed, it will begin
1686 1.178.2.2 christos * operation again.
1687 1.178.2.2 christos */
1688 1.178.2.2 christos xs->error = XS_NOERROR;
1689 1.178.2.2 christos xs->status = SCSI_OK;
1690 1.178.2.2 christos xs->xs_status &= ~XS_STS_DONE;
1691 1.178.2.2 christos xs->xs_requeuecnt++;
1692 1.178.2.2 christos error = scsipi_enqueue(xs);
1693 1.178.2.2 christos if (error == 0) {
1694 1.178.2.2 christos scsipi_periph_thaw_locked(periph, 1);
1695 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1696 1.178.2.2 christos return ERESTART;
1697 1.178.2.2 christos }
1698 1.178.2.2 christos }
1699 1.178.2.2 christos
1700 1.178.2.2 christos /*
1701 1.178.2.2 christos * scsipi_done() freezes the queue if not XS_NOERROR.
1702 1.178.2.2 christos * Thaw it here.
1703 1.178.2.2 christos */
1704 1.178.2.2 christos if (xs->error != XS_NOERROR)
1705 1.178.2.2 christos scsipi_periph_thaw_locked(periph, 1);
1706 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1707 1.178.2.2 christos
1708 1.178.2.2 christos if (periph->periph_switch->psw_done)
1709 1.178.2.2 christos periph->periph_switch->psw_done(xs, error);
1710 1.178.2.2 christos
1711 1.178.2.2 christos mutex_enter(chan_mtx(chan));
1712 1.178.2.2 christos if (xs->xs_control & XS_CTL_ASYNC)
1713 1.178.2.2 christos scsipi_put_xs(xs);
1714 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1715 1.178.2.2 christos
1716 1.178.2.2 christos return error;
1717 1.178.2.2 christos }
1718 1.178.2.2 christos
1719 1.178.2.2 christos /*
1720 1.178.2.2 christos * Issue a request sense for the given scsipi_xfer. Called when the xfer
1721 1.178.2.2 christos * returns with a CHECK_CONDITION status. Must be called in valid thread
1722 1.178.2.2 christos * context.
1723 1.178.2.2 christos */
1724 1.178.2.2 christos
1725 1.178.2.2 christos static void
1726 1.178.2.2 christos scsipi_request_sense(struct scsipi_xfer *xs)
1727 1.178.2.2 christos {
1728 1.178.2.2 christos struct scsipi_periph *periph = xs->xs_periph;
1729 1.178.2.2 christos int flags, error;
1730 1.178.2.2 christos struct scsi_request_sense cmd;
1731 1.178.2.2 christos
1732 1.178.2.2 christos periph->periph_flags |= PERIPH_SENSE;
1733 1.178.2.2 christos
1734 1.178.2.2 christos /* if command was polling, request sense will too */
1735 1.178.2.2 christos flags = xs->xs_control & XS_CTL_POLL;
1736 1.178.2.2 christos /* Polling commands can't sleep */
1737 1.178.2.2 christos if (flags)
1738 1.178.2.2 christos flags |= XS_CTL_NOSLEEP;
1739 1.178.2.2 christos
1740 1.178.2.2 christos flags |= XS_CTL_REQSENSE | XS_CTL_URGENT | XS_CTL_DATA_IN |
1741 1.178.2.2 christos XS_CTL_THAW_PERIPH | XS_CTL_FREEZE_PERIPH;
1742 1.178.2.2 christos
1743 1.178.2.2 christos memset(&cmd, 0, sizeof(cmd));
1744 1.178.2.2 christos cmd.opcode = SCSI_REQUEST_SENSE;
1745 1.178.2.2 christos cmd.length = sizeof(struct scsi_sense_data);
1746 1.178.2.2 christos
1747 1.178.2.2 christos error = scsipi_command(periph, (void *)&cmd, sizeof(cmd),
1748 1.178.2.2 christos (void *)&xs->sense.scsi_sense, sizeof(struct scsi_sense_data),
1749 1.178.2.2 christos 0, 1000, NULL, flags);
1750 1.178.2.2 christos periph->periph_flags &= ~PERIPH_SENSE;
1751 1.178.2.2 christos periph->periph_xscheck = NULL;
1752 1.178.2.2 christos switch (error) {
1753 1.178.2.2 christos case 0:
1754 1.178.2.2 christos /* we have a valid sense */
1755 1.178.2.2 christos xs->error = XS_SENSE;
1756 1.178.2.2 christos return;
1757 1.178.2.2 christos case EINTR:
1758 1.178.2.2 christos /* REQUEST_SENSE interrupted by bus reset. */
1759 1.178.2.2 christos xs->error = XS_RESET;
1760 1.178.2.2 christos return;
1761 1.178.2.2 christos case EIO:
1762 1.178.2.2 christos /* request sense coudn't be performed */
1763 1.178.2.2 christos /*
1764 1.178.2.2 christos * XXX this isn't quite right but we don't have anything
1765 1.178.2.2 christos * better for now
1766 1.178.2.2 christos */
1767 1.178.2.2 christos xs->error = XS_DRIVER_STUFFUP;
1768 1.178.2.2 christos return;
1769 1.178.2.2 christos default:
1770 1.178.2.2 christos /* Notify that request sense failed. */
1771 1.178.2.2 christos xs->error = XS_DRIVER_STUFFUP;
1772 1.178.2.2 christos scsipi_printaddr(periph);
1773 1.178.2.2 christos printf("request sense failed with error %d\n", error);
1774 1.178.2.2 christos return;
1775 1.178.2.2 christos }
1776 1.178.2.2 christos }
1777 1.178.2.2 christos
1778 1.178.2.2 christos /*
1779 1.178.2.2 christos * scsipi_enqueue:
1780 1.178.2.2 christos *
1781 1.178.2.2 christos * Enqueue an xfer on a channel.
1782 1.178.2.2 christos */
1783 1.178.2.2 christos static int
1784 1.178.2.2 christos scsipi_enqueue(struct scsipi_xfer *xs)
1785 1.178.2.2 christos {
1786 1.178.2.2 christos struct scsipi_channel *chan = xs->xs_periph->periph_channel;
1787 1.178.2.2 christos struct scsipi_xfer *qxs;
1788 1.178.2.2 christos
1789 1.178.2.2 christos /*
1790 1.178.2.2 christos * If the xfer is to be polled, and there are already jobs on
1791 1.178.2.2 christos * the queue, we can't proceed.
1792 1.178.2.2 christos */
1793 1.178.2.2 christos if ((xs->xs_control & XS_CTL_POLL) != 0 &&
1794 1.178.2.2 christos TAILQ_FIRST(&chan->chan_queue) != NULL) {
1795 1.178.2.2 christos xs->error = XS_DRIVER_STUFFUP;
1796 1.178.2.2 christos return EAGAIN;
1797 1.178.2.2 christos }
1798 1.178.2.2 christos
1799 1.178.2.2 christos /*
1800 1.178.2.2 christos * If we have an URGENT xfer, it's an error recovery command
1801 1.178.2.2 christos * and it should just go on the head of the channel's queue.
1802 1.178.2.2 christos */
1803 1.178.2.2 christos if (xs->xs_control & XS_CTL_URGENT) {
1804 1.178.2.2 christos TAILQ_INSERT_HEAD(&chan->chan_queue, xs, channel_q);
1805 1.178.2.2 christos goto out;
1806 1.178.2.2 christos }
1807 1.178.2.2 christos
1808 1.178.2.2 christos /*
1809 1.178.2.2 christos * If this xfer has already been on the queue before, we
1810 1.178.2.2 christos * need to reinsert it in the correct order. That order is:
1811 1.178.2.2 christos *
1812 1.178.2.2 christos * Immediately before the first xfer for this periph
1813 1.178.2.2 christos * with a requeuecnt less than xs->xs_requeuecnt.
1814 1.178.2.2 christos *
1815 1.178.2.2 christos * Failing that, at the end of the queue. (We'll end up
1816 1.178.2.2 christos * there naturally.)
1817 1.178.2.2 christos */
1818 1.178.2.2 christos if (xs->xs_requeuecnt != 0) {
1819 1.178.2.2 christos for (qxs = TAILQ_FIRST(&chan->chan_queue); qxs != NULL;
1820 1.178.2.2 christos qxs = TAILQ_NEXT(qxs, channel_q)) {
1821 1.178.2.2 christos if (qxs->xs_periph == xs->xs_periph &&
1822 1.178.2.2 christos qxs->xs_requeuecnt < xs->xs_requeuecnt)
1823 1.178.2.2 christos break;
1824 1.178.2.2 christos }
1825 1.178.2.2 christos if (qxs != NULL) {
1826 1.178.2.2 christos TAILQ_INSERT_AFTER(&chan->chan_queue, qxs, xs,
1827 1.178.2.2 christos channel_q);
1828 1.178.2.2 christos goto out;
1829 1.178.2.2 christos }
1830 1.178.2.2 christos }
1831 1.178.2.2 christos TAILQ_INSERT_TAIL(&chan->chan_queue, xs, channel_q);
1832 1.178.2.2 christos out:
1833 1.178.2.2 christos if (xs->xs_control & XS_CTL_THAW_PERIPH)
1834 1.178.2.2 christos scsipi_periph_thaw_locked(xs->xs_periph, 1);
1835 1.178.2.2 christos return 0;
1836 1.178.2.2 christos }
1837 1.178.2.2 christos
1838 1.178.2.2 christos /*
1839 1.178.2.2 christos * scsipi_run_queue:
1840 1.178.2.2 christos *
1841 1.178.2.2 christos * Start as many xfers as possible running on the channel.
1842 1.178.2.2 christos */
1843 1.178.2.2 christos static void
1844 1.178.2.2 christos scsipi_run_queue(struct scsipi_channel *chan)
1845 1.178.2.2 christos {
1846 1.178.2.2 christos struct scsipi_xfer *xs;
1847 1.178.2.2 christos struct scsipi_periph *periph;
1848 1.178.2.2 christos
1849 1.178.2.2 christos for (;;) {
1850 1.178.2.2 christos mutex_enter(chan_mtx(chan));
1851 1.178.2.2 christos
1852 1.178.2.2 christos /*
1853 1.178.2.2 christos * If the channel is frozen, we can't do any work right
1854 1.178.2.2 christos * now.
1855 1.178.2.2 christos */
1856 1.178.2.2 christos if (chan->chan_qfreeze != 0) {
1857 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1858 1.178.2.2 christos return;
1859 1.178.2.2 christos }
1860 1.178.2.2 christos
1861 1.178.2.2 christos /*
1862 1.178.2.2 christos * Look for work to do, and make sure we can do it.
1863 1.178.2.2 christos */
1864 1.178.2.2 christos for (xs = TAILQ_FIRST(&chan->chan_queue); xs != NULL;
1865 1.178.2.2 christos xs = TAILQ_NEXT(xs, channel_q)) {
1866 1.178.2.2 christos periph = xs->xs_periph;
1867 1.178.2.2 christos
1868 1.178.2.2 christos if ((periph->periph_sent >= periph->periph_openings) ||
1869 1.178.2.2 christos periph->periph_qfreeze != 0 ||
1870 1.178.2.2 christos (periph->periph_flags & PERIPH_UNTAG) != 0)
1871 1.178.2.2 christos continue;
1872 1.178.2.2 christos
1873 1.178.2.2 christos if ((periph->periph_flags &
1874 1.178.2.2 christos (PERIPH_RECOVERING | PERIPH_SENSE)) != 0 &&
1875 1.178.2.2 christos (xs->xs_control & XS_CTL_URGENT) == 0)
1876 1.178.2.2 christos continue;
1877 1.178.2.2 christos
1878 1.178.2.2 christos /*
1879 1.178.2.2 christos * We can issue this xfer!
1880 1.178.2.2 christos */
1881 1.178.2.2 christos goto got_one;
1882 1.178.2.2 christos }
1883 1.178.2.2 christos
1884 1.178.2.2 christos /*
1885 1.178.2.2 christos * Can't find any work to do right now.
1886 1.178.2.2 christos */
1887 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1888 1.178.2.2 christos return;
1889 1.178.2.2 christos
1890 1.178.2.2 christos got_one:
1891 1.178.2.2 christos /*
1892 1.178.2.2 christos * Have an xfer to run. Allocate a resource from
1893 1.178.2.2 christos * the adapter to run it. If we can't allocate that
1894 1.178.2.2 christos * resource, we don't dequeue the xfer.
1895 1.178.2.2 christos */
1896 1.178.2.2 christos if (scsipi_get_resource(chan) == 0) {
1897 1.178.2.2 christos /*
1898 1.178.2.2 christos * Adapter is out of resources. If the adapter
1899 1.178.2.2 christos * supports it, attempt to grow them.
1900 1.178.2.2 christos */
1901 1.178.2.2 christos if (scsipi_grow_resources(chan) == 0) {
1902 1.178.2.2 christos /*
1903 1.178.2.2 christos * Wasn't able to grow resources,
1904 1.178.2.2 christos * nothing more we can do.
1905 1.178.2.2 christos */
1906 1.178.2.2 christos if (xs->xs_control & XS_CTL_POLL) {
1907 1.178.2.2 christos scsipi_printaddr(xs->xs_periph);
1908 1.178.2.2 christos printf("polling command but no "
1909 1.178.2.2 christos "adapter resources");
1910 1.178.2.2 christos /* We'll panic shortly... */
1911 1.178.2.2 christos }
1912 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1913 1.178.2.2 christos
1914 1.178.2.2 christos /*
1915 1.178.2.2 christos * XXX: We should be able to note that
1916 1.178.2.2 christos * XXX: that resources are needed here!
1917 1.178.2.2 christos */
1918 1.178.2.2 christos return;
1919 1.178.2.2 christos }
1920 1.178.2.2 christos /*
1921 1.178.2.2 christos * scsipi_grow_resources() allocated the resource
1922 1.178.2.2 christos * for us.
1923 1.178.2.2 christos */
1924 1.178.2.2 christos }
1925 1.178.2.2 christos
1926 1.178.2.2 christos /*
1927 1.178.2.2 christos * We have a resource to run this xfer, do it!
1928 1.178.2.2 christos */
1929 1.178.2.2 christos TAILQ_REMOVE(&chan->chan_queue, xs, channel_q);
1930 1.178.2.2 christos
1931 1.178.2.2 christos /*
1932 1.178.2.2 christos * If the command is to be tagged, allocate a tag ID
1933 1.178.2.2 christos * for it.
1934 1.178.2.2 christos */
1935 1.178.2.2 christos if (XS_CTL_TAGTYPE(xs) != 0)
1936 1.178.2.2 christos scsipi_get_tag(xs);
1937 1.178.2.2 christos else
1938 1.178.2.2 christos periph->periph_flags |= PERIPH_UNTAG;
1939 1.178.2.2 christos periph->periph_sent++;
1940 1.178.2.2 christos mutex_exit(chan_mtx(chan));
1941 1.178.2.2 christos
1942 1.178.2.2 christos scsipi_adapter_request(chan, ADAPTER_REQ_RUN_XFER, xs);
1943 1.178.2.2 christos }
1944 1.178.2.2 christos #ifdef DIAGNOSTIC
1945 1.178.2.2 christos panic("scsipi_run_queue: impossible");
1946 1.178.2.2 christos #endif
1947 1.178.2.2 christos }
1948 1.178.2.2 christos
1949 1.178.2.2 christos /*
1950 1.178.2.2 christos * scsipi_execute_xs:
1951 1.178.2.2 christos *
1952 1.178.2.2 christos * Begin execution of an xfer, waiting for it to complete, if necessary.
1953 1.178.2.2 christos */
1954 1.178.2.2 christos int
1955 1.178.2.2 christos scsipi_execute_xs(struct scsipi_xfer *xs)
1956 1.178.2.2 christos {
1957 1.178.2.2 christos struct scsipi_periph *periph = xs->xs_periph;
1958 1.178.2.2 christos struct scsipi_channel *chan = periph->periph_channel;
1959 1.178.2.2 christos int oasync, async, poll, error;
1960 1.178.2.2 christos
1961 1.178.2.2 christos KASSERT(!cold);
1962 1.178.2.2 christos
1963 1.178.2.2 christos (chan->chan_bustype->bustype_cmd)(xs);
1964 1.178.2.2 christos
1965 1.178.2.2 christos xs->xs_status &= ~XS_STS_DONE;
1966 1.178.2.2 christos xs->error = XS_NOERROR;
1967 1.178.2.2 christos xs->resid = xs->datalen;
1968 1.178.2.2 christos xs->status = SCSI_OK;
1969 1.178.2.2 christos
1970 1.178.2.2 christos #ifdef SCSIPI_DEBUG
1971 1.178.2.2 christos if (xs->xs_periph->periph_dbflags & SCSIPI_DB3) {
1972 1.178.2.2 christos printf("scsipi_execute_xs: ");
1973 1.178.2.2 christos show_scsipi_xs(xs);
1974 1.178.2.2 christos printf("\n");
1975 1.178.2.2 christos }
1976 1.178.2.2 christos #endif
1977 1.178.2.2 christos
1978 1.178.2.2 christos /*
1979 1.178.2.2 christos * Deal with command tagging:
1980 1.178.2.2 christos *
1981 1.178.2.2 christos * - If the device's current operating mode doesn't
1982 1.178.2.2 christos * include tagged queueing, clear the tag mask.
1983 1.178.2.2 christos *
1984 1.178.2.2 christos * - If the device's current operating mode *does*
1985 1.178.2.2 christos * include tagged queueing, set the tag_type in
1986 1.178.2.2 christos * the xfer to the appropriate byte for the tag
1987 1.178.2.2 christos * message.
1988 1.178.2.2 christos */
1989 1.178.2.2 christos if ((PERIPH_XFER_MODE(periph) & PERIPH_CAP_TQING) == 0 ||
1990 1.178.2.2 christos (xs->xs_control & XS_CTL_REQSENSE)) {
1991 1.178.2.2 christos xs->xs_control &= ~XS_CTL_TAGMASK;
1992 1.178.2.2 christos xs->xs_tag_type = 0;
1993 1.178.2.2 christos } else {
1994 1.178.2.2 christos /*
1995 1.178.2.2 christos * If the request doesn't specify a tag, give Head
1996 1.178.2.2 christos * tags to URGENT operations and Simple tags to
1997 1.178.2.2 christos * everything else.
1998 1.178.2.2 christos */
1999 1.178.2.2 christos if (XS_CTL_TAGTYPE(xs) == 0) {
2000 1.178.2.2 christos if (xs->xs_control & XS_CTL_URGENT)
2001 1.178.2.2 christos xs->xs_control |= XS_CTL_HEAD_TAG;
2002 1.178.2.2 christos else
2003 1.178.2.2 christos xs->xs_control |= XS_CTL_SIMPLE_TAG;
2004 1.178.2.2 christos }
2005 1.178.2.2 christos
2006 1.178.2.2 christos switch (XS_CTL_TAGTYPE(xs)) {
2007 1.178.2.2 christos case XS_CTL_ORDERED_TAG:
2008 1.178.2.2 christos xs->xs_tag_type = MSG_ORDERED_Q_TAG;
2009 1.178.2.2 christos break;
2010 1.178.2.2 christos
2011 1.178.2.2 christos case XS_CTL_SIMPLE_TAG:
2012 1.178.2.2 christos xs->xs_tag_type = MSG_SIMPLE_Q_TAG;
2013 1.178.2.2 christos break;
2014 1.178.2.2 christos
2015 1.178.2.2 christos case XS_CTL_HEAD_TAG:
2016 1.178.2.2 christos xs->xs_tag_type = MSG_HEAD_OF_Q_TAG;
2017 1.178.2.2 christos break;
2018 1.178.2.2 christos
2019 1.178.2.2 christos default:
2020 1.178.2.2 christos scsipi_printaddr(periph);
2021 1.178.2.2 christos printf("invalid tag mask 0x%08x\n",
2022 1.178.2.2 christos XS_CTL_TAGTYPE(xs));
2023 1.178.2.2 christos panic("scsipi_execute_xs");
2024 1.178.2.2 christos }
2025 1.178.2.2 christos }
2026 1.178.2.2 christos
2027 1.178.2.2 christos /* If the adaptor wants us to poll, poll. */
2028 1.178.2.2 christos if (chan->chan_adapter->adapt_flags & SCSIPI_ADAPT_POLL_ONLY)
2029 1.178.2.2 christos xs->xs_control |= XS_CTL_POLL;
2030 1.178.2.2 christos
2031 1.178.2.2 christos /*
2032 1.178.2.2 christos * If we don't yet have a completion thread, or we are to poll for
2033 1.178.2.2 christos * completion, clear the ASYNC flag.
2034 1.178.2.2 christos */
2035 1.178.2.2 christos oasync = (xs->xs_control & XS_CTL_ASYNC);
2036 1.178.2.2 christos if (chan->chan_thread == NULL || (xs->xs_control & XS_CTL_POLL) != 0)
2037 1.178.2.2 christos xs->xs_control &= ~XS_CTL_ASYNC;
2038 1.178.2.2 christos
2039 1.178.2.2 christos async = (xs->xs_control & XS_CTL_ASYNC);
2040 1.178.2.2 christos poll = (xs->xs_control & XS_CTL_POLL);
2041 1.178.2.2 christos
2042 1.178.2.2 christos #ifdef DIAGNOSTIC
2043 1.178.2.2 christos if (oasync != 0 && xs->bp == NULL)
2044 1.178.2.2 christos panic("scsipi_execute_xs: XS_CTL_ASYNC but no buf");
2045 1.178.2.2 christos #endif
2046 1.178.2.2 christos
2047 1.178.2.2 christos /*
2048 1.178.2.2 christos * Enqueue the transfer. If we're not polling for completion, this
2049 1.178.2.2 christos * should ALWAYS return `no error'.
2050 1.178.2.2 christos */
2051 1.178.2.2 christos error = scsipi_enqueue(xs);
2052 1.178.2.2 christos if (error) {
2053 1.178.2.2 christos if (poll == 0) {
2054 1.178.2.2 christos scsipi_printaddr(periph);
2055 1.178.2.2 christos printf("not polling, but enqueue failed with %d\n",
2056 1.178.2.2 christos error);
2057 1.178.2.2 christos panic("scsipi_execute_xs");
2058 1.178.2.2 christos }
2059 1.178.2.2 christos
2060 1.178.2.2 christos scsipi_printaddr(periph);
2061 1.178.2.2 christos printf("should have flushed queue?\n");
2062 1.178.2.2 christos goto free_xs;
2063 1.178.2.2 christos }
2064 1.178.2.2 christos
2065 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2066 1.178.2.2 christos restarted:
2067 1.178.2.2 christos scsipi_run_queue(chan);
2068 1.178.2.2 christos mutex_enter(chan_mtx(chan));
2069 1.178.2.2 christos
2070 1.178.2.2 christos /*
2071 1.178.2.2 christos * The xfer is enqueued, and possibly running. If it's to be
2072 1.178.2.2 christos * completed asynchronously, just return now.
2073 1.178.2.2 christos */
2074 1.178.2.2 christos if (async)
2075 1.178.2.2 christos return 0;
2076 1.178.2.2 christos
2077 1.178.2.2 christos /*
2078 1.178.2.2 christos * Not an asynchronous command; wait for it to complete.
2079 1.178.2.2 christos */
2080 1.178.2.2 christos while ((xs->xs_status & XS_STS_DONE) == 0) {
2081 1.178.2.2 christos if (poll) {
2082 1.178.2.2 christos scsipi_printaddr(periph);
2083 1.178.2.2 christos printf("polling command not done\n");
2084 1.178.2.2 christos panic("scsipi_execute_xs");
2085 1.178.2.2 christos }
2086 1.178.2.2 christos cv_wait(xs_cv(xs), chan_mtx(chan));
2087 1.178.2.2 christos }
2088 1.178.2.2 christos
2089 1.178.2.2 christos /*
2090 1.178.2.2 christos * Command is complete. scsipi_done() has awakened us to perform
2091 1.178.2.2 christos * the error handling.
2092 1.178.2.2 christos */
2093 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2094 1.178.2.2 christos error = scsipi_complete(xs);
2095 1.178.2.2 christos if (error == ERESTART)
2096 1.178.2.2 christos goto restarted;
2097 1.178.2.2 christos
2098 1.178.2.2 christos /*
2099 1.178.2.2 christos * If it was meant to run async and we cleared aync ourselve,
2100 1.178.2.2 christos * don't return an error here. It has already been handled
2101 1.178.2.2 christos */
2102 1.178.2.2 christos if (oasync)
2103 1.178.2.2 christos error = 0;
2104 1.178.2.2 christos /*
2105 1.178.2.2 christos * Command completed successfully or fatal error occurred. Fall
2106 1.178.2.2 christos * into....
2107 1.178.2.2 christos */
2108 1.178.2.2 christos mutex_enter(chan_mtx(chan));
2109 1.178.2.2 christos free_xs:
2110 1.178.2.2 christos scsipi_put_xs(xs);
2111 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2112 1.178.2.2 christos
2113 1.178.2.2 christos /*
2114 1.178.2.2 christos * Kick the queue, keep it running in case it stopped for some
2115 1.178.2.2 christos * reason.
2116 1.178.2.2 christos */
2117 1.178.2.2 christos scsipi_run_queue(chan);
2118 1.178.2.2 christos
2119 1.178.2.2 christos mutex_enter(chan_mtx(chan));
2120 1.178.2.2 christos return error;
2121 1.178.2.2 christos }
2122 1.178.2.2 christos
2123 1.178.2.2 christos /*
2124 1.178.2.2 christos * scsipi_completion_thread:
2125 1.178.2.2 christos *
2126 1.178.2.2 christos * This is the completion thread. We wait for errors on
2127 1.178.2.2 christos * asynchronous xfers, and perform the error handling
2128 1.178.2.2 christos * function, restarting the command, if necessary.
2129 1.178.2.2 christos */
2130 1.178.2.2 christos static void
2131 1.178.2.2 christos scsipi_completion_thread(void *arg)
2132 1.178.2.2 christos {
2133 1.178.2.2 christos struct scsipi_channel *chan = arg;
2134 1.178.2.2 christos struct scsipi_xfer *xs;
2135 1.178.2.2 christos
2136 1.178.2.2 christos if (chan->chan_init_cb)
2137 1.178.2.2 christos (*chan->chan_init_cb)(chan, chan->chan_init_cb_arg);
2138 1.178.2.2 christos
2139 1.178.2.2 christos mutex_enter(chan_mtx(chan));
2140 1.178.2.2 christos chan->chan_flags |= SCSIPI_CHAN_TACTIVE;
2141 1.178.2.2 christos for (;;) {
2142 1.178.2.2 christos xs = TAILQ_FIRST(&chan->chan_complete);
2143 1.178.2.2 christos if (xs == NULL && chan->chan_tflags == 0) {
2144 1.178.2.2 christos /* nothing to do; wait */
2145 1.178.2.2 christos cv_wait(chan_cv_complete(chan), chan_mtx(chan));
2146 1.178.2.2 christos continue;
2147 1.178.2.2 christos }
2148 1.178.2.2 christos if (chan->chan_tflags & SCSIPI_CHANT_CALLBACK) {
2149 1.178.2.2 christos /* call chan_callback from thread context */
2150 1.178.2.2 christos chan->chan_tflags &= ~SCSIPI_CHANT_CALLBACK;
2151 1.178.2.2 christos chan->chan_callback(chan, chan->chan_callback_arg);
2152 1.178.2.2 christos continue;
2153 1.178.2.2 christos }
2154 1.178.2.2 christos if (chan->chan_tflags & SCSIPI_CHANT_GROWRES) {
2155 1.178.2.2 christos /* attempt to get more openings for this channel */
2156 1.178.2.2 christos chan->chan_tflags &= ~SCSIPI_CHANT_GROWRES;
2157 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2158 1.178.2.2 christos scsipi_adapter_request(chan,
2159 1.178.2.2 christos ADAPTER_REQ_GROW_RESOURCES, NULL);
2160 1.178.2.2 christos scsipi_channel_thaw(chan, 1);
2161 1.178.2.2 christos if (chan->chan_tflags & SCSIPI_CHANT_GROWRES)
2162 1.178.2.2 christos kpause("scsizzz", FALSE, hz/10, NULL);
2163 1.178.2.2 christos mutex_enter(chan_mtx(chan));
2164 1.178.2.2 christos continue;
2165 1.178.2.2 christos }
2166 1.178.2.2 christos if (chan->chan_tflags & SCSIPI_CHANT_KICK) {
2167 1.178.2.2 christos /* explicitly run the queues for this channel */
2168 1.178.2.2 christos chan->chan_tflags &= ~SCSIPI_CHANT_KICK;
2169 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2170 1.178.2.2 christos scsipi_run_queue(chan);
2171 1.178.2.2 christos mutex_enter(chan_mtx(chan));
2172 1.178.2.2 christos continue;
2173 1.178.2.2 christos }
2174 1.178.2.2 christos if (chan->chan_tflags & SCSIPI_CHANT_SHUTDOWN) {
2175 1.178.2.2 christos break;
2176 1.178.2.2 christos }
2177 1.178.2.2 christos if (xs) {
2178 1.178.2.2 christos TAILQ_REMOVE(&chan->chan_complete, xs, channel_q);
2179 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2180 1.178.2.2 christos
2181 1.178.2.2 christos /*
2182 1.178.2.2 christos * Have an xfer with an error; process it.
2183 1.178.2.2 christos */
2184 1.178.2.2 christos (void) scsipi_complete(xs);
2185 1.178.2.2 christos
2186 1.178.2.2 christos /*
2187 1.178.2.2 christos * Kick the queue; keep it running if it was stopped
2188 1.178.2.2 christos * for some reason.
2189 1.178.2.2 christos */
2190 1.178.2.2 christos scsipi_run_queue(chan);
2191 1.178.2.2 christos mutex_enter(chan_mtx(chan));
2192 1.178.2.2 christos }
2193 1.178.2.2 christos }
2194 1.178.2.2 christos
2195 1.178.2.2 christos chan->chan_thread = NULL;
2196 1.178.2.2 christos
2197 1.178.2.2 christos /* In case parent is waiting for us to exit. */
2198 1.178.2.2 christos cv_broadcast(chan_cv_thread(chan));
2199 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2200 1.178.2.2 christos
2201 1.178.2.2 christos kthread_exit(0);
2202 1.178.2.2 christos }
2203 1.178.2.2 christos /*
2204 1.178.2.2 christos * scsipi_thread_call_callback:
2205 1.178.2.2 christos *
2206 1.178.2.2 christos * request to call a callback from the completion thread
2207 1.178.2.2 christos */
2208 1.178.2.2 christos int
2209 1.178.2.2 christos scsipi_thread_call_callback(struct scsipi_channel *chan,
2210 1.178.2.2 christos void (*callback)(struct scsipi_channel *, void *), void *arg)
2211 1.178.2.2 christos {
2212 1.178.2.2 christos
2213 1.178.2.2 christos mutex_enter(chan_mtx(chan));
2214 1.178.2.2 christos if ((chan->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
2215 1.178.2.2 christos /* kernel thread doesn't exist yet */
2216 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2217 1.178.2.2 christos return ESRCH;
2218 1.178.2.2 christos }
2219 1.178.2.2 christos if (chan->chan_tflags & SCSIPI_CHANT_CALLBACK) {
2220 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2221 1.178.2.2 christos return EBUSY;
2222 1.178.2.2 christos }
2223 1.178.2.2 christos scsipi_channel_freeze(chan, 1);
2224 1.178.2.2 christos chan->chan_callback = callback;
2225 1.178.2.2 christos chan->chan_callback_arg = arg;
2226 1.178.2.2 christos chan->chan_tflags |= SCSIPI_CHANT_CALLBACK;
2227 1.178.2.2 christos cv_broadcast(chan_cv_complete(chan));
2228 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2229 1.178.2.2 christos return 0;
2230 1.178.2.2 christos }
2231 1.178.2.2 christos
2232 1.178.2.2 christos /*
2233 1.178.2.2 christos * scsipi_async_event:
2234 1.178.2.2 christos *
2235 1.178.2.2 christos * Handle an asynchronous event from an adapter.
2236 1.178.2.2 christos */
2237 1.178.2.2 christos void
2238 1.178.2.2 christos scsipi_async_event(struct scsipi_channel *chan, scsipi_async_event_t event,
2239 1.178.2.2 christos void *arg)
2240 1.178.2.2 christos {
2241 1.178.2.2 christos bool lock = chan_running(chan) > 0;
2242 1.178.2.2 christos
2243 1.178.2.2 christos if (lock)
2244 1.178.2.2 christos mutex_enter(chan_mtx(chan));
2245 1.178.2.2 christos switch (event) {
2246 1.178.2.2 christos case ASYNC_EVENT_MAX_OPENINGS:
2247 1.178.2.2 christos scsipi_async_event_max_openings(chan,
2248 1.178.2.2 christos (struct scsipi_max_openings *)arg);
2249 1.178.2.2 christos break;
2250 1.178.2.2 christos
2251 1.178.2.2 christos case ASYNC_EVENT_XFER_MODE:
2252 1.178.2.2 christos if (chan->chan_bustype->bustype_async_event_xfer_mode) {
2253 1.178.2.2 christos chan->chan_bustype->bustype_async_event_xfer_mode(
2254 1.178.2.2 christos chan, arg);
2255 1.178.2.2 christos }
2256 1.178.2.2 christos break;
2257 1.178.2.2 christos case ASYNC_EVENT_RESET:
2258 1.178.2.2 christos scsipi_async_event_channel_reset(chan);
2259 1.178.2.2 christos break;
2260 1.178.2.2 christos }
2261 1.178.2.2 christos if (lock)
2262 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2263 1.178.2.2 christos }
2264 1.178.2.2 christos
2265 1.178.2.2 christos /*
2266 1.178.2.2 christos * scsipi_async_event_max_openings:
2267 1.178.2.2 christos *
2268 1.178.2.2 christos * Update the maximum number of outstanding commands a
2269 1.178.2.2 christos * device may have.
2270 1.178.2.2 christos */
2271 1.178.2.2 christos static void
2272 1.178.2.2 christos scsipi_async_event_max_openings(struct scsipi_channel *chan,
2273 1.178.2.2 christos struct scsipi_max_openings *mo)
2274 1.178.2.2 christos {
2275 1.178.2.2 christos struct scsipi_periph *periph;
2276 1.178.2.2 christos int minlun, maxlun;
2277 1.178.2.2 christos
2278 1.178.2.2 christos if (mo->mo_lun == -1) {
2279 1.178.2.2 christos /*
2280 1.178.2.2 christos * Wildcarded; apply it to all LUNs.
2281 1.178.2.2 christos */
2282 1.178.2.2 christos minlun = 0;
2283 1.178.2.2 christos maxlun = chan->chan_nluns - 1;
2284 1.178.2.2 christos } else
2285 1.178.2.2 christos minlun = maxlun = mo->mo_lun;
2286 1.178.2.2 christos
2287 1.178.2.2 christos /* XXX This could really suck with a large LUN space. */
2288 1.178.2.2 christos for (; minlun <= maxlun; minlun++) {
2289 1.178.2.2 christos periph = scsipi_lookup_periph_locked(chan, mo->mo_target, minlun);
2290 1.178.2.2 christos if (periph == NULL)
2291 1.178.2.2 christos continue;
2292 1.178.2.2 christos
2293 1.178.2.2 christos if (mo->mo_openings < periph->periph_openings)
2294 1.178.2.2 christos periph->periph_openings = mo->mo_openings;
2295 1.178.2.2 christos else if (mo->mo_openings > periph->periph_openings &&
2296 1.178.2.2 christos (periph->periph_flags & PERIPH_GROW_OPENINGS) != 0)
2297 1.178.2.2 christos periph->periph_openings = mo->mo_openings;
2298 1.178.2.2 christos }
2299 1.178.2.2 christos }
2300 1.178.2.2 christos
2301 1.178.2.2 christos /*
2302 1.178.2.2 christos * scsipi_set_xfer_mode:
2303 1.178.2.2 christos *
2304 1.178.2.2 christos * Set the xfer mode for the specified I_T Nexus.
2305 1.178.2.2 christos */
2306 1.178.2.2 christos void
2307 1.178.2.2 christos scsipi_set_xfer_mode(struct scsipi_channel *chan, int target, int immed)
2308 1.178.2.2 christos {
2309 1.178.2.2 christos struct scsipi_xfer_mode xm;
2310 1.178.2.2 christos struct scsipi_periph *itperiph;
2311 1.178.2.2 christos int lun;
2312 1.178.2.2 christos
2313 1.178.2.2 christos /*
2314 1.178.2.2 christos * Go to the minimal xfer mode.
2315 1.178.2.2 christos */
2316 1.178.2.2 christos xm.xm_target = target;
2317 1.178.2.2 christos xm.xm_mode = 0;
2318 1.178.2.2 christos xm.xm_period = 0; /* ignored */
2319 1.178.2.2 christos xm.xm_offset = 0; /* ignored */
2320 1.178.2.2 christos
2321 1.178.2.2 christos /*
2322 1.178.2.2 christos * Find the first LUN we know about on this I_T Nexus.
2323 1.178.2.2 christos */
2324 1.178.2.2 christos for (itperiph = NULL, lun = 0; lun < chan->chan_nluns; lun++) {
2325 1.178.2.2 christos itperiph = scsipi_lookup_periph(chan, target, lun);
2326 1.178.2.2 christos if (itperiph != NULL)
2327 1.178.2.2 christos break;
2328 1.178.2.2 christos }
2329 1.178.2.2 christos if (itperiph != NULL) {
2330 1.178.2.2 christos xm.xm_mode = itperiph->periph_cap;
2331 1.178.2.2 christos /*
2332 1.178.2.2 christos * Now issue the request to the adapter.
2333 1.178.2.2 christos */
2334 1.178.2.2 christos scsipi_adapter_request(chan, ADAPTER_REQ_SET_XFER_MODE, &xm);
2335 1.178.2.2 christos /*
2336 1.178.2.2 christos * If we want this to happen immediately, issue a dummy
2337 1.178.2.2 christos * command, since most adapters can't really negotiate unless
2338 1.178.2.2 christos * they're executing a job.
2339 1.178.2.2 christos */
2340 1.178.2.2 christos if (immed != 0) {
2341 1.178.2.2 christos (void) scsipi_test_unit_ready(itperiph,
2342 1.178.2.2 christos XS_CTL_DISCOVERY | XS_CTL_IGNORE_ILLEGAL_REQUEST |
2343 1.178.2.2 christos XS_CTL_IGNORE_NOT_READY |
2344 1.178.2.2 christos XS_CTL_IGNORE_MEDIA_CHANGE);
2345 1.178.2.2 christos }
2346 1.178.2.2 christos }
2347 1.178.2.2 christos }
2348 1.178.2.2 christos
2349 1.178.2.2 christos /*
2350 1.178.2.2 christos * scsipi_channel_reset:
2351 1.178.2.2 christos *
2352 1.178.2.2 christos * handle scsi bus reset
2353 1.178.2.2 christos * called with channel lock held
2354 1.178.2.2 christos */
2355 1.178.2.2 christos static void
2356 1.178.2.2 christos scsipi_async_event_channel_reset(struct scsipi_channel *chan)
2357 1.178.2.2 christos {
2358 1.178.2.2 christos struct scsipi_xfer *xs, *xs_next;
2359 1.178.2.2 christos struct scsipi_periph *periph;
2360 1.178.2.2 christos int target, lun;
2361 1.178.2.2 christos
2362 1.178.2.2 christos /*
2363 1.178.2.2 christos * Channel has been reset. Also mark as reset pending REQUEST_SENSE
2364 1.178.2.2 christos * commands; as the sense is not available any more.
2365 1.178.2.2 christos * can't call scsipi_done() from here, as the command has not been
2366 1.178.2.2 christos * sent to the adapter yet (this would corrupt accounting).
2367 1.178.2.2 christos */
2368 1.178.2.2 christos
2369 1.178.2.2 christos for (xs = TAILQ_FIRST(&chan->chan_queue); xs != NULL; xs = xs_next) {
2370 1.178.2.2 christos xs_next = TAILQ_NEXT(xs, channel_q);
2371 1.178.2.2 christos if (xs->xs_control & XS_CTL_REQSENSE) {
2372 1.178.2.2 christos TAILQ_REMOVE(&chan->chan_queue, xs, channel_q);
2373 1.178.2.2 christos xs->error = XS_RESET;
2374 1.178.2.2 christos if ((xs->xs_control & XS_CTL_ASYNC) != 0)
2375 1.178.2.2 christos TAILQ_INSERT_TAIL(&chan->chan_complete, xs,
2376 1.178.2.2 christos channel_q);
2377 1.178.2.2 christos }
2378 1.178.2.2 christos }
2379 1.178.2.2 christos cv_broadcast(chan_cv_complete(chan));
2380 1.178.2.2 christos /* Catch xs with pending sense which may not have a REQSENSE xs yet */
2381 1.178.2.2 christos for (target = 0; target < chan->chan_ntargets; target++) {
2382 1.178.2.2 christos if (target == chan->chan_id)
2383 1.178.2.2 christos continue;
2384 1.178.2.2 christos for (lun = 0; lun < chan->chan_nluns; lun++) {
2385 1.178.2.2 christos periph = scsipi_lookup_periph_locked(chan, target, lun);
2386 1.178.2.2 christos if (periph) {
2387 1.178.2.2 christos xs = periph->periph_xscheck;
2388 1.178.2.2 christos if (xs)
2389 1.178.2.2 christos xs->error = XS_RESET;
2390 1.178.2.2 christos }
2391 1.178.2.2 christos }
2392 1.178.2.2 christos }
2393 1.178.2.2 christos }
2394 1.178.2.2 christos
2395 1.178.2.2 christos /*
2396 1.178.2.2 christos * scsipi_target_detach:
2397 1.178.2.2 christos *
2398 1.178.2.2 christos * detach all periph associated with a I_T
2399 1.178.2.2 christos * must be called from valid thread context
2400 1.178.2.2 christos */
2401 1.178.2.2 christos int
2402 1.178.2.2 christos scsipi_target_detach(struct scsipi_channel *chan, int target, int lun,
2403 1.178.2.2 christos int flags)
2404 1.178.2.2 christos {
2405 1.178.2.2 christos struct scsipi_periph *periph;
2406 1.178.2.2 christos device_t tdev;
2407 1.178.2.2 christos int ctarget, mintarget, maxtarget;
2408 1.178.2.2 christos int clun, minlun, maxlun;
2409 1.178.2.2 christos int error = 0;
2410 1.178.2.2 christos
2411 1.178.2.2 christos if (target == -1) {
2412 1.178.2.2 christos mintarget = 0;
2413 1.178.2.2 christos maxtarget = chan->chan_ntargets;
2414 1.178.2.2 christos } else {
2415 1.178.2.2 christos if (target == chan->chan_id)
2416 1.178.2.2 christos return EINVAL;
2417 1.178.2.2 christos if (target < 0 || target >= chan->chan_ntargets)
2418 1.178.2.2 christos return EINVAL;
2419 1.178.2.2 christos mintarget = target;
2420 1.178.2.2 christos maxtarget = target + 1;
2421 1.178.2.2 christos }
2422 1.178.2.2 christos
2423 1.178.2.2 christos if (lun == -1) {
2424 1.178.2.2 christos minlun = 0;
2425 1.178.2.2 christos maxlun = chan->chan_nluns;
2426 1.178.2.2 christos } else {
2427 1.178.2.2 christos if (lun < 0 || lun >= chan->chan_nluns)
2428 1.178.2.2 christos return EINVAL;
2429 1.178.2.2 christos minlun = lun;
2430 1.178.2.2 christos maxlun = lun + 1;
2431 1.178.2.2 christos }
2432 1.178.2.2 christos
2433 1.178.2.2 christos /* for config_detach */
2434 1.178.2.2 christos KERNEL_LOCK(1, curlwp);
2435 1.178.2.2 christos
2436 1.178.2.2 christos mutex_enter(chan_mtx(chan));
2437 1.178.2.2 christos for (ctarget = mintarget; ctarget < maxtarget; ctarget++) {
2438 1.178.2.2 christos if (ctarget == chan->chan_id)
2439 1.178.2.2 christos continue;
2440 1.178.2.2 christos
2441 1.178.2.2 christos for (clun = minlun; clun < maxlun; clun++) {
2442 1.178.2.2 christos periph = scsipi_lookup_periph_locked(chan, ctarget, clun);
2443 1.178.2.2 christos if (periph == NULL)
2444 1.178.2.2 christos continue;
2445 1.178.2.2 christos tdev = periph->periph_dev;
2446 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2447 1.178.2.2 christos error = config_detach(tdev, flags);
2448 1.178.2.2 christos if (error)
2449 1.178.2.2 christos goto out;
2450 1.178.2.2 christos mutex_enter(chan_mtx(chan));
2451 1.178.2.2 christos KASSERT(scsipi_lookup_periph_locked(chan, ctarget, clun) == NULL);
2452 1.178.2.2 christos }
2453 1.178.2.2 christos }
2454 1.178.2.2 christos mutex_exit(chan_mtx(chan));
2455 1.178.2.2 christos
2456 1.178.2.2 christos out:
2457 1.178.2.2 christos KERNEL_UNLOCK_ONE(curlwp);
2458 1.178.2.2 christos
2459 1.178.2.2 christos return error;
2460 1.178.2.2 christos }
2461 1.178.2.2 christos
2462 1.178.2.2 christos /*
2463 1.178.2.2 christos * scsipi_adapter_addref:
2464 1.178.2.2 christos *
2465 1.178.2.2 christos * Add a reference to the adapter pointed to by the provided
2466 1.178.2.2 christos * link, enabling the adapter if necessary.
2467 1.178.2.2 christos */
2468 1.178.2.2 christos int
2469 1.178.2.2 christos scsipi_adapter_addref(struct scsipi_adapter *adapt)
2470 1.178.2.2 christos {
2471 1.178.2.2 christos int error = 0;
2472 1.178.2.2 christos
2473 1.178.2.2 christos if (atomic_inc_uint_nv(&adapt->adapt_refcnt) == 1
2474 1.178.2.2 christos && adapt->adapt_enable != NULL) {
2475 1.178.2.2 christos scsipi_adapter_lock(adapt);
2476 1.178.2.2 christos error = scsipi_adapter_enable(adapt, 1);
2477 1.178.2.2 christos scsipi_adapter_unlock(adapt);
2478 1.178.2.2 christos if (error)
2479 1.178.2.2 christos atomic_dec_uint(&adapt->adapt_refcnt);
2480 1.178.2.2 christos }
2481 1.178.2.2 christos return error;
2482 1.178.2.2 christos }
2483 1.178.2.2 christos
2484 1.178.2.2 christos /*
2485 1.178.2.2 christos * scsipi_adapter_delref:
2486 1.178.2.2 christos *
2487 1.178.2.2 christos * Delete a reference to the adapter pointed to by the provided
2488 1.178.2.2 christos * link, disabling the adapter if possible.
2489 1.178.2.2 christos */
2490 1.178.2.2 christos void
2491 1.178.2.2 christos scsipi_adapter_delref(struct scsipi_adapter *adapt)
2492 1.178.2.2 christos {
2493 1.178.2.2 christos
2494 1.178.2.2 christos if (atomic_dec_uint_nv(&adapt->adapt_refcnt) == 0
2495 1.178.2.2 christos && adapt->adapt_enable != NULL) {
2496 1.178.2.2 christos scsipi_adapter_lock(adapt);
2497 1.178.2.2 christos (void) scsipi_adapter_enable(adapt, 0);
2498 1.178.2.2 christos scsipi_adapter_unlock(adapt);
2499 1.178.2.2 christos }
2500 1.178.2.2 christos }
2501 1.178.2.2 christos
2502 1.178.2.2 christos static struct scsipi_syncparam {
2503 1.178.2.2 christos int ss_factor;
2504 1.178.2.2 christos int ss_period; /* ns * 100 */
2505 1.178.2.2 christos } scsipi_syncparams[] = {
2506 1.178.2.2 christos { 0x08, 625 }, /* FAST-160 (Ultra320) */
2507 1.178.2.2 christos { 0x09, 1250 }, /* FAST-80 (Ultra160) */
2508 1.178.2.2 christos { 0x0a, 2500 }, /* FAST-40 40MHz (Ultra2) */
2509 1.178.2.2 christos { 0x0b, 3030 }, /* FAST-40 33MHz (Ultra2) */
2510 1.178.2.2 christos { 0x0c, 5000 }, /* FAST-20 (Ultra) */
2511 1.178.2.2 christos };
2512 1.178.2.2 christos static const int scsipi_nsyncparams =
2513 1.178.2.2 christos sizeof(scsipi_syncparams) / sizeof(scsipi_syncparams[0]);
2514 1.178.2.2 christos
2515 1.178.2.2 christos int
2516 1.178.2.2 christos scsipi_sync_period_to_factor(int period /* ns * 100 */)
2517 1.178.2.2 christos {
2518 1.178.2.2 christos int i;
2519 1.178.2.2 christos
2520 1.178.2.2 christos for (i = 0; i < scsipi_nsyncparams; i++) {
2521 1.178.2.2 christos if (period <= scsipi_syncparams[i].ss_period)
2522 1.178.2.2 christos return scsipi_syncparams[i].ss_factor;
2523 1.178.2.2 christos }
2524 1.178.2.2 christos
2525 1.178.2.2 christos return (period / 100) / 4;
2526 1.178.2.2 christos }
2527 1.178.2.2 christos
2528 1.178.2.2 christos int
2529 1.178.2.2 christos scsipi_sync_factor_to_period(int factor)
2530 1.178.2.2 christos {
2531 1.178.2.2 christos int i;
2532 1.178.2.2 christos
2533 1.178.2.2 christos for (i = 0; i < scsipi_nsyncparams; i++) {
2534 1.178.2.2 christos if (factor == scsipi_syncparams[i].ss_factor)
2535 1.178.2.2 christos return scsipi_syncparams[i].ss_period;
2536 1.178.2.2 christos }
2537 1.178.2.2 christos
2538 1.178.2.2 christos return (factor * 4) * 100;
2539 1.178.2.2 christos }
2540 1.178.2.2 christos
2541 1.178.2.2 christos int
2542 1.178.2.2 christos scsipi_sync_factor_to_freq(int factor)
2543 1.178.2.2 christos {
2544 1.178.2.2 christos int i;
2545 1.178.2.2 christos
2546 1.178.2.2 christos for (i = 0; i < scsipi_nsyncparams; i++) {
2547 1.178.2.2 christos if (factor == scsipi_syncparams[i].ss_factor)
2548 1.178.2.2 christos return 100000000 / scsipi_syncparams[i].ss_period;
2549 1.178.2.2 christos }
2550 1.178.2.2 christos
2551 1.178.2.2 christos return 10000000 / ((factor * 4) * 10);
2552 1.178.2.2 christos }
2553 1.178.2.2 christos
2554 1.178.2.2 christos static inline void
2555 1.178.2.2 christos scsipi_adapter_lock(struct scsipi_adapter *adapt)
2556 1.178.2.2 christos {
2557 1.178.2.2 christos
2558 1.178.2.2 christos if ((adapt->adapt_flags & SCSIPI_ADAPT_MPSAFE) == 0)
2559 1.178.2.2 christos KERNEL_LOCK(1, NULL);
2560 1.178.2.2 christos }
2561 1.178.2.2 christos
2562 1.178.2.2 christos static inline void
2563 1.178.2.2 christos scsipi_adapter_unlock(struct scsipi_adapter *adapt)
2564 1.178.2.2 christos {
2565 1.178.2.2 christos
2566 1.178.2.2 christos if ((adapt->adapt_flags & SCSIPI_ADAPT_MPSAFE) == 0)
2567 1.178.2.2 christos KERNEL_UNLOCK_ONE(NULL);
2568 1.178.2.2 christos }
2569 1.178.2.2 christos
2570 1.178.2.2 christos void
2571 1.178.2.2 christos scsipi_adapter_minphys(struct scsipi_channel *chan, struct buf *bp)
2572 1.178.2.2 christos {
2573 1.178.2.2 christos struct scsipi_adapter *adapt = chan->chan_adapter;
2574 1.178.2.2 christos
2575 1.178.2.2 christos scsipi_adapter_lock(adapt);
2576 1.178.2.2 christos (adapt->adapt_minphys)(bp);
2577 1.178.2.2 christos scsipi_adapter_unlock(chan->chan_adapter);
2578 1.178.2.2 christos }
2579 1.178.2.2 christos
2580 1.178.2.2 christos void
2581 1.178.2.2 christos scsipi_adapter_request(struct scsipi_channel *chan,
2582 1.178.2.2 christos scsipi_adapter_req_t req, void *arg)
2583 1.178.2.2 christos
2584 1.178.2.2 christos {
2585 1.178.2.2 christos struct scsipi_adapter *adapt = chan->chan_adapter;
2586 1.178.2.2 christos
2587 1.178.2.2 christos scsipi_adapter_lock(adapt);
2588 1.178.2.2 christos (adapt->adapt_request)(chan, req, arg);
2589 1.178.2.2 christos scsipi_adapter_unlock(adapt);
2590 1.178.2.2 christos }
2591 1.178.2.2 christos
2592 1.178.2.2 christos int
2593 1.178.2.2 christos scsipi_adapter_ioctl(struct scsipi_channel *chan, u_long cmd,
2594 1.178.2.2 christos void *data, int flag, struct proc *p)
2595 1.178.2.2 christos {
2596 1.178.2.2 christos struct scsipi_adapter *adapt = chan->chan_adapter;
2597 1.178.2.2 christos int error;
2598 1.178.2.2 christos
2599 1.178.2.2 christos if (adapt->adapt_ioctl == NULL)
2600 1.178.2.2 christos return ENOTTY;
2601 1.178.2.2 christos
2602 1.178.2.2 christos scsipi_adapter_lock(adapt);
2603 1.178.2.2 christos error = (adapt->adapt_ioctl)(chan, cmd, data, flag, p);
2604 1.178.2.2 christos scsipi_adapter_unlock(adapt);
2605 1.178.2.2 christos return error;
2606 1.178.2.2 christos }
2607 1.178.2.2 christos
2608 1.178.2.2 christos int
2609 1.178.2.2 christos scsipi_adapter_enable(struct scsipi_adapter *adapt, int enable)
2610 1.178.2.2 christos {
2611 1.178.2.2 christos int error;
2612 1.178.2.2 christos
2613 1.178.2.2 christos scsipi_adapter_lock(adapt);
2614 1.178.2.2 christos error = (adapt->adapt_enable)(adapt->adapt_dev, enable);
2615 1.178.2.2 christos scsipi_adapter_unlock(adapt);
2616 1.178.2.2 christos return error;
2617 1.178.2.2 christos }
2618 1.178.2.2 christos
2619 1.178.2.2 christos #ifdef SCSIPI_DEBUG
2620 1.178.2.2 christos /*
2621 1.178.2.2 christos * Given a scsipi_xfer, dump the request, in all its glory
2622 1.178.2.2 christos */
2623 1.178.2.2 christos void
2624 1.178.2.2 christos show_scsipi_xs(struct scsipi_xfer *xs)
2625 1.178.2.2 christos {
2626 1.178.2.2 christos
2627 1.178.2.2 christos printf("xs(%p): ", xs);
2628 1.178.2.2 christos printf("xs_control(0x%08x)", xs->xs_control);
2629 1.178.2.2 christos printf("xs_status(0x%08x)", xs->xs_status);
2630 1.178.2.2 christos printf("periph(%p)", xs->xs_periph);
2631 1.178.2.2 christos printf("retr(0x%x)", xs->xs_retries);
2632 1.178.2.2 christos printf("timo(0x%x)", xs->timeout);
2633 1.178.2.2 christos printf("cmd(%p)", xs->cmd);
2634 1.178.2.2 christos printf("len(0x%x)", xs->cmdlen);
2635 1.178.2.2 christos printf("data(%p)", xs->data);
2636 1.178.2.2 christos printf("len(0x%x)", xs->datalen);
2637 1.178.2.2 christos printf("res(0x%x)", xs->resid);
2638 1.178.2.2 christos printf("err(0x%x)", xs->error);
2639 1.178.2.2 christos printf("bp(%p)", xs->bp);
2640 1.178.2.2 christos show_scsipi_cmd(xs);
2641 1.178.2.2 christos }
2642 1.178.2.2 christos
2643 1.178.2.2 christos void
2644 1.178.2.2 christos show_scsipi_cmd(struct scsipi_xfer *xs)
2645 1.178.2.2 christos {
2646 1.178.2.2 christos u_char *b = (u_char *) xs->cmd;
2647 1.178.2.2 christos int i = 0;
2648 1.178.2.2 christos
2649 1.178.2.2 christos scsipi_printaddr(xs->xs_periph);
2650 1.178.2.2 christos printf(" command: ");
2651 1.178.2.2 christos
2652 1.178.2.2 christos if ((xs->xs_control & XS_CTL_RESET) == 0) {
2653 1.178.2.2 christos while (i < xs->cmdlen) {
2654 1.178.2.2 christos if (i)
2655 1.178.2.2 christos printf(",");
2656 1.178.2.2 christos printf("0x%x", b[i++]);
2657 1.178.2.2 christos }
2658 1.178.2.2 christos printf("-[%d bytes]\n", xs->datalen);
2659 1.178.2.2 christos if (xs->datalen)
2660 1.178.2.2 christos show_mem(xs->data, min(64, xs->datalen));
2661 1.178.2.2 christos } else
2662 1.178.2.2 christos printf("-RESET-\n");
2663 1.178.2.2 christos }
2664 1.178.2.2 christos
2665 1.178.2.2 christos void
2666 1.178.2.2 christos show_mem(u_char *address, int num)
2667 1.178.2.2 christos {
2668 1.178.2.2 christos int x;
2669 1.178.2.2 christos
2670 1.178.2.2 christos printf("------------------------------");
2671 1.178.2.2 christos for (x = 0; x < num; x++) {
2672 1.178.2.2 christos if ((x % 16) == 0)
2673 1.178.2.2 christos printf("\n%03d: ", x);
2674 1.178.2.2 christos printf("%02x ", *address++);
2675 1.178.2.2 christos }
2676 1.178.2.2 christos printf("\n------------------------------\n");
2677 1.178.2.2 christos }
2678 1.178.2.2 christos #endif /* SCSIPI_DEBUG */
2679