Annotation of src/sys/dev/scsipi/scsipi_base.c, Revision 1.26.2.17
1.26.2.17! bouyer 1: /* $NetBSD$ */
1.2 bouyer 2:
1.8 mycroft 3: /*-
1.26.2.7 thorpej 4: * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
1.8 mycroft 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
1.26.2.1 thorpej 8: * by Charles M. Hannum; by Jason R. Thorpe of the Numerical Aerospace
9: * Simulation Facility, NASA Ames Research Center.
1.2 bouyer 10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
1.8 mycroft 21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
1.2 bouyer 26: *
1.8 mycroft 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
1.2 bouyer 38: */
39:
1.13 bouyer 40: #include "opt_scsi.h"
41:
1.2 bouyer 42: #include <sys/types.h>
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/kernel.h>
46: #include <sys/buf.h>
47: #include <sys/uio.h>
48: #include <sys/malloc.h>
1.6 thorpej 49: #include <sys/pool.h>
1.2 bouyer 50: #include <sys/errno.h>
51: #include <sys/device.h>
52: #include <sys/proc.h>
1.26.2.1 thorpej 53: #include <sys/kthread.h>
1.2 bouyer 54:
55: #include <dev/scsipi/scsipi_all.h>
56: #include <dev/scsipi/scsipi_disk.h>
57: #include <dev/scsipi/scsipiconf.h>
58: #include <dev/scsipi/scsipi_base.h>
59:
1.26.2.1 thorpej 60: #include <dev/scsipi/scsi_all.h>
61: #include <dev/scsipi/scsi_message.h>
62:
63: int scsipi_complete __P((struct scsipi_xfer *));
1.26.2.9 bouyer 64: void scsipi_request_sense __P((struct scsipi_xfer *));
1.26.2.1 thorpej 65: int scsipi_enqueue __P((struct scsipi_xfer *));
66: void scsipi_run_queue __P((struct scsipi_channel *chan));
67:
68: void scsipi_completion_thread __P((void *));
69:
70: void scsipi_get_tag __P((struct scsipi_xfer *));
71: void scsipi_put_tag __P((struct scsipi_xfer *));
1.6 thorpej 72:
1.26.2.7 thorpej 73: int scsipi_get_resource __P((struct scsipi_channel *));
74: void scsipi_put_resource __P((struct scsipi_channel *));
75: __inline int scsipi_grow_resources __P((struct scsipi_channel *));
76:
1.26.2.1 thorpej 77: void scsipi_async_event_max_openings __P((struct scsipi_channel *,
78: struct scsipi_max_openings *));
1.26.2.2 thorpej 79: void scsipi_async_event_xfer_mode __P((struct scsipi_channel *,
80: struct scsipi_xfer_mode *));
1.26.2.9 bouyer 81: void scsipi_async_event_channel_reset __P((struct scsipi_channel *));
1.26.2.1 thorpej 82:
83: struct pool scsipi_xfer_pool;
1.2 bouyer 84:
85: /*
1.26.2.1 thorpej 86: * scsipi_init:
87: *
88: * Called when a scsibus or atapibus is attached to the system
89: * to initialize shared data structures.
1.6 thorpej 90: */
91: void
92: scsipi_init()
93: {
94: static int scsipi_init_done;
95:
96: if (scsipi_init_done)
97: return;
98: scsipi_init_done = 1;
99:
100: /* Initialize the scsipi_xfer pool. */
101: pool_init(&scsipi_xfer_pool, sizeof(struct scsipi_xfer), 0,
102: 0, 0, "scxspl", 0, NULL, NULL, M_DEVBUF);
103: }
104:
105: /*
1.26.2.1 thorpej 106: * scsipi_channel_init:
107: *
108: * Initialize a scsipi_channel when it is attached.
109: */
1.26.2.14 mjacob 110: int
1.26.2.1 thorpej 111: scsipi_channel_init(chan)
112: struct scsipi_channel *chan;
113: {
114: size_t nbytes;
115: int i;
116:
117: /* Initialize shared data. */
118: scsipi_init();
119:
120: /* Initialize the queues. */
121: TAILQ_INIT(&chan->chan_queue);
122: TAILQ_INIT(&chan->chan_complete);
123:
1.26.2.11 bouyer 124: nbytes = chan->chan_ntargets * sizeof(struct scsipi_periph **);
1.26.2.14 mjacob 125: chan->chan_periphs = malloc(nbytes, M_DEVBUF, M_NOWAIT);
126: if (chan->chan_periphs == NULL)
127: return (ENOMEM);
128:
1.26.2.1 thorpej 129:
130: nbytes = chan->chan_nluns * sizeof(struct scsipi_periph *);
131: for (i = 0; i < chan->chan_ntargets; i++) {
1.26.2.14 mjacob 132: chan->chan_periphs[i] = malloc(nbytes, M_DEVBUF, M_NOWAIT);
133: if (chan->chan_periphs[i] == NULL) {
134: while (--i >= 0) {
135: free(chan->chan_periphs[i], M_DEVBUF);
136: }
137: return (ENOMEM);
138: }
1.26.2.1 thorpej 139: memset(chan->chan_periphs[i], 0, nbytes);
140: }
141:
142: /*
143: * Create the asynchronous completion thread.
144: */
145: kthread_create(scsipi_create_completion_thread, chan);
1.26.2.14 mjacob 146: return (0);
1.26.2.1 thorpej 147: }
148:
149: /*
1.26.2.7 thorpej 150: * scsipi_channel_shutdown:
151: *
152: * Shutdown a scsipi_channel.
153: */
154: void
155: scsipi_channel_shutdown(chan)
156: struct scsipi_channel *chan;
157: {
158:
159: /*
160: * Shut down the completion thread.
161: */
162: chan->chan_flags |= SCSIPI_CHAN_SHUTDOWN;
163: wakeup(&chan->chan_complete);
164:
165: /*
166: * Now wait for the thread to exit.
167: */
168: while (chan->chan_thread != NULL)
169: (void) tsleep(&chan->chan_thread, PRIBIO, "scshut", 0);
170: }
171:
172: /*
173: * scsipi_insert_periph:
174: *
175: * Insert a periph into the channel.
176: */
177: void
178: scsipi_insert_periph(chan, periph)
179: struct scsipi_channel *chan;
180: struct scsipi_periph *periph;
181: {
182: int s;
183:
184: s = splbio();
185: chan->chan_periphs[periph->periph_target][periph->periph_lun] = periph;
186: splx(s);
187: }
188:
189: /*
190: * scsipi_remove_periph:
191: *
192: * Remove a periph from the channel.
193: */
194: void
195: scsipi_remove_periph(chan, periph)
196: struct scsipi_channel *chan;
197: struct scsipi_periph *periph;
198: {
199: int s;
200:
201: s = splbio();
202: chan->chan_periphs[periph->periph_target][periph->periph_lun] = NULL;
203: splx(s);
204: }
205:
206: /*
1.26.2.1 thorpej 207: * scsipi_lookup_periph:
208: *
209: * Lookup a periph on the specified channel.
210: */
211: struct scsipi_periph *
212: scsipi_lookup_periph(chan, target, lun)
213: struct scsipi_channel *chan;
214: int target, lun;
215: {
216: struct scsipi_periph *periph;
217: int s;
218:
219: if (target >= chan->chan_ntargets ||
220: lun >= chan->chan_nluns)
221: return (NULL);
222:
223: s = splbio();
224: periph = chan->chan_periphs[target][lun];
225: splx(s);
226:
227: return (periph);
228: }
229:
230: /*
231: * scsipi_get_resource:
232: *
233: * Allocate a single xfer `resource' from the channel.
234: *
235: * NOTE: Must be called at splbio().
236: */
237: int
238: scsipi_get_resource(chan)
239: struct scsipi_channel *chan;
240: {
241: struct scsipi_adapter *adapt = chan->chan_adapter;
242:
243: if (chan->chan_flags & SCSIPI_CHAN_OPENINGS) {
244: if (chan->chan_openings > 0) {
245: chan->chan_openings--;
246: return (1);
247: }
248: return (0);
249: }
250:
251: if (adapt->adapt_openings > 0) {
252: adapt->adapt_openings--;
253: return (1);
254: }
255: return (0);
256: }
257:
258: /*
259: * scsipi_grow_resources:
260: *
261: * Attempt to grow resources for a channel. If this succeeds,
262: * we allocate one for our caller.
263: *
264: * NOTE: Must be called at splbio().
265: */
1.26.2.7 thorpej 266: __inline int
1.26.2.1 thorpej 267: scsipi_grow_resources(chan)
268: struct scsipi_channel *chan;
269: {
270:
271: if (chan->chan_flags & SCSIPI_CHAN_CANGROW) {
272: scsipi_adapter_request(chan, ADAPTER_REQ_GROW_RESOURCES, NULL);
273: return (scsipi_get_resource(chan));
274: }
275:
276: return (0);
277: }
278:
279: /*
280: * scsipi_put_resource:
281: *
282: * Free a single xfer `resource' to the channel.
283: *
284: * NOTE: Must be called at splbio().
285: */
286: void
287: scsipi_put_resource(chan)
288: struct scsipi_channel *chan;
289: {
290: struct scsipi_adapter *adapt = chan->chan_adapter;
291:
292: if (chan->chan_flags & SCSIPI_CHAN_OPENINGS)
293: chan->chan_openings++;
294: else
295: adapt->adapt_openings++;
296: }
297:
298: /*
299: * scsipi_get_tag:
300: *
301: * Get a tag ID for the specified xfer.
302: *
303: * NOTE: Must be called at splbio().
304: */
305: void
306: scsipi_get_tag(xs)
307: struct scsipi_xfer *xs;
308: {
309: struct scsipi_periph *periph = xs->xs_periph;
310: int word, bit, tag;
311:
312: for (word = 0; word < PERIPH_NTAGWORDS; word++) {
313: bit = ffs(periph->periph_freetags[word]);
314: if (bit != 0)
315: break;
316: }
317: #ifdef DIAGNOSTIC
318: if (word == PERIPH_NTAGWORDS) {
319: scsipi_printaddr(periph);
320: printf("no free tags\n");
321: panic("scsipi_get_tag");
322: }
323: #endif
324:
325: bit -= 1;
326: periph->periph_freetags[word] &= ~(1 << bit);
327: tag = (word << 5) | bit;
328:
329: /* XXX Should eventually disallow this completely. */
330: if (tag >= periph->periph_openings) {
331: scsipi_printaddr(periph);
332: printf("WARNING: tag %d greater than available openings %d\n",
333: tag, periph->periph_openings);
334: }
335:
336: xs->xs_tag_id = tag;
337: }
338:
339: /*
340: * scsipi_put_tag:
341: *
342: * Put the tag ID for the specified xfer back into the pool.
343: *
344: * NOTE: Must be called at splbio().
1.2 bouyer 345: */
1.26.2.1 thorpej 346: void
347: scsipi_put_tag(xs)
348: struct scsipi_xfer *xs;
349: {
350: struct scsipi_periph *periph = xs->xs_periph;
351: int word, bit;
352:
353: word = xs->xs_tag_id >> 5;
354: bit = xs->xs_tag_id & 0x1f;
355:
356: periph->periph_freetags[word] |= (1 << bit);
357: }
1.2 bouyer 358:
1.26.2.1 thorpej 359: /*
360: * scsipi_get_xs:
361: *
362: * Allocate an xfer descriptor and associate it with the
363: * specified peripherial. If the peripherial has no more
364: * available command openings, we either block waiting for
365: * one to become available, or fail.
366: */
1.2 bouyer 367: struct scsipi_xfer *
1.26.2.1 thorpej 368: scsipi_get_xs(periph, flags)
369: struct scsipi_periph *periph;
370: int flags;
1.2 bouyer 371: {
372: struct scsipi_xfer *xs;
373: int s;
374:
1.26.2.6 thorpej 375: SC_DEBUG(periph, SCSIPI_DB3, ("scsipi_get_xs\n"));
1.6 thorpej 376:
1.24 thorpej 377: /*
378: * If we're cold, make sure we poll.
379: */
380: if (cold)
381: flags |= XS_CTL_NOSLEEP | XS_CTL_POLL;
382:
1.26.2.1 thorpej 383: #ifdef DIAGNOSTIC
384: /*
385: * URGENT commands can never be ASYNC.
386: */
387: if ((flags & (XS_CTL_URGENT|XS_CTL_ASYNC)) ==
388: (XS_CTL_URGENT|XS_CTL_ASYNC)) {
389: scsipi_printaddr(periph);
390: printf("URGENT and ASYNC\n");
391: panic("scsipi_get_xs");
392: }
393: #endif
394:
1.2 bouyer 395: s = splbio();
1.26.2.1 thorpej 396: /*
397: * Wait for a command opening to become available. Rules:
398: *
399: * - All xfers must wait for an available opening.
400: * Exception: URGENT xfers can proceed when
401: * active == openings, because we use the opening
402: * of the command we're recovering for.
1.26.2.9 bouyer 403: * - if the periph has sense pending, only URGENT & REQSENSE
404: * xfers may proceed.
1.26.2.1 thorpej 405: *
406: * - If the periph is recovering, only URGENT xfers may
407: * proceed.
408: *
409: * - If the periph is currently executing a recovery
410: * command, URGENT commands must block, because only
411: * one recovery command can execute at a time.
412: */
413: for (;;) {
414: if (flags & XS_CTL_URGENT) {
1.26.2.9 bouyer 415: if (periph->periph_active > periph->periph_openings)
1.26.2.1 thorpej 416: goto wait_for_opening;
1.26.2.9 bouyer 417: if (periph->periph_flags & PERIPH_SENSE) {
418: if ((flags & XS_CTL_REQSENSE) == 0)
419: goto wait_for_opening;
420: } else {
421: if ((periph->periph_flags &
422: PERIPH_RECOVERY_ACTIVE) != 0)
423: goto wait_for_opening;
424: periph->periph_flags |= PERIPH_RECOVERY_ACTIVE;
425: }
1.26.2.1 thorpej 426: break;
427: }
428: if (periph->periph_active >= periph->periph_openings ||
429: (periph->periph_flags & PERIPH_RECOVERING) != 0)
430: goto wait_for_opening;
431: periph->periph_active++;
432: break;
433:
434: wait_for_opening:
435: if (flags & XS_CTL_NOSLEEP) {
1.2 bouyer 436: splx(s);
1.26.2.1 thorpej 437: return (NULL);
1.2 bouyer 438: }
1.26.2.6 thorpej 439: SC_DEBUG(periph, SCSIPI_DB3, ("sleeping\n"));
1.26.2.1 thorpej 440: periph->periph_flags |= PERIPH_WAITING;
441: (void) tsleep(periph, PRIBIO, "getxs", 0);
1.2 bouyer 442: }
1.26.2.6 thorpej 443: SC_DEBUG(periph, SCSIPI_DB3, ("calling pool_get\n"));
1.6 thorpej 444: xs = pool_get(&scsipi_xfer_pool,
1.24 thorpej 445: ((flags & XS_CTL_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK));
1.26.2.1 thorpej 446: if (xs == NULL) {
1.26.2.9 bouyer 447: if (flags & XS_CTL_URGENT) {
448: if ((flags & XS_CTL_REQSENSE) == 0)
449: periph->periph_flags &= ~PERIPH_RECOVERY_ACTIVE;
450: } else
1.26.2.1 thorpej 451: periph->periph_active--;
452: scsipi_printaddr(periph);
453: printf("unable to allocate %sscsipi_xfer\n",
454: (flags & XS_CTL_URGENT) ? "URGENT " : "");
1.2 bouyer 455: }
1.6 thorpej 456: splx(s);
1.2 bouyer 457:
1.26.2.6 thorpej 458: SC_DEBUG(periph, SCSIPI_DB3, ("returning\n"));
1.6 thorpej 459:
1.7 scottr 460: if (xs != NULL) {
1.26.2.8 bouyer 461: callout_init(&xs->xs_callout);
1.26.2.1 thorpej 462: memset(xs, 0, sizeof(*xs));
463: xs->xs_periph = periph;
1.24 thorpej 464: xs->xs_control = flags;
1.26.2.8 bouyer 465: xs->xs_status = 0;
1.26.2.1 thorpej 466: s = splbio();
467: TAILQ_INSERT_TAIL(&periph->periph_xferq, xs, device_q);
468: splx(s);
1.7 scottr 469: }
1.3 enami 470: return (xs);
1.2 bouyer 471: }
472:
473: /*
1.26.2.1 thorpej 474: * scsipi_put_xs:
1.6 thorpej 475: *
1.26.2.1 thorpej 476: * Release an xfer descriptor, decreasing the outstanding command
477: * count for the peripherial. If there is a thread waiting for
478: * an opening, wake it up. If not, kick any queued I/O the
479: * peripherial may have.
480: *
481: * NOTE: Must be called at splbio().
1.2 bouyer 482: */
1.3 enami 483: void
1.26.2.1 thorpej 484: scsipi_put_xs(xs)
1.2 bouyer 485: struct scsipi_xfer *xs;
486: {
1.26.2.1 thorpej 487: struct scsipi_periph *periph = xs->xs_periph;
488: int flags = xs->xs_control;
1.2 bouyer 489:
1.26.2.6 thorpej 490: SC_DEBUG(periph, SCSIPI_DB3, ("scsipi_free_xs\n"));
1.26.2.1 thorpej 491:
492: TAILQ_REMOVE(&periph->periph_xferq, xs, device_q);
1.6 thorpej 493: pool_put(&scsipi_xfer_pool, xs);
1.2 bouyer 494:
1.26.2.1 thorpej 495: #ifdef DIAGNOSTIC
496: if ((periph->periph_flags & PERIPH_RECOVERY_ACTIVE) != 0 &&
497: periph->periph_active == 0) {
498: scsipi_printaddr(periph);
499: printf("recovery without a command to recovery for\n");
500: panic("scsipi_put_xs");
501: }
502: #endif
503:
1.26.2.9 bouyer 504: if (flags & XS_CTL_URGENT) {
505: if ((flags & XS_CTL_REQSENSE) == 0)
506: periph->periph_flags &= ~PERIPH_RECOVERY_ACTIVE;
507: } else
1.26.2.1 thorpej 508: periph->periph_active--;
509: if (periph->periph_active == 0 &&
510: (periph->periph_flags & PERIPH_WAITDRAIN) != 0) {
511: periph->periph_flags &= ~PERIPH_WAITDRAIN;
512: wakeup(&periph->periph_active);
513: }
514:
515: if (periph->periph_flags & PERIPH_WAITING) {
516: periph->periph_flags &= ~PERIPH_WAITING;
517: wakeup(periph);
1.2 bouyer 518: } else {
1.26.2.1 thorpej 519: if (periph->periph_switch->psw_start != NULL) {
1.26.2.6 thorpej 520: SC_DEBUG(periph, SCSIPI_DB2,
1.3 enami 521: ("calling private start()\n"));
1.26.2.1 thorpej 522: (*periph->periph_switch->psw_start)(periph);
1.2 bouyer 523: }
524: }
1.15 thorpej 525: }
526:
527: /*
1.26.2.3 thorpej 528: * scsipi_channel_freeze:
529: *
530: * Freeze a channel's xfer queue.
531: */
532: void
533: scsipi_channel_freeze(chan, count)
534: struct scsipi_channel *chan;
535: int count;
536: {
537: int s;
538:
539: s = splbio();
540: chan->chan_qfreeze += count;
541: splx(s);
542: }
543:
544: /*
545: * scsipi_channel_thaw:
546: *
547: * Thaw a channel's xfer queue.
548: */
549: void
550: scsipi_channel_thaw(chan, count)
551: struct scsipi_channel *chan;
552: int count;
553: {
554: int s;
555:
556: s = splbio();
557: chan->chan_qfreeze -= count;
1.26.2.16 mjacob 558: /*
559: * Don't let the freeze count go negative.
560: *
561: * Presumably the adapter driver could keep track of this,
562: * but it might just be easier to do this here so as to allow
563: * multiple callers, including those outside the adapter driver.
564: */
565: if (chan->chan_qfreeze < 0) {
566: chan->chan_qfreeze = 0;
567: }
1.26.2.3 thorpej 568: splx(s);
569: }
570:
571: /*
572: * scsipi_channel_timed_thaw:
573: *
574: * Thaw a channel after some time has expired.
575: */
576: void
577: scsipi_channel_timed_thaw(arg)
578: void *arg;
579: {
580: struct scsipi_channel *chan = arg;
581:
582: scsipi_channel_thaw(chan, 1);
583:
584: /*
585: * Kick the channel's queue here. Note, we're running in
586: * interrupt context (softclock), so the adapter driver
587: * had better not sleep.
588: */
589: scsipi_run_queue(chan);
590: }
591:
592: /*
1.26.2.1 thorpej 593: * scsipi_periph_freeze:
594: *
595: * Freeze a device's xfer queue.
596: */
597: void
598: scsipi_periph_freeze(periph, count)
599: struct scsipi_periph *periph;
600: int count;
601: {
602: int s;
603:
604: s = splbio();
605: periph->periph_qfreeze += count;
606: splx(s);
607: }
608:
609: /*
610: * scsipi_periph_thaw:
611: *
612: * Thaw a device's xfer queue.
613: */
614: void
615: scsipi_periph_thaw(periph, count)
616: struct scsipi_periph *periph;
617: int count;
618: {
619: int s;
620:
621: s = splbio();
622: periph->periph_qfreeze -= count;
623: if (periph->periph_qfreeze == 0 &&
624: (periph->periph_flags & PERIPH_WAITING) != 0)
625: wakeup(periph);
626: splx(s);
627: }
628:
629: /*
630: * scsipi_periph_timed_thaw:
631: *
632: * Thaw a device after some time has expired.
633: */
634: void
635: scsipi_periph_timed_thaw(arg)
636: void *arg;
637: {
638: struct scsipi_periph *periph = arg;
639:
1.26.2.8 bouyer 640: callout_stop(&periph->periph_callout);
1.26.2.1 thorpej 641: scsipi_periph_thaw(periph, 1);
642:
1.26.2.3 thorpej 643: /*
644: * Kick the channel's queue here. Note, we're running in
645: * interrupt context (softclock), so the adapter driver
646: * had better not sleep.
647: */
648: scsipi_run_queue(periph->periph_channel);
1.26.2.1 thorpej 649: }
650:
651: /*
652: * scsipi_wait_drain:
653: *
654: * Wait for a periph's pending xfers to drain.
1.15 thorpej 655: */
656: void
1.26.2.1 thorpej 657: scsipi_wait_drain(periph)
658: struct scsipi_periph *periph;
1.15 thorpej 659: {
660: int s;
661:
662: s = splbio();
1.26.2.1 thorpej 663: while (periph->periph_active != 0) {
664: periph->periph_flags |= PERIPH_WAITDRAIN;
665: (void) tsleep(&periph->periph_active, PRIBIO, "sxdrn", 0);
1.15 thorpej 666: }
667: splx(s);
1.23 thorpej 668: }
669:
670: /*
1.26.2.1 thorpej 671: * scsipi_kill_pending:
1.23 thorpej 672: *
1.26.2.1 thorpej 673: * Kill off all pending xfers for a periph.
674: *
675: * NOTE: Must be called at splbio().
1.23 thorpej 676: */
677: void
1.26.2.1 thorpej 678: scsipi_kill_pending(periph)
679: struct scsipi_periph *periph;
1.23 thorpej 680: {
681:
1.26.2.4 thorpej 682: (*periph->periph_channel->chan_bustype->bustype_kill_pending)(periph);
683: #ifdef DIAGNOSTIC
684: if (TAILQ_FIRST(&periph->periph_xferq) != NULL)
685: panic("scsipi_kill_pending");
686: #endif
1.26.2.8 bouyer 687: scsipi_wait_drain(periph);
1.2 bouyer 688: }
689:
690: /*
1.26.2.1 thorpej 691: * scsipi_interpret_sense:
692: *
693: * Look at the returned sense and act on the error, determining
694: * the unix error number to pass back. (0 = report no error)
1.13 bouyer 695: *
1.26.2.1 thorpej 696: * NOTE: If we return ERESTART, we are expected to haved
697: * thawed the device!
698: *
699: * THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES.
1.13 bouyer 700: */
701: int
702: scsipi_interpret_sense(xs)
703: struct scsipi_xfer *xs;
704: {
705: struct scsipi_sense_data *sense;
1.26.2.1 thorpej 706: struct scsipi_periph *periph = xs->xs_periph;
1.13 bouyer 707: u_int8_t key;
708: u_int32_t info;
709: int error;
710: #ifndef SCSIVERBOSE
711: static char *error_mes[] = {
712: "soft error (corrected)",
713: "not ready", "medium error",
714: "non-media hardware failure", "illegal request",
715: "unit attention", "readonly device",
716: "no data found", "vendor unique",
717: "copy aborted", "command aborted",
718: "search returned equal", "volume overflow",
719: "verify miscompare", "unknown error key"
720: };
721: #endif
722:
723: sense = &xs->sense.scsi_sense;
1.26.2.6 thorpej 724: #ifdef SCSIPI_DEBUG
725: if (periph->periph_flags & SCSIPI_DB1) {
1.13 bouyer 726: int count;
1.26.2.6 thorpej 727: scsipi_printaddr(periph);
728: printf(" sense debug information:\n");
729: printf("\tcode 0x%x valid 0x%x\n",
1.13 bouyer 730: sense->error_code & SSD_ERRCODE,
731: sense->error_code & SSD_ERRCODE_VALID ? 1 : 0);
1.26.2.6 thorpej 732: printf("\tseg 0x%x key 0x%x ili 0x%x eom 0x%x fmark 0x%x\n",
1.13 bouyer 733: sense->segment,
734: sense->flags & SSD_KEY,
735: sense->flags & SSD_ILI ? 1 : 0,
736: sense->flags & SSD_EOM ? 1 : 0,
737: sense->flags & SSD_FILEMARK ? 1 : 0);
1.26.2.6 thorpej 738: printf("\ninfo: 0x%x 0x%x 0x%x 0x%x followed by %d "
739: "extra bytes\n",
1.13 bouyer 740: sense->info[0],
741: sense->info[1],
742: sense->info[2],
743: sense->info[3],
744: sense->extra_len);
1.26.2.6 thorpej 745: printf("\textra: ");
1.13 bouyer 746: for (count = 0; count < ADD_BYTES_LIM(sense); count++)
747: printf("0x%x ", sense->cmd_spec_info[count]);
748: printf("\n");
749: }
1.26.2.6 thorpej 750: #endif
1.26.2.1 thorpej 751:
1.13 bouyer 752: /*
1.26.2.1 thorpej 753: * If the periph has it's own error handler, call it first.
1.13 bouyer 754: * If it returns a legit error value, return that, otherwise
755: * it wants us to continue with normal error processing.
756: */
1.26.2.1 thorpej 757: if (periph->periph_switch->psw_error != NULL) {
1.26.2.6 thorpej 758: SC_DEBUG(periph, SCSIPI_DB2,
1.13 bouyer 759: ("calling private err_handler()\n"));
1.26.2.1 thorpej 760: error = (*periph->periph_switch->psw_error)(xs);
761: if (error != EJUSTRETURN)
762: return (error);
1.13 bouyer 763: }
764: /* otherwise use the default */
765: switch (sense->error_code & SSD_ERRCODE) {
766: /*
767: * If it's code 70, use the extended stuff and
768: * interpret the key
769: */
770: case 0x71: /* delayed error */
1.26.2.1 thorpej 771: scsipi_printaddr(periph);
1.13 bouyer 772: key = sense->flags & SSD_KEY;
773: printf(" DEFERRED ERROR, key = 0x%x\n", key);
774: /* FALLTHROUGH */
775: case 0x70:
776: if ((sense->error_code & SSD_ERRCODE_VALID) != 0)
777: info = _4btol(sense->info);
778: else
779: info = 0;
780: key = sense->flags & SSD_KEY;
781:
782: switch (key) {
783: case SKEY_NO_SENSE:
784: case SKEY_RECOVERED_ERROR:
785: if (xs->resid == xs->datalen && xs->datalen) {
786: /*
787: * Why is this here?
788: */
789: xs->resid = 0; /* not short read */
790: }
791: case SKEY_EQUAL:
792: error = 0;
793: break;
794: case SKEY_NOT_READY:
1.26.2.1 thorpej 795: if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
796: periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
1.24 thorpej 797: if ((xs->xs_control & XS_CTL_IGNORE_NOT_READY) != 0)
1.13 bouyer 798: return (0);
1.19 bouyer 799: if (sense->add_sense_code == 0x3A &&
800: sense->add_sense_code_qual == 0x00)
801: error = ENODEV; /* Medium not present */
802: else
803: error = EIO;
1.24 thorpej 804: if ((xs->xs_control & XS_CTL_SILENT) != 0)
1.19 bouyer 805: return (error);
1.13 bouyer 806: break;
807: case SKEY_ILLEGAL_REQUEST:
1.24 thorpej 808: if ((xs->xs_control &
809: XS_CTL_IGNORE_ILLEGAL_REQUEST) != 0)
1.13 bouyer 810: return (0);
1.24 thorpej 811: /*
812: * Handle the case where a device reports
813: * Logical Unit Not Supported during discovery.
814: */
815: if ((xs->xs_control & XS_CTL_DISCOVERY) != 0 &&
816: sense->add_sense_code == 0x25 &&
817: sense->add_sense_code_qual == 0x00)
818: return (EINVAL);
819: if ((xs->xs_control & XS_CTL_SILENT) != 0)
1.13 bouyer 820: return (EIO);
821: error = EINVAL;
822: break;
823: case SKEY_UNIT_ATTENTION:
1.20 bouyer 824: if (sense->add_sense_code == 0x29 &&
1.26.2.1 thorpej 825: sense->add_sense_code_qual == 0x00) {
826: /* device or bus reset */
827: return (ERESTART);
828: }
829: if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
830: periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
1.24 thorpej 831: if ((xs->xs_control &
832: XS_CTL_IGNORE_MEDIA_CHANGE) != 0 ||
1.13 bouyer 833: /* XXX Should reupload any transient state. */
1.26.2.1 thorpej 834: (periph->periph_flags &
835: PERIPH_REMOVABLE) == 0) {
1.13 bouyer 836: return (ERESTART);
1.26.2.1 thorpej 837: }
1.24 thorpej 838: if ((xs->xs_control & XS_CTL_SILENT) != 0)
1.13 bouyer 839: return (EIO);
840: error = EIO;
841: break;
842: case SKEY_WRITE_PROTECT:
843: error = EROFS;
844: break;
845: case SKEY_BLANK_CHECK:
846: error = 0;
847: break;
848: case SKEY_ABORTED_COMMAND:
849: error = ERESTART;
850: break;
851: case SKEY_VOLUME_OVERFLOW:
852: error = ENOSPC;
853: break;
854: default:
855: error = EIO;
856: break;
857: }
858:
859: #ifdef SCSIVERBOSE
1.26.2.8 bouyer 860: if (key && (xs->xs_control & XS_CTL_SILENT) == 0)
1.13 bouyer 861: scsipi_print_sense(xs, 0);
862: #else
863: if (key) {
1.26.2.1 thorpej 864: scsipi_printaddr(periph);
1.13 bouyer 865: printf("%s", error_mes[key - 1]);
866: if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
867: switch (key) {
868: case SKEY_NOT_READY:
869: case SKEY_ILLEGAL_REQUEST:
870: case SKEY_UNIT_ATTENTION:
871: case SKEY_WRITE_PROTECT:
872: break;
873: case SKEY_BLANK_CHECK:
874: printf(", requested size: %d (decimal)",
875: info);
876: break;
877: case SKEY_ABORTED_COMMAND:
1.26.2.1 thorpej 878: if (xs->xs_retries)
1.13 bouyer 879: printf(", retrying");
880: printf(", cmd 0x%x, info 0x%x",
881: xs->cmd->opcode, info);
882: break;
883: default:
884: printf(", info = %d (decimal)", info);
885: }
886: }
887: if (sense->extra_len != 0) {
888: int n;
889: printf(", data =");
890: for (n = 0; n < sense->extra_len; n++)
891: printf(" %02x",
892: sense->cmd_spec_info[n]);
893: }
894: printf("\n");
895: }
896: #endif
897: return (error);
898:
899: /*
900: * Not code 70, just report it
901: */
902: default:
1.26.2.8 bouyer 903: #if defined(SCSIDEBUG) || defined(DEBUG)
904: {
905: static char *uc = "undecodable sense error";
906: int i;
907: u_int8_t *cptr = (u_int8_t *) sense;
908: scsipi_printaddr(periph);
909: if (xs->cmd == &xs->cmdstore) {
910: printf("%s for opcode 0x%x, data=",
911: uc, xs->cmdstore.opcode);
912: } else {
913: printf("%s, data=", uc);
914: }
915: for (i = 0; i < sizeof (sense); i++)
916: printf(" 0x%02x", *(cptr++) & 0xff);
917: printf("\n");
918: }
919: #else
920:
1.26.2.1 thorpej 921: scsipi_printaddr(periph);
1.17 mjacob 922: printf("Sense Error Code 0x%x",
923: sense->error_code & SSD_ERRCODE);
1.13 bouyer 924: if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
925: struct scsipi_sense_data_unextended *usense =
926: (struct scsipi_sense_data_unextended *)sense;
927: printf(" at block no. %d (decimal)",
928: _3btol(usense->block));
929: }
930: printf("\n");
1.26.2.8 bouyer 931: #endif
1.13 bouyer 932: return (EIO);
933: }
934: }
935:
936: /*
1.26.2.1 thorpej 937: * scsipi_size:
938: *
939: * Find out from the device what its capacity is.
1.2 bouyer 940: */
941: u_long
1.26.2.1 thorpej 942: scsipi_size(periph, flags)
943: struct scsipi_periph *periph;
1.2 bouyer 944: int flags;
945: {
946: struct scsipi_read_cap_data rdcap;
947: struct scsipi_read_capacity scsipi_cmd;
948:
949: bzero(&scsipi_cmd, sizeof(scsipi_cmd));
950: scsipi_cmd.opcode = READ_CAPACITY;
951:
952: /*
953: * If the command works, interpret the result as a 4 byte
954: * number of blocks
955: */
1.26.2.1 thorpej 956: if (scsipi_command(periph, (struct scsipi_generic *)&scsipi_cmd,
1.3 enami 957: sizeof(scsipi_cmd), (u_char *)&rdcap, sizeof(rdcap),
1.26.2.8 bouyer 958: SCSIPIRETRIES, 20000, NULL,
959: flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK) != 0) {
1.26.2.1 thorpej 960: scsipi_printaddr(periph);
1.2 bouyer 961: printf("could not get size\n");
1.3 enami 962: return (0);
1.2 bouyer 963: }
964:
1.3 enami 965: return (_4btol(rdcap.addr) + 1);
1.2 bouyer 966: }
967:
968: /*
1.26.2.1 thorpej 969: * scsipi_test_unit_ready:
970: *
971: * Issue a `test unit ready' request.
1.2 bouyer 972: */
1.3 enami 973: int
1.26.2.1 thorpej 974: scsipi_test_unit_ready(periph, flags)
975: struct scsipi_periph *periph;
1.2 bouyer 976: int flags;
977: {
978: struct scsipi_test_unit_ready scsipi_cmd;
979:
980: /* some ATAPI drives don't support TEST_UNIT_READY. Sigh */
1.26.2.1 thorpej 981: if (periph->periph_quirks & PQUIRK_NOTUR)
1.3 enami 982: return (0);
1.2 bouyer 983:
984: bzero(&scsipi_cmd, sizeof(scsipi_cmd));
985: scsipi_cmd.opcode = TEST_UNIT_READY;
986:
1.26.2.1 thorpej 987: return (scsipi_command(periph,
1.3 enami 988: (struct scsipi_generic *)&scsipi_cmd, sizeof(scsipi_cmd),
1.26.2.8 bouyer 989: 0, 0, SCSIPIRETRIES, 10000, NULL, flags));
1.2 bouyer 990: }
991:
992: /*
1.26.2.1 thorpej 993: * scsipi_inquire:
994: *
995: * Ask the device about itself.
1.2 bouyer 996: */
1.3 enami 997: int
1.26.2.1 thorpej 998: scsipi_inquire(periph, inqbuf, flags)
999: struct scsipi_periph *periph;
1.2 bouyer 1000: struct scsipi_inquiry_data *inqbuf;
1001: int flags;
1002: {
1003: struct scsipi_inquiry scsipi_cmd;
1004:
1005: bzero(&scsipi_cmd, sizeof(scsipi_cmd));
1006: scsipi_cmd.opcode = INQUIRY;
1007: scsipi_cmd.length = sizeof(struct scsipi_inquiry_data);
1008:
1.26.2.1 thorpej 1009: return (scsipi_command(periph,
1.3 enami 1010: (struct scsipi_generic *) &scsipi_cmd, sizeof(scsipi_cmd),
1011: (u_char *) inqbuf, sizeof(struct scsipi_inquiry_data),
1.26.2.8 bouyer 1012: SCSIPIRETRIES, 10000, NULL, XS_CTL_DATA_IN | flags));
1.2 bouyer 1013: }
1014:
1015: /*
1.26.2.1 thorpej 1016: * scsipi_prevent:
1017: *
1018: * Prevent or allow the user to remove the media
1.2 bouyer 1019: */
1.3 enami 1020: int
1.26.2.1 thorpej 1021: scsipi_prevent(periph, type, flags)
1022: struct scsipi_periph *periph;
1.2 bouyer 1023: int type, flags;
1024: {
1025: struct scsipi_prevent scsipi_cmd;
1026:
1.26.2.1 thorpej 1027: if (periph->periph_quirks & PQUIRK_NODOORLOCK)
1.3 enami 1028: return (0);
1.2 bouyer 1029:
1030: bzero(&scsipi_cmd, sizeof(scsipi_cmd));
1031: scsipi_cmd.opcode = PREVENT_ALLOW;
1032: scsipi_cmd.how = type;
1.26.2.1 thorpej 1033:
1034: return (scsipi_command(periph,
1.3 enami 1035: (struct scsipi_generic *) &scsipi_cmd, sizeof(scsipi_cmd),
1.26.2.8 bouyer 1036: 0, 0, SCSIPIRETRIES, 5000, NULL, flags));
1.2 bouyer 1037: }
1038:
1039: /*
1.26.2.1 thorpej 1040: * scsipi_start:
1041: *
1042: * Send a START UNIT.
1.2 bouyer 1043: */
1.3 enami 1044: int
1.26.2.1 thorpej 1045: scsipi_start(periph, type, flags)
1046: struct scsipi_periph *periph;
1.2 bouyer 1047: int type, flags;
1048: {
1049: struct scsipi_start_stop scsipi_cmd;
1.18 bouyer 1050:
1.26.2.1 thorpej 1051: if (periph->periph_quirks & PQUIRK_NOSTARTUNIT)
1.18 bouyer 1052: return 0;
1.2 bouyer 1053:
1054: bzero(&scsipi_cmd, sizeof(scsipi_cmd));
1055: scsipi_cmd.opcode = START_STOP;
1056: scsipi_cmd.byte2 = 0x00;
1057: scsipi_cmd.how = type;
1.26.2.1 thorpej 1058:
1059: return (scsipi_command(periph,
1.3 enami 1060: (struct scsipi_generic *) &scsipi_cmd, sizeof(scsipi_cmd),
1.26.2.8 bouyer 1061: 0, 0, SCSIPIRETRIES, (type & SSS_START) ? 60000 : 10000,
1062: NULL, flags));
1.2 bouyer 1063: }
1064:
1065: /*
1.26.2.1 thorpej 1066: * scsipi_done:
1067: *
1068: * This routine is called by an adapter's interrupt handler when
1069: * an xfer is completed.
1.2 bouyer 1070: */
1.3 enami 1071: void
1.2 bouyer 1072: scsipi_done(xs)
1073: struct scsipi_xfer *xs;
1074: {
1.26.2.1 thorpej 1075: struct scsipi_periph *periph = xs->xs_periph;
1076: struct scsipi_channel *chan = periph->periph_channel;
1077: int s, freezecnt;
1.2 bouyer 1078:
1.26.2.6 thorpej 1079: SC_DEBUG(periph, SCSIPI_DB2, ("scsipi_done\n"));
1080: #ifdef SCSIPI_DEBUG
1081: if (periph->periph_dbflags & SCSIPI_DB1)
1.2 bouyer 1082: show_scsipi_cmd(xs);
1.26.2.6 thorpej 1083: #endif
1.2 bouyer 1084:
1.26.2.1 thorpej 1085: s = splbio();
1086: /*
1087: * The resource this command was using is now free.
1088: */
1089: scsipi_put_resource(chan);
1.26.2.15 bouyer 1090: xs->xs_periph->periph_sent--;
1.26.2.1 thorpej 1091:
1092: /*
1093: * If the command was tagged, free the tag.
1094: */
1095: if (XS_CTL_TAGTYPE(xs) != 0)
1096: scsipi_put_tag(xs);
1.26.2.13 bouyer 1097: else
1098: periph->periph_flags &= ~PERIPH_UNTAG;
1.26.2.1 thorpej 1099:
1100: /* Mark the command as `done'. */
1101: xs->xs_status |= XS_STS_DONE;
1102:
1103: #ifdef DIAGNOSTIC
1104: if ((xs->xs_control & (XS_CTL_ASYNC|XS_CTL_POLL)) ==
1105: (XS_CTL_ASYNC|XS_CTL_POLL))
1106: panic("scsipi_done: ASYNC and POLL");
1107: #endif
1108:
1109: /*
1110: * If the xfer had an error of any sort, freeze the
1111: * periph's queue. Freeze it again if we were requested
1112: * to do so in the xfer.
1113: */
1114: freezecnt = 0;
1115: if (xs->error != XS_NOERROR)
1116: freezecnt++;
1117: if (xs->xs_control & XS_CTL_FREEZE_PERIPH)
1118: freezecnt++;
1119: if (freezecnt != 0)
1120: scsipi_periph_freeze(periph, freezecnt);
1121:
1122: /*
1.26.2.9 bouyer 1123: * record the xfer with a pending sense, in case a SCSI reset is
1124: * received before the thread is waked up.
1125: */
1126: if (xs->error == XS_BUSY && xs->status == SCSI_CHECK) {
1127: periph->periph_flags |= PERIPH_SENSE;
1128: periph->periph_xscheck = xs;
1129: }
1130:
1131: /*
1.26.2.1 thorpej 1132: * If this was an xfer that was not to complete asynchrnously,
1133: * let the requesting thread perform error checking/handling
1134: * in its context.
1135: */
1.24 thorpej 1136: if ((xs->xs_control & XS_CTL_ASYNC) == 0) {
1.26.2.1 thorpej 1137: splx(s);
1.2 bouyer 1138: /*
1.26.2.1 thorpej 1139: * If it's a polling job, just return, to unwind the
1140: * call graph. We don't need to restart the queue,
1141: * because pollings jobs are treated specially, and
1142: * are really only used during crash dumps anyway
1143: * (XXX or during boot-time autconfiguration of
1144: * ATAPI devices).
1.2 bouyer 1145: */
1.26.2.1 thorpej 1146: if (xs->xs_control & XS_CTL_POLL)
1147: return;
1.2 bouyer 1148: wakeup(xs);
1.26.2.1 thorpej 1149: goto out;
1.2 bouyer 1150: }
1151:
1152: /*
1.26.2.1 thorpej 1153: * Catch the extremely common case of I/O completing
1154: * without error; no use in taking a context switch
1155: * if we can handle it in interrupt context.
1.2 bouyer 1156: */
1.26.2.1 thorpej 1157: if (xs->error == XS_NOERROR) {
1158: splx(s);
1159: (void) scsipi_complete(xs);
1160: goto out;
1.20 bouyer 1161: }
1.2 bouyer 1162:
1.9 scottr 1163: /*
1.26.2.1 thorpej 1164: * There is an error on this xfer. Put it on the channel's
1165: * completion queue, and wake up the completion thread.
1.9 scottr 1166: */
1.26.2.1 thorpej 1167: TAILQ_INSERT_TAIL(&chan->chan_complete, xs, channel_q);
1168: splx(s);
1169: wakeup(&chan->chan_complete);
1170:
1171: out:
1172: /*
1173: * If there are more xfers on the channel's queue, attempt to
1174: * run them.
1175: */
1176: scsipi_run_queue(chan);
1.2 bouyer 1177: }
1178:
1.26.2.1 thorpej 1179: /*
1180: * scsipi_complete:
1181: *
1182: * Completion of a scsipi_xfer. This is the guts of scsipi_done().
1183: *
1184: * NOTE: This routine MUST be called with valid thread context
1185: * except for the case where the following two conditions are
1186: * true:
1187: *
1188: * xs->error == XS_NOERROR
1189: * XS_CTL_ASYNC is set in xs->xs_control
1190: *
1191: * The semantics of this routine can be tricky, so here is an
1192: * explanation:
1193: *
1194: * 0 Xfer completed successfully.
1195: *
1196: * ERESTART Xfer had an error, but was restarted.
1197: *
1198: * anything else Xfer had an error, return value is Unix
1199: * errno.
1200: *
1201: * If the return value is anything but ERESTART:
1202: *
1203: * - If XS_CTL_ASYNC is set, `xs' has been freed back to
1204: * the pool.
1205: * - If there is a buf associated with the xfer,
1206: * it has been biodone()'d.
1207: */
1.2 bouyer 1208: int
1.26.2.1 thorpej 1209: scsipi_complete(xs)
1.2 bouyer 1210: struct scsipi_xfer *xs;
1211: {
1.26.2.1 thorpej 1212: struct scsipi_periph *periph = xs->xs_periph;
1213: struct scsipi_channel *chan = periph->periph_channel;
1214: struct buf *bp;
1215: int error, s;
1.2 bouyer 1216:
1.26.2.1 thorpej 1217: #ifdef DIAGNOSTIC
1218: if ((xs->xs_control & XS_CTL_ASYNC) != 0 && xs->bp == NULL)
1219: panic("scsipi_complete: XS_CTL_ASYNC but no buf");
1220: #endif
1.26.2.9 bouyer 1221: /*
1222: * If command terminated with a CHECK CONDITION, we need to issue a
1223: * REQUEST_SENSE command. Once the REQUEST_SENSE has been processed
1224: * we'll have the real status.
1225: * Must be processed at splbio() to avoid missing a SCSI bus reset
1226: * for this command.
1227: */
1228: s = splbio();
1229: if (xs->error == XS_BUSY && xs->status == SCSI_CHECK) {
1230: /* request sense for a request sense ? */
1231: if (xs->xs_control & XS_CTL_REQSENSE) {
1232: scsipi_printaddr(periph);
1.26.2.12 bouyer 1233: /* XXX maybe we should reset the device ? */
1.26.2.10 bouyer 1234: /* we've been frozen because xs->error != XS_NOERROR */
1235: scsipi_periph_thaw(periph, 1);
1236: splx(s);
1.26.2.12 bouyer 1237: return EINVAL;
1.26.2.9 bouyer 1238: }
1239: scsipi_request_sense(xs);
1240: }
1241: splx(s);
1242: /*
1243: * If it's a user level request, bypass all usual completion
1244: * processing, let the user work it out..
1245: */
1246: if ((xs->xs_control & XS_CTL_USERCMD) != 0) {
1247: SC_DEBUG(periph, SCSIPI_DB3, ("calling user done()\n"));
1.26.2.10 bouyer 1248: if (xs->error != XS_NOERROR)
1249: scsipi_periph_thaw(periph, 1);
1.26.2.9 bouyer 1250: scsipi_user_done(xs);
1251: SC_DEBUG(periph, SCSIPI_DB3, ("returned from user done()\n "));
1252: return 0;
1253: }
1254:
1.2 bouyer 1255:
1.26.2.1 thorpej 1256: switch (xs->error) {
1257: case XS_NOERROR:
1258: error = 0;
1259: break;
1260:
1261: case XS_SENSE:
1262: case XS_SHORTSENSE:
1263: error = (*chan->chan_bustype->bustype_interpret_sense)(xs);
1264: break;
1265:
1266: case XS_RESOURCE_SHORTAGE:
1267: /*
1268: * XXX Should freeze channel's queue.
1269: */
1270: scsipi_printaddr(periph);
1271: printf("adapter resource shortage\n");
1272: /* FALLTHROUGH */
1273:
1274: case XS_BUSY:
1275: if (xs->error == XS_BUSY && xs->status == SCSI_QUEUE_FULL) {
1276: struct scsipi_max_openings mo;
1277:
1278: /*
1279: * We set the openings to active - 1, assuming that
1280: * the command that got us here is the first one that
1281: * can't fit into the device's queue. If that's not
1282: * the case, I guess we'll find out soon enough.
1283: */
1284: mo.mo_target = periph->periph_target;
1285: mo.mo_lun = periph->periph_lun;
1286: mo.mo_openings = periph->periph_active - 1;
1.2 bouyer 1287: #ifdef DIAGNOSTIC
1.26.2.1 thorpej 1288: if (mo.mo_openings < 0) {
1289: scsipi_printaddr(periph);
1290: printf("QUEUE FULL resulted in < 0 openings\n");
1291: panic("scsipi_done");
1292: }
1.2 bouyer 1293: #endif
1.26.2.1 thorpej 1294: if (mo.mo_openings == 0) {
1295: scsipi_printaddr(periph);
1296: printf("QUEUE FULL resulted in 0 openings\n");
1297: mo.mo_openings = 1;
1298: }
1299: scsipi_async_event(chan, ASYNC_EVENT_MAX_OPENINGS, &mo);
1300: error = ERESTART;
1301: } else if (xs->xs_retries != 0) {
1302: xs->xs_retries--;
1303: /*
1304: * Wait one second, and try again.
1305: */
1306: if (xs->xs_control & XS_CTL_POLL)
1307: delay(1000000);
1308: else {
1309: scsipi_periph_freeze(periph, 1);
1.26.2.8 bouyer 1310: callout_reset(&periph->periph_callout,
1311: hz, scsipi_periph_timed_thaw, periph);
1.26.2.1 thorpej 1312: }
1313: error = ERESTART;
1314: } else
1315: error = EBUSY;
1316: break;
1.2 bouyer 1317:
1.26.2.10 bouyer 1318: case XS_REQUEUE:
1319: error = ERESTART;
1320: break;
1321:
1.26.2.1 thorpej 1322: case XS_TIMEOUT:
1323: if (xs->xs_retries != 0) {
1324: xs->xs_retries--;
1325: error = ERESTART;
1326: } else
1327: error = EIO;
1328: break;
1329:
1330: case XS_SELTIMEOUT:
1331: /* XXX Disable device? */
1332: error = EIO;
1333: break;
1334:
1335: case XS_RESET:
1.26.2.9 bouyer 1336: if (xs->xs_control & XS_CTL_REQSENSE) {
1337: /*
1338: * request sense interrupted by reset: signal it
1339: * with EINTR return code.
1340: */
1341: error = EINTR;
1342: } else {
1343: if (xs->xs_retries != 0) {
1344: xs->xs_retries--;
1345: error = ERESTART;
1346: } else
1347: error = EIO;
1348: }
1.26.2.1 thorpej 1349: break;
1.2 bouyer 1350:
1351: default:
1.26.2.1 thorpej 1352: scsipi_printaddr(periph);
1353: printf("invalid return code from adapter: %d\n", xs->error);
1354: error = EIO;
1355: break;
1.2 bouyer 1356: }
1357:
1.26.2.1 thorpej 1358: s = splbio();
1359: if (error == ERESTART) {
1360: /*
1361: * If we get here, the periph has been thawed and frozen
1362: * again if we had to issue recovery commands. Alternatively,
1363: * it may have been frozen again and in a timed thaw. In
1364: * any case, we thaw the periph once we re-enqueue the
1365: * command. Once the periph is fully thawed, it will begin
1366: * operation again.
1367: */
1368: xs->error = XS_NOERROR;
1369: xs->status = SCSI_OK;
1370: xs->xs_status &= ~XS_STS_DONE;
1371: xs->xs_requeuecnt++;
1372: error = scsipi_enqueue(xs);
1373: if (error == 0) {
1374: scsipi_periph_thaw(periph, 1);
1375: splx(s);
1376: return (ERESTART);
1377: }
1378: }
1379:
1380: /*
1381: * scsipi_done() freezes the queue if not XS_NOERROR.
1382: * Thaw it here.
1383: */
1384: if (xs->error != XS_NOERROR)
1385: scsipi_periph_thaw(periph, 1);
1386:
1387: if ((bp = xs->bp) != NULL) {
1388: if (error) {
1389: bp->b_error = error;
1390: bp->b_flags |= B_ERROR;
1391: bp->b_resid = bp->b_bcount;
1392: } else {
1393: bp->b_error = 0;
1394: bp->b_resid = xs->resid;
1395: }
1396: biodone(bp);
1397: }
1398:
1399: if (xs->xs_control & XS_CTL_ASYNC)
1400: scsipi_put_xs(xs);
1401: splx(s);
1402:
1403: return (error);
1404: }
1405:
1406: /*
1.26.2.9 bouyer 1407: * Issue a request sense for the given scsipi_xfer. Called when the xfer
1408: * returns with a CHECK_CONDITION status. Must be called in valid thread
1409: * context and at splbio().
1410: */
1411:
1412: void
1413: scsipi_request_sense(xs)
1414: struct scsipi_xfer *xs;
1415: {
1416: struct scsipi_periph *periph = xs->xs_periph;
1417: int flags, error;
1418: struct scsipi_sense cmd;
1419:
1420: periph->periph_flags |= PERIPH_SENSE;
1421:
1422: /* if command was polling, request sense will too */
1423: flags = xs->xs_control & XS_CTL_POLL;
1424: /* Polling commands can't sleep */
1425: if (flags)
1426: flags |= XS_CTL_NOSLEEP;
1427:
1428: flags |= XS_CTL_REQSENSE | XS_CTL_URGENT | XS_CTL_DATA_IN |
1429: XS_CTL_THAW_PERIPH | XS_CTL_FREEZE_PERIPH;
1430:
1431: bzero(&cmd, sizeof(cmd));
1432: cmd.opcode = REQUEST_SENSE;
1433: cmd.length = sizeof(struct scsipi_sense_data);
1434:
1435: error = scsipi_command(periph,
1436: (struct scsipi_generic *) &cmd, sizeof(cmd),
1437: (u_char*)&xs->sense.scsi_sense, sizeof(struct scsipi_sense_data),
1438: 0, 1000, NULL, flags);
1439: periph->periph_flags &= ~PERIPH_SENSE;
1440: periph->periph_xscheck = NULL;
1441: switch(error) {
1442: case 0:
1443: /* we have a valid sense */
1444: xs->error = XS_SENSE;
1445: return;
1446: case EINTR:
1447: /* REQUEST_SENSE interrupted by bus reset. */
1448: xs->error = XS_RESET;
1.26.2.12 bouyer 1449: return;
1450: case EIO:
1451: /* request sense coudn't be performed */
1452: /*
1453: * XXX this isn't quite rigth but we don't have anything
1454: * better for now
1455: */
1456: xs->error = XS_DRIVER_STUFFUP;
1.26.2.9 bouyer 1457: return;
1458: default:
1459: /* Notify that request sense failed. */
1460: xs->error = XS_DRIVER_STUFFUP;
1461: scsipi_printaddr(periph);
1462: printf("request sense failed with error %d\n", error);
1463: return;
1464: }
1465: }
1466:
1467: /*
1.26.2.1 thorpej 1468: * scsipi_enqueue:
1469: *
1470: * Enqueue an xfer on a channel.
1471: */
1472: int
1473: scsipi_enqueue(xs)
1474: struct scsipi_xfer *xs;
1475: {
1476: struct scsipi_channel *chan = xs->xs_periph->periph_channel;
1477: struct scsipi_xfer *qxs;
1478: int s;
1479:
1480: s = splbio();
1481:
1482: /*
1483: * If the xfer is to be polled, and there are already jobs on
1484: * the queue, we can't proceed.
1485: */
1486: if ((xs->xs_control & XS_CTL_POLL) != 0 &&
1487: TAILQ_FIRST(&chan->chan_queue) != NULL) {
1488: splx(s);
1489: xs->error = XS_DRIVER_STUFFUP;
1490: return (EAGAIN);
1491: }
1492:
1493: /*
1494: * If we have an URGENT xfer, it's an error recovery command
1495: * and it should just go on the head of the channel's queue.
1496: */
1497: if (xs->xs_control & XS_CTL_URGENT) {
1498: TAILQ_INSERT_HEAD(&chan->chan_queue, xs, channel_q);
1499: goto out;
1500: }
1501:
1502: /*
1503: * If this xfer has already been on the queue before, we
1504: * need to reinsert it in the correct order. That order is:
1505: *
1506: * Immediately before the first xfer for this periph
1507: * with a requeuecnt less than xs->xs_requeuecnt.
1508: *
1509: * Failing that, at the end of the queue. (We'll end up
1510: * there naturally.)
1511: */
1512: if (xs->xs_requeuecnt != 0) {
1513: for (qxs = TAILQ_FIRST(&chan->chan_queue); qxs != NULL;
1514: qxs = TAILQ_NEXT(qxs, channel_q)) {
1515: if (qxs->xs_periph == xs->xs_periph &&
1516: qxs->xs_requeuecnt < xs->xs_requeuecnt)
1517: break;
1518: }
1519: if (qxs != NULL) {
1520: TAILQ_INSERT_AFTER(&chan->chan_queue, qxs, xs,
1521: channel_q);
1522: goto out;
1523: }
1524: }
1525: TAILQ_INSERT_TAIL(&chan->chan_queue, xs, channel_q);
1526: out:
1527: if (xs->xs_control & XS_CTL_THAW_PERIPH)
1528: scsipi_periph_thaw(xs->xs_periph, 1);
1529: splx(s);
1530: return (0);
1531: }
1532:
1533: /*
1534: * scsipi_run_queue:
1535: *
1536: * Start as many xfers as possible running on the channel.
1537: */
1538: void
1539: scsipi_run_queue(chan)
1540: struct scsipi_channel *chan;
1541: {
1542: struct scsipi_xfer *xs;
1543: struct scsipi_periph *periph;
1544: int s;
1545:
1546: for (;;) {
1547: s = splbio();
1.26.2.3 thorpej 1548:
1549: /*
1550: * If the channel is frozen, we can't do any work right
1551: * now.
1552: */
1553: if (chan->chan_qfreeze != 0) {
1554: splx(s);
1555: return;
1556: }
1557:
1.26.2.1 thorpej 1558: /*
1559: * Look for work to do, and make sure we can do it.
1560: */
1561: for (xs = TAILQ_FIRST(&chan->chan_queue); xs != NULL;
1562: xs = TAILQ_NEXT(xs, channel_q)) {
1563: periph = xs->xs_periph;
1564:
1.26.2.15 bouyer 1565: if ((periph->periph_sent >= periph->periph_openings) ||
1566: periph->periph_qfreeze != 0 ||
1.26.2.13 bouyer 1567: (periph->periph_flags & PERIPH_UNTAG) != 0)
1.26.2.1 thorpej 1568: continue;
1569:
1.26.2.9 bouyer 1570: if ((periph->periph_flags &
1571: (PERIPH_RECOVERING | PERIPH_SENSE)) != 0 &&
1.26.2.1 thorpej 1572: (xs->xs_control & XS_CTL_URGENT) == 0)
1573: continue;
1574:
1575: /*
1576: * We can issue this xfer!
1577: */
1578: goto got_one;
1579: }
1580:
1581: /*
1582: * Can't find any work to do right now.
1583: */
1584: splx(s);
1585: return;
1586:
1587: got_one:
1588: /*
1589: * Have an xfer to run. Allocate a resource from
1590: * the adapter to run it. If we can't allocate that
1591: * resource, we don't dequeue the xfer.
1592: */
1593: if (scsipi_get_resource(chan) == 0) {
1594: /*
1595: * Adapter is out of resources. If the adapter
1596: * supports it, attempt to grow them.
1597: */
1598: if (scsipi_grow_resources(chan) == 0) {
1599: /*
1600: * Wasn't able to grow resources,
1601: * nothing more we can do.
1602: */
1603: if (xs->xs_control & XS_CTL_POLL) {
1604: scsipi_printaddr(xs->xs_periph);
1605: printf("polling command but no "
1606: "adapter resources");
1607: /* We'll panic shortly... */
1608: }
1609: splx(s);
1.26.2.16 mjacob 1610:
1611: /*
1612: * XXX: We should be able to note that
1613: * XXX: that resources are needed here!
1614: */
1.26.2.1 thorpej 1615: return;
1616: }
1617: /*
1618: * scsipi_grow_resources() allocated the resource
1619: * for us.
1620: */
1621: }
1622:
1623: /*
1624: * We have a resource to run this xfer, do it!
1625: */
1626: TAILQ_REMOVE(&chan->chan_queue, xs, channel_q);
1627:
1628: /*
1629: * If the command is to be tagged, allocate a tag ID
1630: * for it.
1631: */
1632: if (XS_CTL_TAGTYPE(xs) != 0)
1633: scsipi_get_tag(xs);
1.26.2.13 bouyer 1634: else
1635: periph->periph_flags |= PERIPH_UNTAG;
1.26.2.15 bouyer 1636: periph->periph_sent++;
1.26.2.1 thorpej 1637: splx(s);
1638:
1639: scsipi_adapter_request(chan, ADAPTER_REQ_RUN_XFER, xs);
1640: }
1.2 bouyer 1641: #ifdef DIAGNOSTIC
1.26.2.1 thorpej 1642: panic("scsipi_run_queue: impossible");
1.2 bouyer 1643: #endif
1644: }
1645:
1.26.2.1 thorpej 1646: /*
1647: * scsipi_execute_xs:
1648: *
1649: * Begin execution of an xfer, waiting for it to complete, if necessary.
1650: */
1.3 enami 1651: int
1.26.2.1 thorpej 1652: scsipi_execute_xs(xs)
1.2 bouyer 1653: struct scsipi_xfer *xs;
1654: {
1.26.2.1 thorpej 1655: struct scsipi_periph *periph = xs->xs_periph;
1656: struct scsipi_channel *chan = periph->periph_channel;
1657: int async, poll, retries, error, s;
1658:
1659: xs->xs_status &= ~XS_STS_DONE;
1660: xs->error = XS_NOERROR;
1661: xs->resid = xs->datalen;
1662: xs->status = SCSI_OK;
1663:
1.26.2.6 thorpej 1664: #ifdef SCSIPI_DEBUG
1665: if (xs->xs_periph->periph_dbflags & SCSIPI_DB3) {
1666: printf("scsipi_execute_xs: ");
1.26.2.1 thorpej 1667: show_scsipi_xs(xs);
1668: printf("\n");
1669: }
1670: #endif
1.2 bouyer 1671:
1.26.2.1 thorpej 1672: /*
1673: * Deal with command tagging:
1674: *
1675: * - If the device's current operating mode doesn't
1676: * include tagged queueing, clear the tag mask.
1677: *
1678: * - If the device's current operating mode *does*
1679: * include tagged queueing, set the tag_type in
1680: * the xfer to the appropriate byte for the tag
1681: * message.
1682: */
1.26.2.9 bouyer 1683: if ((PERIPH_XFER_MODE(periph) & PERIPH_CAP_TQING) == 0 ||
1684: (xs->xs_control & XS_CTL_REQSENSE)) {
1.26.2.1 thorpej 1685: xs->xs_control &= ~XS_CTL_TAGMASK;
1686: xs->xs_tag_type = 0;
1687: } else {
1688: /*
1689: * If the request doesn't specify a tag, give Head
1690: * tags to URGENT operations and Ordered tags to
1691: * everything else.
1692: */
1693: if (XS_CTL_TAGTYPE(xs) == 0) {
1694: if (xs->xs_control & XS_CTL_URGENT)
1695: xs->xs_control |= XS_CTL_HEAD_TAG;
1696: else
1697: xs->xs_control |= XS_CTL_ORDERED_TAG;
1698: }
1699:
1700: switch (XS_CTL_TAGTYPE(xs)) {
1701: case XS_CTL_ORDERED_TAG:
1702: xs->xs_tag_type = MSG_ORDERED_Q_TAG;
1703: break;
1704:
1705: case XS_CTL_SIMPLE_TAG:
1706: xs->xs_tag_type = MSG_SIMPLE_Q_TAG;
1707: break;
1708:
1709: case XS_CTL_HEAD_TAG:
1710: xs->xs_tag_type = MSG_HEAD_OF_Q_TAG;
1711: break;
1712:
1713: default:
1714: scsipi_printaddr(periph);
1715: printf("invalid tag mask 0x%08x\n",
1716: XS_CTL_TAGTYPE(xs));
1717: panic("scsipi_execute_xs");
1718: }
1719: }
1.2 bouyer 1720:
1721: /*
1.26.2.1 thorpej 1722: * If we don't yet have a completion thread, or we are to poll for
1723: * completion, clear the ASYNC flag.
1.2 bouyer 1724: */
1.26.2.1 thorpej 1725: if (chan->chan_thread == NULL || (xs->xs_control & XS_CTL_POLL) != 0)
1726: xs->xs_control &= ~XS_CTL_ASYNC;
1.2 bouyer 1727:
1.26.2.1 thorpej 1728: async = (xs->xs_control & XS_CTL_ASYNC);
1729: poll = (xs->xs_control & XS_CTL_POLL);
1730: retries = xs->xs_retries; /* for polling commands */
1.2 bouyer 1731:
1.26.2.1 thorpej 1732: #ifdef DIAGNOSTIC
1733: if (async != 0 && xs->bp == NULL)
1734: panic("scsipi_execute_xs: XS_CTL_ASYNC but no buf");
1.2 bouyer 1735: #endif
1.26.2.1 thorpej 1736:
1737: /*
1738: * Enqueue the transfer. If we're not polling for completion, this
1739: * should ALWAYS return `no error'.
1740: */
1741: try_again:
1742: error = scsipi_enqueue(xs);
1743: if (error) {
1744: if (poll == 0) {
1745: scsipi_printaddr(periph);
1746: printf("not polling, but enqueue failed with %d\n",
1747: error);
1748: panic("scsipi_execute_xs");
1.2 bouyer 1749: }
1.26.2.1 thorpej 1750:
1751: scsipi_printaddr(periph);
1752: printf("failed to enqueue polling command");
1753: if (retries != 0) {
1754: printf(", retrying...\n");
1755: delay(1000000);
1756: retries--;
1757: goto try_again;
1.2 bouyer 1758: }
1.26.2.1 thorpej 1759: printf("\n");
1760: goto free_xs;
1761: }
1.2 bouyer 1762:
1.26.2.1 thorpej 1763: restarted:
1764: scsipi_run_queue(chan);
1.12 thorpej 1765:
1.26.2.1 thorpej 1766: /*
1767: * The xfer is enqueued, and possibly running. If it's to be
1768: * completed asynchronously, just return now.
1769: */
1770: if (async)
1771: return (EJUSTRETURN);
1772:
1773: /*
1774: * Not an asynchronous command; wait for it to complete.
1775: */
1.26.2.16 mjacob 1776: s = splbio();
1.26.2.1 thorpej 1777: while ((xs->xs_status & XS_STS_DONE) == 0) {
1778: if (poll) {
1779: scsipi_printaddr(periph);
1780: printf("polling command not done\n");
1781: panic("scsipi_execute_xs");
1.12 thorpej 1782: }
1.26.2.1 thorpej 1783: (void) tsleep(xs, PRIBIO, "xscmd", 0);
1784: }
1.26.2.16 mjacob 1785: splx(s);
1.2 bouyer 1786:
1.26.2.1 thorpej 1787: /*
1788: * Command is complete. scsipi_done() has awakened us to perform
1789: * the error handling.
1790: */
1791: error = scsipi_complete(xs);
1792: if (error == ERESTART)
1793: goto restarted;
1794:
1795: /*
1796: * Command completed successfully or fatal error occurred. Fall
1797: * into....
1798: */
1799: free_xs:
1800: s = splbio();
1801: scsipi_put_xs(xs);
1802: splx(s);
1803:
1804: /*
1805: * Kick the queue, keep it running in case it stopped for some
1806: * reason.
1807: */
1808: scsipi_run_queue(chan);
1809:
1810: return (error);
1811: }
1812:
1813: /*
1814: * scsipi_completion_thread:
1815: *
1816: * This is the completion thread. We wait for errors on
1817: * asynchronous xfers, and perform the error handling
1818: * function, restarting the command, if necessary.
1819: */
1820: void
1821: scsipi_completion_thread(arg)
1822: void *arg;
1823: {
1824: struct scsipi_channel *chan = arg;
1825: struct scsipi_xfer *xs;
1826: int s;
1827:
1.26.2.7 thorpej 1828: for (;;) {
1.26.2.1 thorpej 1829: s = splbio();
1.26.2.7 thorpej 1830: xs = TAILQ_FIRST(&chan->chan_complete);
1831: if (xs == NULL &&
1832: (chan->chan_flags & SCSIPI_CHAN_SHUTDOWN) == 0) {
1.26.2.1 thorpej 1833: (void) tsleep(&chan->chan_complete, PRIBIO,
1834: "sccomp", 0);
1.26.2.17! bouyer 1835: splx(s);
1.26.2.1 thorpej 1836: continue;
1.26.2.7 thorpej 1837: }
1838: if (chan->chan_flags & SCSIPI_CHAN_SHUTDOWN) {
1839: splx(s);
1840: break;
1.26.2.1 thorpej 1841: }
1842: TAILQ_REMOVE(&chan->chan_complete, xs, channel_q);
1843: splx(s);
1844:
1845: /*
1846: * Have an xfer with an error; process it.
1847: */
1848: (void) scsipi_complete(xs);
1849:
1850: /*
1851: * Kick the queue; keep it running if it was stopped
1852: * for some reason.
1853: */
1854: scsipi_run_queue(chan);
1855: }
1856:
1857: chan->chan_thread = NULL;
1858:
1859: /* In case parent is waiting for us to exit. */
1860: wakeup(&chan->chan_thread);
1861:
1862: kthread_exit(0);
1863: }
1864:
1865: /*
1866: * scsipi_create_completion_thread:
1867: *
1868: * Callback to actually create the completion thread.
1869: */
1870: void
1871: scsipi_create_completion_thread(arg)
1872: void *arg;
1873: {
1874: struct scsipi_channel *chan = arg;
1875: struct scsipi_adapter *adapt = chan->chan_adapter;
1876:
1877: if (kthread_create1(scsipi_completion_thread, chan,
1878: &chan->chan_thread, "%s:%d", adapt->adapt_dev->dv_xname,
1879: chan->chan_channel)) {
1880: printf("%s: unable to create completion thread for "
1881: "channel %d\n", adapt->adapt_dev->dv_xname,
1882: chan->chan_channel);
1883: panic("scsipi_create_completion_thread");
1884: }
1885: }
1886:
1887: /*
1888: * scsipi_async_event:
1889: *
1890: * Handle an asynchronous event from an adapter.
1891: */
1892: void
1893: scsipi_async_event(chan, event, arg)
1894: struct scsipi_channel *chan;
1895: scsipi_async_event_t event;
1896: void *arg;
1897: {
1898: int s;
1899:
1900: s = splbio();
1901: switch (event) {
1902: case ASYNC_EVENT_MAX_OPENINGS:
1903: scsipi_async_event_max_openings(chan,
1904: (struct scsipi_max_openings *)arg);
1.2 bouyer 1905: break;
1.26.2.2 thorpej 1906:
1907: case ASYNC_EVENT_XFER_MODE:
1908: scsipi_async_event_xfer_mode(chan,
1909: (struct scsipi_xfer_mode *)arg);
1910: break;
1.26.2.9 bouyer 1911: case ASYNC_EVENT_RESET:
1912: scsipi_async_event_channel_reset(chan);
1913: break;
1.2 bouyer 1914: }
1.26.2.1 thorpej 1915: splx(s);
1916: }
1.2 bouyer 1917:
1.26.2.1 thorpej 1918: /*
1919: * scsipi_print_xfer_mode:
1920: *
1921: * Print a periph's capabilities.
1922: */
1923: void
1924: scsipi_print_xfer_mode(periph)
1925: struct scsipi_periph *periph;
1926: {
1927: int period, freq, speed, mbs;
1928:
1929: if ((periph->periph_flags & PERIPH_MODE_VALID) == 0)
1930: return;
1931:
1932: printf("%s: ", periph->periph_dev->dv_xname);
1933: if (periph->periph_mode & PERIPH_CAP_SYNC) {
1934: period = scsipi_sync_factor_to_period(periph->periph_period);
1935: printf("Sync (%d.%dns offset %d)",
1936: period / 10, period % 10, periph->periph_offset);
1937: } else
1938: printf("Async");
1939:
1940: if (periph->periph_mode & PERIPH_CAP_WIDE32)
1941: printf(", 32-bit");
1942: else if (periph->periph_mode & PERIPH_CAP_WIDE16)
1943: printf(", 16-bit");
1944: else
1945: printf(", 8-bit");
1946:
1947: if (periph->periph_mode & PERIPH_CAP_SYNC) {
1948: freq = scsipi_sync_factor_to_freq(periph->periph_period);
1949: speed = freq;
1950: if (periph->periph_mode & PERIPH_CAP_WIDE32)
1951: speed *= 4;
1952: else if (periph->periph_mode & PERIPH_CAP_WIDE16)
1953: speed *= 2;
1954: mbs = speed / 1000;
1955: if (mbs > 0)
1956: printf(" (%d.%03dMB/s)", mbs, speed % 1000);
1957: else
1958: printf(" (%dKB/s)", speed % 1000);
1959: }
1960:
1961: printf(" transfers");
1962:
1963: if (periph->periph_mode & PERIPH_CAP_TQING)
1964: printf(", tagged queueing");
1965:
1966: printf("\n");
1.2 bouyer 1967: }
1968:
1.14 thorpej 1969: /*
1.26.2.1 thorpej 1970: * scsipi_async_event_max_openings:
1971: *
1972: * Update the maximum number of outstanding commands a
1973: * device may have.
1974: */
1975: void
1976: scsipi_async_event_max_openings(chan, mo)
1977: struct scsipi_channel *chan;
1978: struct scsipi_max_openings *mo;
1979: {
1980: struct scsipi_periph *periph;
1.26.2.6 thorpej 1981: int minlun, maxlun;
1.26.2.1 thorpej 1982:
1.26.2.6 thorpej 1983: if (mo->mo_lun == -1) {
1984: /*
1985: * Wildcarded; apply it to all LUNs.
1986: */
1987: minlun = 0;
1988: maxlun = chan->chan_nluns - 1;
1989: } else
1990: minlun = maxlun = mo->mo_lun;
1991:
1992: for (; minlun <= maxlun; minlun++) {
1993: periph = scsipi_lookup_periph(chan, mo->mo_target, minlun);
1994: if (periph == NULL)
1995: continue;
1.26.2.1 thorpej 1996:
1.26.2.6 thorpej 1997: if (mo->mo_openings < periph->periph_openings)
1998: periph->periph_openings = mo->mo_openings;
1999: else if (mo->mo_openings > periph->periph_openings &&
2000: (periph->periph_flags & PERIPH_GROW_OPENINGS) != 0)
2001: periph->periph_openings = mo->mo_openings;
2002: }
1.26.2.2 thorpej 2003: }
2004:
2005: /*
2006: * scsipi_async_event_xfer_mode:
2007: *
2008: * Update the xfer mode for all periphs sharing the
2009: * specified I_T Nexus.
2010: */
2011: void
2012: scsipi_async_event_xfer_mode(chan, xm)
2013: struct scsipi_channel *chan;
2014: struct scsipi_xfer_mode *xm;
2015: {
2016: struct scsipi_periph *periph;
1.26.2.5 thorpej 2017: int lun, announce, mode, period, offset;
1.26.2.2 thorpej 2018:
2019: for (lun = 0; lun < chan->chan_nluns; lun++) {
2020: periph = scsipi_lookup_periph(chan, xm->xm_target, lun);
2021: if (periph == NULL)
2022: continue;
1.26.2.5 thorpej 2023: announce = 0;
2024:
2025: /*
2026: * Clamp the xfer mode down to this periph's capabilities.
2027: */
2028: mode = xm->xm_mode & periph->periph_cap;
2029: if (mode & PERIPH_CAP_SYNC) {
2030: period = xm->xm_period;
2031: offset = xm->xm_offset;
2032: } else {
2033: period = 0;
2034: offset = 0;
2035: }
2036:
2037: /*
2038: * If we do not have a valid xfer mode yet, or the parameters
2039: * are different, announce them.
2040: */
2041: if ((periph->periph_flags & PERIPH_MODE_VALID) == 0 ||
2042: periph->periph_mode != mode ||
2043: periph->periph_period != period ||
2044: periph->periph_offset != offset)
2045: announce = 1;
2046:
2047: periph->periph_mode = mode;
2048: periph->periph_period = period;
2049: periph->periph_offset = offset;
2050: periph->periph_flags |= PERIPH_MODE_VALID;
2051:
2052: if (announce)
2053: scsipi_print_xfer_mode(periph);
2054: }
2055: }
2056:
2057: /*
2058: * scsipi_set_xfer_mode:
2059: *
2060: * Set the xfer mode for the specified I_T Nexus.
2061: */
2062: void
2063: scsipi_set_xfer_mode(chan, target, immed)
2064: struct scsipi_channel *chan;
2065: int target, immed;
2066: {
2067: struct scsipi_xfer_mode xm;
2068: struct scsipi_periph *itperiph;
2069: int lun, s;
2070:
2071: /*
2072: * Go to the minimal xfer mode.
2073: */
2074: xm.xm_target = target;
2075: xm.xm_mode = 0;
2076: xm.xm_period = 0; /* ignored */
2077: xm.xm_offset = 0; /* ignored */
2078:
2079: /*
2080: * Find the first LUN we know about on this I_T Nexus.
2081: */
2082: for (lun = 0; lun < chan->chan_nluns; lun++) {
2083: itperiph = scsipi_lookup_periph(chan, target, lun);
2084: if (itperiph != NULL)
2085: break;
2086: }
2087: if (itperiph != NULL)
2088: xm.xm_mode = itperiph->periph_cap;
2089:
2090: /*
2091: * Now issue the request to the adapter.
2092: */
2093: s = splbio();
2094: scsipi_adapter_request(chan, ADAPTER_REQ_SET_XFER_MODE, &xm);
2095: splx(s);
2096:
2097: /*
2098: * If we want this to happen immediately, issue a dummy command,
2099: * since most adapters can't really negotiate unless they're
2100: * executing a job.
2101: */
2102: if (immed != 0 && itperiph != NULL) {
2103: (void) scsipi_test_unit_ready(itperiph,
2104: XS_CTL_DISCOVERY | XS_CTL_IGNORE_ILLEGAL_REQUEST |
2105: XS_CTL_IGNORE_NOT_READY |
2106: XS_CTL_IGNORE_MEDIA_CHANGE);
1.26.2.2 thorpej 2107: }
1.26.2.1 thorpej 2108: }
1.26.2.9 bouyer 2109:
2110: /*
2111: * scsipi_channel_reset:
2112: *
2113: * handle scsi bus reset
1.26.2.15 bouyer 2114: * called at splbio
1.26.2.9 bouyer 2115: */
2116: void
2117: scsipi_async_event_channel_reset(chan)
2118: struct scsipi_channel *chan;
2119: {
2120: struct scsipi_xfer *xs, *xs_next;
2121: struct scsipi_periph *periph;
2122: int target, lun;
2123:
2124: /*
2125: * Channel has been reset. Also mark as reset pending REQUEST_SENSE
2126: * commands; as the sense is not available any more.
1.26.2.15 bouyer 2127: * can't call scsipi_done() from here, as the command has not been
2128: * sent to the adapter yet (this would corrupt accounting).
1.26.2.9 bouyer 2129: */
2130:
2131: for (xs = TAILQ_FIRST(&chan->chan_queue); xs != NULL; xs = xs_next) {
2132: xs_next = TAILQ_NEXT(xs, channel_q);
2133: if (xs->xs_control & XS_CTL_REQSENSE) {
1.26.2.10 bouyer 2134: TAILQ_REMOVE(&chan->chan_queue, xs, channel_q);
1.26.2.9 bouyer 2135: xs->error = XS_RESET;
1.26.2.15 bouyer 2136: if ((xs->xs_control & XS_CTL_ASYNC) != 0)
2137: TAILQ_INSERT_TAIL(&chan->chan_complete, xs,
2138: channel_q);
1.26.2.9 bouyer 2139: }
2140: }
1.26.2.15 bouyer 2141: wakeup(&chan->chan_complete);
1.26.2.9 bouyer 2142: /* Catch xs with pending sense which may not have a REQSENSE xs yet */
2143: for (target = 0; target < chan->chan_ntargets; target++) {
2144: if (target == chan->chan_id)
2145: continue;
2146: for (lun = 0; lun < chan->chan_nluns; lun++) {
2147: periph = chan->chan_periphs[target][lun];
2148: if (periph) {
2149: xs = periph->periph_xscheck;
2150: if (xs)
2151: xs->error = XS_RESET;
2152: }
2153: }
2154: }
2155: }
2156:
1.26.2.1 thorpej 2157:
2158: /*
2159: * scsipi_adapter_addref:
2160: *
2161: * Add a reference to the adapter pointed to by the provided
2162: * link, enabling the adapter if necessary.
1.14 thorpej 2163: */
2164: int
1.26.2.1 thorpej 2165: scsipi_adapter_addref(adapt)
2166: struct scsipi_adapter *adapt;
1.14 thorpej 2167: {
2168: int s, error = 0;
2169:
2170: s = splbio();
1.26.2.1 thorpej 2171: if (adapt->adapt_refcnt++ == 0 && adapt->adapt_enable != NULL) {
2172: error = (*adapt->adapt_enable)(adapt->adapt_dev, 1);
1.14 thorpej 2173: if (error)
1.26.2.1 thorpej 2174: adapt->adapt_refcnt--;
1.14 thorpej 2175: }
2176: splx(s);
2177: return (error);
2178: }
2179:
2180: /*
1.26.2.1 thorpej 2181: * scsipi_adapter_delref:
2182: *
2183: * Delete a reference to the adapter pointed to by the provided
2184: * link, disabling the adapter if possible.
1.14 thorpej 2185: */
2186: void
1.26.2.1 thorpej 2187: scsipi_adapter_delref(adapt)
2188: struct scsipi_adapter *adapt;
1.14 thorpej 2189: {
2190: int s;
2191:
2192: s = splbio();
1.26.2.1 thorpej 2193: if (adapt->adapt_refcnt-- == 1 && adapt->adapt_enable != NULL)
2194: (void) (*adapt->adapt_enable)(adapt->adapt_dev, 0);
1.14 thorpej 2195: splx(s);
2196: }
2197:
1.26.2.1 thorpej 2198: struct scsipi_syncparam {
2199: int ss_factor;
2200: int ss_period; /* ns * 10 */
2201: } scsipi_syncparams[] = {
2202: { 0x0a, 250 },
2203: { 0x0b, 303 },
2204: { 0x0c, 500 },
2205: };
2206: const int scsipi_nsyncparams =
2207: sizeof(scsipi_syncparams) / sizeof(scsipi_syncparams[0]);
2208:
2209: int
2210: scsipi_sync_period_to_factor(period)
2211: int period; /* ns * 10 */
2212: {
2213: int i;
2214:
2215: for (i = 0; i < scsipi_nsyncparams; i++) {
2216: if (period <= scsipi_syncparams[i].ss_period)
2217: return (scsipi_syncparams[i].ss_factor);
2218: }
2219:
2220: return ((period / 10) / 4);
2221: }
2222:
2223: int
2224: scsipi_sync_factor_to_period(factor)
2225: int factor;
2226: {
2227: int i;
2228:
2229: for (i = 0; i < scsipi_nsyncparams; i++) {
2230: if (factor == scsipi_syncparams[i].ss_factor)
2231: return (scsipi_syncparams[i].ss_period);
2232: }
2233:
2234: return ((factor * 4) * 10);
2235: }
2236:
2237: int
2238: scsipi_sync_factor_to_freq(factor)
2239: int factor;
2240: {
2241: int i;
2242:
2243: for (i = 0; i < scsipi_nsyncparams; i++) {
2244: if (factor == scsipi_syncparams[i].ss_factor)
2245: return (10000000 / scsipi_syncparams[i].ss_period);
2246: }
2247:
2248: return (10000000 / ((factor * 4) * 10));
2249: }
2250:
1.26.2.6 thorpej 2251: #ifdef SCSIPI_DEBUG
1.2 bouyer 2252: /*
2253: * Given a scsipi_xfer, dump the request, in all it's glory
2254: */
2255: void
2256: show_scsipi_xs(xs)
2257: struct scsipi_xfer *xs;
2258: {
1.3 enami 2259:
1.2 bouyer 2260: printf("xs(%p): ", xs);
1.24 thorpej 2261: printf("xs_control(0x%08x)", xs->xs_control);
2262: printf("xs_status(0x%08x)", xs->xs_status);
1.26.2.6 thorpej 2263: printf("periph(%p)", xs->xs_periph);
1.26.2.1 thorpej 2264: printf("retr(0x%x)", xs->xs_retries);
1.2 bouyer 2265: printf("timo(0x%x)", xs->timeout);
2266: printf("cmd(%p)", xs->cmd);
2267: printf("len(0x%x)", xs->cmdlen);
2268: printf("data(%p)", xs->data);
2269: printf("len(0x%x)", xs->datalen);
2270: printf("res(0x%x)", xs->resid);
2271: printf("err(0x%x)", xs->error);
2272: printf("bp(%p)", xs->bp);
2273: show_scsipi_cmd(xs);
2274: }
2275:
2276: void
2277: show_scsipi_cmd(xs)
2278: struct scsipi_xfer *xs;
2279: {
2280: u_char *b = (u_char *) xs->cmd;
1.3 enami 2281: int i = 0;
1.2 bouyer 2282:
1.26.2.6 thorpej 2283: scsipi_printaddr(xs->xs_periph);
2284: printf(" command: ");
1.2 bouyer 2285:
1.24 thorpej 2286: if ((xs->xs_control & XS_CTL_RESET) == 0) {
1.2 bouyer 2287: while (i < xs->cmdlen) {
2288: if (i)
2289: printf(",");
2290: printf("0x%x", b[i++]);
2291: }
2292: printf("-[%d bytes]\n", xs->datalen);
2293: if (xs->datalen)
2294: show_mem(xs->data, min(64, xs->datalen));
2295: } else
2296: printf("-RESET-\n");
2297: }
2298:
2299: void
2300: show_mem(address, num)
2301: u_char *address;
2302: int num;
2303: {
2304: int x;
2305:
2306: printf("------------------------------");
2307: for (x = 0; x < num; x++) {
2308: if ((x % 16) == 0)
2309: printf("\n%03d: ", x);
2310: printf("%02x ", *address++);
2311: }
2312: printf("\n------------------------------\n");
2313: }
1.26.2.6 thorpej 2314: #endif /* SCSIPI_DEBUG */
CVSweb <webmaster@jp.NetBSD.org>