scsipi_base.c revision 1.33 1 1.33 enami /* $NetBSD: scsipi_base.c,v 1.33 2000/04/03 01:40:51 enami Exp $ */
2 1.2 bouyer
3 1.8 mycroft /*-
4 1.8 mycroft * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 1.8 mycroft * All rights reserved.
6 1.8 mycroft *
7 1.8 mycroft * This code is derived from software contributed to The NetBSD Foundation
8 1.8 mycroft * by Charles M. Hannum.
9 1.2 bouyer *
10 1.2 bouyer * Redistribution and use in source and binary forms, with or without
11 1.2 bouyer * modification, are permitted provided that the following conditions
12 1.2 bouyer * are met:
13 1.2 bouyer * 1. Redistributions of source code must retain the above copyright
14 1.2 bouyer * notice, this list of conditions and the following disclaimer.
15 1.2 bouyer * 2. Redistributions in binary form must reproduce the above copyright
16 1.2 bouyer * notice, this list of conditions and the following disclaimer in the
17 1.2 bouyer * documentation and/or other materials provided with the distribution.
18 1.2 bouyer * 3. All advertising materials mentioning features or use of this software
19 1.2 bouyer * must display the following acknowledgement:
20 1.8 mycroft * This product includes software developed by the NetBSD
21 1.8 mycroft * Foundation, Inc. and its contributors.
22 1.8 mycroft * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.8 mycroft * contributors may be used to endorse or promote products derived
24 1.8 mycroft * from this software without specific prior written permission.
25 1.2 bouyer *
26 1.8 mycroft * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.8 mycroft * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.8 mycroft * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.8 mycroft * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.8 mycroft * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.8 mycroft * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.8 mycroft * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.8 mycroft * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.8 mycroft * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.8 mycroft * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.8 mycroft * POSSIBILITY OF SUCH DAMAGE.
37 1.2 bouyer */
38 1.2 bouyer
39 1.13 bouyer #include "opt_scsi.h"
40 1.13 bouyer
41 1.2 bouyer #include <sys/types.h>
42 1.2 bouyer #include <sys/param.h>
43 1.2 bouyer #include <sys/systm.h>
44 1.2 bouyer #include <sys/kernel.h>
45 1.2 bouyer #include <sys/buf.h>
46 1.2 bouyer #include <sys/uio.h>
47 1.2 bouyer #include <sys/malloc.h>
48 1.6 thorpej #include <sys/pool.h>
49 1.2 bouyer #include <sys/errno.h>
50 1.2 bouyer #include <sys/device.h>
51 1.2 bouyer #include <sys/proc.h>
52 1.2 bouyer
53 1.2 bouyer #include <dev/scsipi/scsipi_all.h>
54 1.2 bouyer #include <dev/scsipi/scsipi_disk.h>
55 1.2 bouyer #include <dev/scsipi/scsipiconf.h>
56 1.2 bouyer #include <dev/scsipi/scsipi_base.h>
57 1.2 bouyer
58 1.6 thorpej struct pool scsipi_xfer_pool;
59 1.6 thorpej
60 1.3 enami int sc_err1 __P((struct scsipi_xfer *, int));
61 1.2 bouyer
62 1.2 bouyer /*
63 1.6 thorpej * Called when a scsibus is attached to initialize global data.
64 1.6 thorpej */
65 1.6 thorpej void
66 1.6 thorpej scsipi_init()
67 1.6 thorpej {
68 1.6 thorpej static int scsipi_init_done;
69 1.6 thorpej
70 1.6 thorpej if (scsipi_init_done)
71 1.6 thorpej return;
72 1.6 thorpej scsipi_init_done = 1;
73 1.6 thorpej
74 1.6 thorpej /* Initialize the scsipi_xfer pool. */
75 1.6 thorpej pool_init(&scsipi_xfer_pool, sizeof(struct scsipi_xfer), 0,
76 1.6 thorpej 0, 0, "scxspl", 0, NULL, NULL, M_DEVBUF);
77 1.6 thorpej }
78 1.6 thorpej
79 1.6 thorpej /*
80 1.2 bouyer * Get a scsipi transfer structure for the caller. Charge the structure
81 1.3 enami * to the device that is referenced by the sc_link structure. If the
82 1.2 bouyer * sc_link structure has no 'credits' then the device already has the
83 1.2 bouyer * maximum number or outstanding operations under way. In this stage,
84 1.2 bouyer * wait on the structure so that when one is freed, we are awoken again
85 1.24 thorpej * If the XS_CTL_NOSLEEP flag is set, then do not wait, but rather, return
86 1.2 bouyer * a NULL pointer, signifying that no slots were available
87 1.2 bouyer * Note in the link structure, that we are waiting on it.
88 1.2 bouyer */
89 1.2 bouyer
90 1.2 bouyer struct scsipi_xfer *
91 1.2 bouyer scsipi_get_xs(sc_link, flags)
92 1.2 bouyer struct scsipi_link *sc_link; /* who to charge the xs to */
93 1.2 bouyer int flags; /* if this call can sleep */
94 1.2 bouyer {
95 1.2 bouyer struct scsipi_xfer *xs;
96 1.2 bouyer int s;
97 1.2 bouyer
98 1.2 bouyer SC_DEBUG(sc_link, SDEV_DB3, ("scsipi_get_xs\n"));
99 1.6 thorpej
100 1.24 thorpej /*
101 1.24 thorpej * If we're cold, make sure we poll.
102 1.24 thorpej */
103 1.24 thorpej if (cold)
104 1.24 thorpej flags |= XS_CTL_NOSLEEP | XS_CTL_POLL;
105 1.24 thorpej
106 1.2 bouyer s = splbio();
107 1.24 thorpej while (sc_link->active >= sc_link->openings) {
108 1.2 bouyer SC_DEBUG(sc_link, SDEV_DB3, ("sleeping\n"));
109 1.24 thorpej if ((flags & XS_CTL_NOSLEEP) != 0) {
110 1.2 bouyer splx(s);
111 1.3 enami return (0);
112 1.2 bouyer }
113 1.2 bouyer sc_link->flags |= SDEV_WAITING;
114 1.3 enami (void)tsleep(sc_link, PRIBIO, "getxs", 0);
115 1.2 bouyer }
116 1.6 thorpej SC_DEBUG(sc_link, SDEV_DB3, ("calling pool_get\n"));
117 1.6 thorpej xs = pool_get(&scsipi_xfer_pool,
118 1.24 thorpej ((flags & XS_CTL_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK));
119 1.6 thorpej if (xs != NULL)
120 1.24 thorpej sc_link->active++;
121 1.6 thorpej else {
122 1.6 thorpej (*sc_link->sc_print_addr)(sc_link);
123 1.6 thorpej printf("cannot allocate scsipi xs\n");
124 1.2 bouyer }
125 1.6 thorpej splx(s);
126 1.2 bouyer
127 1.2 bouyer SC_DEBUG(sc_link, SDEV_DB3, ("returning\n"));
128 1.6 thorpej
129 1.3 enami /*
130 1.7 scottr * zeroes out the command, as ATAPI may use longer commands
131 1.3 enami * than SCSI
132 1.3 enami */
133 1.7 scottr if (xs != NULL) {
134 1.30 thorpej callout_init(&xs->xs_callout);
135 1.24 thorpej xs->xs_control = flags;
136 1.15 thorpej TAILQ_INSERT_TAIL(&sc_link->pending_xfers, xs, device_q);
137 1.7 scottr bzero(&xs->cmdstore, sizeof(xs->cmdstore));
138 1.7 scottr }
139 1.3 enami return (xs);
140 1.2 bouyer }
141 1.2 bouyer
142 1.2 bouyer /*
143 1.2 bouyer * Given a scsipi_xfer struct, and a device (referenced through sc_link)
144 1.2 bouyer * return the struct to the free pool and credit the device with it
145 1.2 bouyer * If another process is waiting for an xs, do a wakeup, let it proceed
146 1.6 thorpej *
147 1.6 thorpej * MUST BE CALLED AT splbio()!!
148 1.2 bouyer */
149 1.3 enami void
150 1.2 bouyer scsipi_free_xs(xs, flags)
151 1.2 bouyer struct scsipi_xfer *xs;
152 1.2 bouyer int flags;
153 1.2 bouyer {
154 1.2 bouyer struct scsipi_link *sc_link = xs->sc_link;
155 1.2 bouyer
156 1.15 thorpej TAILQ_REMOVE(&sc_link->pending_xfers, xs, device_q);
157 1.15 thorpej if (TAILQ_FIRST(&sc_link->pending_xfers) == NULL &&
158 1.16 thorpej (sc_link->flags & SDEV_WAITDRAIN) != 0) {
159 1.16 thorpej sc_link->flags &= ~SDEV_WAITDRAIN;
160 1.15 thorpej wakeup(&sc_link->pending_xfers);
161 1.16 thorpej }
162 1.6 thorpej pool_put(&scsipi_xfer_pool, xs);
163 1.2 bouyer
164 1.2 bouyer SC_DEBUG(sc_link, SDEV_DB3, ("scsipi_free_xs\n"));
165 1.2 bouyer /* if was 0 and someone waits, wake them up */
166 1.24 thorpej sc_link->active--;
167 1.2 bouyer if ((sc_link->flags & SDEV_WAITING) != 0) {
168 1.2 bouyer sc_link->flags &= ~SDEV_WAITING;
169 1.2 bouyer wakeup(sc_link);
170 1.2 bouyer } else {
171 1.2 bouyer if (sc_link->device->start) {
172 1.3 enami SC_DEBUG(sc_link, SDEV_DB2,
173 1.3 enami ("calling private start()\n"));
174 1.3 enami (*(sc_link->device->start))(sc_link->device_softc);
175 1.2 bouyer }
176 1.2 bouyer }
177 1.15 thorpej }
178 1.15 thorpej
179 1.15 thorpej /*
180 1.15 thorpej * Wait for a scsipi_link's pending xfers to drain.
181 1.15 thorpej */
182 1.15 thorpej void
183 1.15 thorpej scsipi_wait_drain(sc_link)
184 1.15 thorpej struct scsipi_link *sc_link;
185 1.15 thorpej {
186 1.15 thorpej int s;
187 1.15 thorpej
188 1.15 thorpej s = splbio();
189 1.16 thorpej while (TAILQ_FIRST(&sc_link->pending_xfers) != NULL) {
190 1.15 thorpej sc_link->flags |= SDEV_WAITDRAIN;
191 1.15 thorpej (void) tsleep(&sc_link->pending_xfers, PRIBIO, "sxdrn", 0);
192 1.15 thorpej }
193 1.15 thorpej splx(s);
194 1.23 thorpej }
195 1.23 thorpej
196 1.23 thorpej /*
197 1.23 thorpej * Kill off all pending xfers for a scsipi_link.
198 1.23 thorpej *
199 1.23 thorpej * Must be called at splbio().
200 1.23 thorpej */
201 1.23 thorpej void
202 1.23 thorpej scsipi_kill_pending(sc_link)
203 1.23 thorpej struct scsipi_link *sc_link;
204 1.23 thorpej {
205 1.23 thorpej
206 1.27 enami (*sc_link->scsipi_kill_pending)(sc_link);
207 1.27 enami #ifdef DIAGNOSTIC
208 1.27 enami if (TAILQ_FIRST(&sc_link->pending_xfers) != NULL)
209 1.27 enami panic("scsipi_kill_pending");
210 1.27 enami #endif
211 1.2 bouyer }
212 1.2 bouyer
213 1.2 bouyer /*
214 1.13 bouyer * Look at the returned sense and act on the error, determining
215 1.13 bouyer * the unix error number to pass back. (0 = report no error)
216 1.13 bouyer *
217 1.13 bouyer * THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES
218 1.13 bouyer */
219 1.13 bouyer int
220 1.13 bouyer scsipi_interpret_sense(xs)
221 1.13 bouyer struct scsipi_xfer *xs;
222 1.13 bouyer {
223 1.13 bouyer struct scsipi_sense_data *sense;
224 1.13 bouyer struct scsipi_link *sc_link = xs->sc_link;
225 1.13 bouyer u_int8_t key;
226 1.13 bouyer u_int32_t info;
227 1.13 bouyer int error;
228 1.13 bouyer #ifndef SCSIVERBOSE
229 1.13 bouyer static char *error_mes[] = {
230 1.13 bouyer "soft error (corrected)",
231 1.13 bouyer "not ready", "medium error",
232 1.13 bouyer "non-media hardware failure", "illegal request",
233 1.13 bouyer "unit attention", "readonly device",
234 1.13 bouyer "no data found", "vendor unique",
235 1.13 bouyer "copy aborted", "command aborted",
236 1.13 bouyer "search returned equal", "volume overflow",
237 1.13 bouyer "verify miscompare", "unknown error key"
238 1.13 bouyer };
239 1.13 bouyer #endif
240 1.13 bouyer
241 1.13 bouyer sense = &xs->sense.scsi_sense;
242 1.13 bouyer #ifdef SCSIDEBUG
243 1.13 bouyer if ((sc_link->flags & SDEV_DB1) != 0) {
244 1.13 bouyer int count;
245 1.13 bouyer printf("code 0x%x valid 0x%x ",
246 1.13 bouyer sense->error_code & SSD_ERRCODE,
247 1.13 bouyer sense->error_code & SSD_ERRCODE_VALID ? 1 : 0);
248 1.13 bouyer printf("seg 0x%x key 0x%x ili 0x%x eom 0x%x fmark 0x%x\n",
249 1.13 bouyer sense->segment,
250 1.13 bouyer sense->flags & SSD_KEY,
251 1.13 bouyer sense->flags & SSD_ILI ? 1 : 0,
252 1.13 bouyer sense->flags & SSD_EOM ? 1 : 0,
253 1.13 bouyer sense->flags & SSD_FILEMARK ? 1 : 0);
254 1.13 bouyer printf("info: 0x%x 0x%x 0x%x 0x%x followed by %d extra bytes\n",
255 1.13 bouyer sense->info[0],
256 1.13 bouyer sense->info[1],
257 1.13 bouyer sense->info[2],
258 1.13 bouyer sense->info[3],
259 1.13 bouyer sense->extra_len);
260 1.13 bouyer printf("extra: ");
261 1.13 bouyer for (count = 0; count < ADD_BYTES_LIM(sense); count++)
262 1.13 bouyer printf("0x%x ", sense->cmd_spec_info[count]);
263 1.13 bouyer printf("\n");
264 1.13 bouyer }
265 1.13 bouyer #endif /* SCSIDEBUG */
266 1.13 bouyer /*
267 1.13 bouyer * If the device has it's own error handler, call it first.
268 1.13 bouyer * If it returns a legit error value, return that, otherwise
269 1.13 bouyer * it wants us to continue with normal error processing.
270 1.13 bouyer */
271 1.13 bouyer if (sc_link->device->err_handler) {
272 1.13 bouyer SC_DEBUG(sc_link, SDEV_DB2,
273 1.13 bouyer ("calling private err_handler()\n"));
274 1.13 bouyer error = (*sc_link->device->err_handler)(xs);
275 1.13 bouyer if (error != SCSIRET_CONTINUE)
276 1.13 bouyer return (error); /* error >= 0 better ? */
277 1.13 bouyer }
278 1.13 bouyer /* otherwise use the default */
279 1.13 bouyer switch (sense->error_code & SSD_ERRCODE) {
280 1.13 bouyer /*
281 1.13 bouyer * If it's code 70, use the extended stuff and
282 1.13 bouyer * interpret the key
283 1.13 bouyer */
284 1.13 bouyer case 0x71: /* delayed error */
285 1.13 bouyer sc_link->sc_print_addr(sc_link);
286 1.13 bouyer key = sense->flags & SSD_KEY;
287 1.13 bouyer printf(" DEFERRED ERROR, key = 0x%x\n", key);
288 1.13 bouyer /* FALLTHROUGH */
289 1.13 bouyer case 0x70:
290 1.13 bouyer if ((sense->error_code & SSD_ERRCODE_VALID) != 0)
291 1.13 bouyer info = _4btol(sense->info);
292 1.13 bouyer else
293 1.13 bouyer info = 0;
294 1.13 bouyer key = sense->flags & SSD_KEY;
295 1.13 bouyer
296 1.13 bouyer switch (key) {
297 1.13 bouyer case SKEY_NO_SENSE:
298 1.13 bouyer case SKEY_RECOVERED_ERROR:
299 1.13 bouyer if (xs->resid == xs->datalen && xs->datalen) {
300 1.13 bouyer /*
301 1.13 bouyer * Why is this here?
302 1.13 bouyer */
303 1.13 bouyer xs->resid = 0; /* not short read */
304 1.13 bouyer }
305 1.13 bouyer case SKEY_EQUAL:
306 1.13 bouyer error = 0;
307 1.13 bouyer break;
308 1.13 bouyer case SKEY_NOT_READY:
309 1.13 bouyer if ((sc_link->flags & SDEV_REMOVABLE) != 0)
310 1.13 bouyer sc_link->flags &= ~SDEV_MEDIA_LOADED;
311 1.24 thorpej if ((xs->xs_control & XS_CTL_IGNORE_NOT_READY) != 0)
312 1.13 bouyer return (0);
313 1.19 bouyer if (sense->add_sense_code == 0x3A &&
314 1.19 bouyer sense->add_sense_code_qual == 0x00)
315 1.19 bouyer error = ENODEV; /* Medium not present */
316 1.19 bouyer else
317 1.19 bouyer error = EIO;
318 1.24 thorpej if ((xs->xs_control & XS_CTL_SILENT) != 0)
319 1.19 bouyer return (error);
320 1.13 bouyer break;
321 1.13 bouyer case SKEY_ILLEGAL_REQUEST:
322 1.24 thorpej if ((xs->xs_control &
323 1.24 thorpej XS_CTL_IGNORE_ILLEGAL_REQUEST) != 0)
324 1.13 bouyer return (0);
325 1.24 thorpej /*
326 1.24 thorpej * Handle the case where a device reports
327 1.24 thorpej * Logical Unit Not Supported during discovery.
328 1.24 thorpej */
329 1.24 thorpej if ((xs->xs_control & XS_CTL_DISCOVERY) != 0 &&
330 1.24 thorpej sense->add_sense_code == 0x25 &&
331 1.24 thorpej sense->add_sense_code_qual == 0x00)
332 1.24 thorpej return (EINVAL);
333 1.24 thorpej if ((xs->xs_control & XS_CTL_SILENT) != 0)
334 1.13 bouyer return (EIO);
335 1.13 bouyer error = EINVAL;
336 1.13 bouyer break;
337 1.13 bouyer case SKEY_UNIT_ATTENTION:
338 1.20 bouyer if (sense->add_sense_code == 0x29 &&
339 1.20 bouyer sense->add_sense_code_qual == 0x00)
340 1.20 bouyer return (ERESTART); /* device or bus reset */
341 1.13 bouyer if ((sc_link->flags & SDEV_REMOVABLE) != 0)
342 1.13 bouyer sc_link->flags &= ~SDEV_MEDIA_LOADED;
343 1.24 thorpej if ((xs->xs_control &
344 1.24 thorpej XS_CTL_IGNORE_MEDIA_CHANGE) != 0 ||
345 1.13 bouyer /* XXX Should reupload any transient state. */
346 1.13 bouyer (sc_link->flags & SDEV_REMOVABLE) == 0)
347 1.13 bouyer return (ERESTART);
348 1.24 thorpej if ((xs->xs_control & XS_CTL_SILENT) != 0)
349 1.13 bouyer return (EIO);
350 1.13 bouyer error = EIO;
351 1.13 bouyer break;
352 1.13 bouyer case SKEY_WRITE_PROTECT:
353 1.13 bouyer error = EROFS;
354 1.13 bouyer break;
355 1.13 bouyer case SKEY_BLANK_CHECK:
356 1.13 bouyer error = 0;
357 1.13 bouyer break;
358 1.13 bouyer case SKEY_ABORTED_COMMAND:
359 1.13 bouyer error = ERESTART;
360 1.13 bouyer break;
361 1.13 bouyer case SKEY_VOLUME_OVERFLOW:
362 1.13 bouyer error = ENOSPC;
363 1.13 bouyer break;
364 1.13 bouyer default:
365 1.13 bouyer error = EIO;
366 1.13 bouyer break;
367 1.13 bouyer }
368 1.13 bouyer
369 1.13 bouyer #ifdef SCSIVERBOSE
370 1.32 augustss if (key && (xs->xs_control & XS_CTL_SILENT) == 0)
371 1.13 bouyer scsipi_print_sense(xs, 0);
372 1.13 bouyer #else
373 1.13 bouyer if (key) {
374 1.13 bouyer sc_link->sc_print_addr(sc_link);
375 1.13 bouyer printf("%s", error_mes[key - 1]);
376 1.13 bouyer if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
377 1.13 bouyer switch (key) {
378 1.13 bouyer case SKEY_NOT_READY:
379 1.13 bouyer case SKEY_ILLEGAL_REQUEST:
380 1.13 bouyer case SKEY_UNIT_ATTENTION:
381 1.13 bouyer case SKEY_WRITE_PROTECT:
382 1.13 bouyer break;
383 1.13 bouyer case SKEY_BLANK_CHECK:
384 1.13 bouyer printf(", requested size: %d (decimal)",
385 1.13 bouyer info);
386 1.13 bouyer break;
387 1.13 bouyer case SKEY_ABORTED_COMMAND:
388 1.13 bouyer if (xs->retries)
389 1.13 bouyer printf(", retrying");
390 1.13 bouyer printf(", cmd 0x%x, info 0x%x",
391 1.13 bouyer xs->cmd->opcode, info);
392 1.13 bouyer break;
393 1.13 bouyer default:
394 1.13 bouyer printf(", info = %d (decimal)", info);
395 1.13 bouyer }
396 1.13 bouyer }
397 1.13 bouyer if (sense->extra_len != 0) {
398 1.13 bouyer int n;
399 1.13 bouyer printf(", data =");
400 1.13 bouyer for (n = 0; n < sense->extra_len; n++)
401 1.13 bouyer printf(" %02x",
402 1.13 bouyer sense->cmd_spec_info[n]);
403 1.13 bouyer }
404 1.13 bouyer printf("\n");
405 1.13 bouyer }
406 1.13 bouyer #endif
407 1.13 bouyer return (error);
408 1.13 bouyer
409 1.13 bouyer /*
410 1.13 bouyer * Not code 70, just report it
411 1.13 bouyer */
412 1.13 bouyer default:
413 1.28 mjacob #if defined(SCSIDEBUG) || defined(DEBUG)
414 1.28 mjacob {
415 1.28 mjacob static char *uc = "undecodable sense error";
416 1.28 mjacob int i;
417 1.28 mjacob u_int8_t *cptr = (u_int8_t *) sense;
418 1.28 mjacob sc_link->sc_print_addr(sc_link);
419 1.28 mjacob if (xs->cmd == &xs->cmdstore) {
420 1.28 mjacob printf("%s for opcode 0x%x, data=",
421 1.28 mjacob uc, xs->cmdstore.opcode);
422 1.28 mjacob } else {
423 1.28 mjacob printf("%s, data=", uc);
424 1.28 mjacob }
425 1.28 mjacob for (i = 0; i < sizeof (sense); i++)
426 1.28 mjacob printf(" 0x%02x", *(cptr++) & 0xff);
427 1.28 mjacob printf("\n");
428 1.28 mjacob }
429 1.28 mjacob #else
430 1.13 bouyer sc_link->sc_print_addr(sc_link);
431 1.17 mjacob printf("Sense Error Code 0x%x",
432 1.17 mjacob sense->error_code & SSD_ERRCODE);
433 1.13 bouyer if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
434 1.13 bouyer struct scsipi_sense_data_unextended *usense =
435 1.13 bouyer (struct scsipi_sense_data_unextended *)sense;
436 1.13 bouyer printf(" at block no. %d (decimal)",
437 1.13 bouyer _3btol(usense->block));
438 1.13 bouyer }
439 1.13 bouyer printf("\n");
440 1.28 mjacob #endif
441 1.13 bouyer return (EIO);
442 1.13 bouyer }
443 1.13 bouyer }
444 1.13 bouyer
445 1.13 bouyer /*
446 1.2 bouyer * Find out from the device what its capacity is.
447 1.2 bouyer */
448 1.2 bouyer u_long
449 1.2 bouyer scsipi_size(sc_link, flags)
450 1.2 bouyer struct scsipi_link *sc_link;
451 1.2 bouyer int flags;
452 1.2 bouyer {
453 1.2 bouyer struct scsipi_read_cap_data rdcap;
454 1.2 bouyer struct scsipi_read_capacity scsipi_cmd;
455 1.2 bouyer
456 1.2 bouyer /*
457 1.2 bouyer * make up a scsipi command and ask the scsipi driver to do
458 1.2 bouyer * it for you.
459 1.2 bouyer */
460 1.2 bouyer bzero(&scsipi_cmd, sizeof(scsipi_cmd));
461 1.2 bouyer scsipi_cmd.opcode = READ_CAPACITY;
462 1.2 bouyer
463 1.2 bouyer /*
464 1.2 bouyer * If the command works, interpret the result as a 4 byte
465 1.2 bouyer * number of blocks
466 1.2 bouyer */
467 1.4 thorpej if (scsipi_command(sc_link, (struct scsipi_generic *)&scsipi_cmd,
468 1.3 enami sizeof(scsipi_cmd), (u_char *)&rdcap, sizeof(rdcap),
469 1.29 bouyer SCSIPIRETRIES, 20000, NULL, flags | XS_CTL_DATA_IN) != 0) {
470 1.2 bouyer sc_link->sc_print_addr(sc_link);
471 1.2 bouyer printf("could not get size\n");
472 1.3 enami return (0);
473 1.2 bouyer }
474 1.2 bouyer
475 1.3 enami return (_4btol(rdcap.addr) + 1);
476 1.2 bouyer }
477 1.2 bouyer
478 1.2 bouyer /*
479 1.2 bouyer * Get scsipi driver to send a "are you ready?" command
480 1.2 bouyer */
481 1.3 enami int
482 1.2 bouyer scsipi_test_unit_ready(sc_link, flags)
483 1.2 bouyer struct scsipi_link *sc_link;
484 1.2 bouyer int flags;
485 1.2 bouyer {
486 1.2 bouyer struct scsipi_test_unit_ready scsipi_cmd;
487 1.2 bouyer
488 1.2 bouyer /* some ATAPI drives don't support TEST_UNIT_READY. Sigh */
489 1.2 bouyer if (sc_link->quirks & ADEV_NOTUR)
490 1.3 enami return (0);
491 1.2 bouyer
492 1.2 bouyer bzero(&scsipi_cmd, sizeof(scsipi_cmd));
493 1.2 bouyer scsipi_cmd.opcode = TEST_UNIT_READY;
494 1.2 bouyer
495 1.4 thorpej return (scsipi_command(sc_link,
496 1.3 enami (struct scsipi_generic *)&scsipi_cmd, sizeof(scsipi_cmd),
497 1.29 bouyer 0, 0, SCSIPIRETRIES, 10000, NULL, flags));
498 1.2 bouyer }
499 1.2 bouyer
500 1.2 bouyer /*
501 1.2 bouyer * Do a scsipi operation asking a device what it is
502 1.2 bouyer * Use the scsipi_cmd routine in the switch table.
503 1.2 bouyer * XXX actually this is only used for scsi devices, because I have the feeling
504 1.2 bouyer * that some atapi CDROM may not implement it, althouh it marked as mandatory
505 1.2 bouyer * in the atapi specs.
506 1.2 bouyer */
507 1.3 enami int
508 1.2 bouyer scsipi_inquire(sc_link, inqbuf, flags)
509 1.2 bouyer struct scsipi_link *sc_link;
510 1.2 bouyer struct scsipi_inquiry_data *inqbuf;
511 1.2 bouyer int flags;
512 1.2 bouyer {
513 1.2 bouyer struct scsipi_inquiry scsipi_cmd;
514 1.2 bouyer
515 1.2 bouyer bzero(&scsipi_cmd, sizeof(scsipi_cmd));
516 1.2 bouyer scsipi_cmd.opcode = INQUIRY;
517 1.2 bouyer scsipi_cmd.length = sizeof(struct scsipi_inquiry_data);
518 1.2 bouyer
519 1.4 thorpej return (scsipi_command(sc_link,
520 1.3 enami (struct scsipi_generic *) &scsipi_cmd, sizeof(scsipi_cmd),
521 1.3 enami (u_char *) inqbuf, sizeof(struct scsipi_inquiry_data),
522 1.29 bouyer SCSIPIRETRIES, 10000, NULL, XS_CTL_DATA_IN | flags));
523 1.2 bouyer }
524 1.2 bouyer
525 1.2 bouyer /*
526 1.2 bouyer * Prevent or allow the user to remove the media
527 1.2 bouyer */
528 1.3 enami int
529 1.2 bouyer scsipi_prevent(sc_link, type, flags)
530 1.2 bouyer struct scsipi_link *sc_link;
531 1.2 bouyer int type, flags;
532 1.2 bouyer {
533 1.2 bouyer struct scsipi_prevent scsipi_cmd;
534 1.2 bouyer
535 1.2 bouyer if (sc_link->quirks & ADEV_NODOORLOCK)
536 1.3 enami return (0);
537 1.2 bouyer
538 1.2 bouyer bzero(&scsipi_cmd, sizeof(scsipi_cmd));
539 1.2 bouyer scsipi_cmd.opcode = PREVENT_ALLOW;
540 1.2 bouyer scsipi_cmd.how = type;
541 1.4 thorpej return (scsipi_command(sc_link,
542 1.3 enami (struct scsipi_generic *) &scsipi_cmd, sizeof(scsipi_cmd),
543 1.29 bouyer 0, 0, SCSIPIRETRIES, 5000, NULL, flags));
544 1.2 bouyer }
545 1.2 bouyer
546 1.2 bouyer /*
547 1.2 bouyer * Get scsipi driver to send a "start up" command
548 1.2 bouyer */
549 1.3 enami int
550 1.2 bouyer scsipi_start(sc_link, type, flags)
551 1.2 bouyer struct scsipi_link *sc_link;
552 1.2 bouyer int type, flags;
553 1.2 bouyer {
554 1.2 bouyer struct scsipi_start_stop scsipi_cmd;
555 1.18 bouyer
556 1.18 bouyer if (sc_link->quirks & SDEV_NOSTARTUNIT)
557 1.18 bouyer return 0;
558 1.2 bouyer
559 1.2 bouyer bzero(&scsipi_cmd, sizeof(scsipi_cmd));
560 1.2 bouyer scsipi_cmd.opcode = START_STOP;
561 1.2 bouyer scsipi_cmd.byte2 = 0x00;
562 1.2 bouyer scsipi_cmd.how = type;
563 1.4 thorpej return (scsipi_command(sc_link,
564 1.3 enami (struct scsipi_generic *) &scsipi_cmd, sizeof(scsipi_cmd),
565 1.29 bouyer 0, 0, SCSIPIRETRIES, (type & SSS_START) ? 60000 : 10000,
566 1.29 bouyer NULL, flags));
567 1.2 bouyer }
568 1.2 bouyer
569 1.2 bouyer /*
570 1.3 enami * This routine is called by the scsipi interrupt when the transfer is
571 1.3 enami * complete.
572 1.2 bouyer */
573 1.3 enami void
574 1.2 bouyer scsipi_done(xs)
575 1.2 bouyer struct scsipi_xfer *xs;
576 1.2 bouyer {
577 1.2 bouyer struct scsipi_link *sc_link = xs->sc_link;
578 1.2 bouyer struct buf *bp;
579 1.31 enami int error, s;
580 1.2 bouyer
581 1.2 bouyer SC_DEBUG(sc_link, SDEV_DB2, ("scsipi_done\n"));
582 1.2 bouyer #ifdef SCSIDEBUG
583 1.2 bouyer if ((sc_link->flags & SDEV_DB1) != 0)
584 1.2 bouyer show_scsipi_cmd(xs);
585 1.2 bouyer #endif /* SCSIDEBUG */
586 1.2 bouyer
587 1.2 bouyer /*
588 1.3 enami * If it's a user level request, bypass all usual completion
589 1.3 enami * processing, let the user work it out.. We take
590 1.3 enami * reponsibility for freeing the xs when the user returns.
591 1.3 enami * (and restarting the device's queue).
592 1.3 enami */
593 1.24 thorpej if ((xs->xs_control & XS_CTL_USERCMD) != 0) {
594 1.2 bouyer SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n"));
595 1.2 bouyer scsipi_user_done(xs); /* to take a copy of the sense etc. */
596 1.2 bouyer SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n "));
597 1.2 bouyer
598 1.9 scottr /*
599 1.9 scottr * If this was an asynchronous operation (i.e. adapter
600 1.9 scottr * returned SUCCESSFULLY_QUEUED when the command was
601 1.9 scottr * submitted), we need to free the scsipi_xfer here.
602 1.9 scottr */
603 1.31 enami if (xs->xs_control & XS_CTL_ASYNC) {
604 1.31 enami s = splbio();
605 1.24 thorpej scsipi_free_xs(xs, XS_CTL_NOSLEEP);
606 1.31 enami splx(s);
607 1.31 enami }
608 1.2 bouyer SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n"));
609 1.2 bouyer return;
610 1.2 bouyer }
611 1.2 bouyer
612 1.24 thorpej if ((xs->xs_control & XS_CTL_ASYNC) == 0) {
613 1.2 bouyer /*
614 1.2 bouyer * if it's a normal upper level request, then ask
615 1.2 bouyer * the upper level code to handle error checking
616 1.2 bouyer * rather than doing it here at interrupt time
617 1.2 bouyer */
618 1.2 bouyer wakeup(xs);
619 1.2 bouyer return;
620 1.2 bouyer }
621 1.2 bouyer
622 1.2 bouyer /*
623 1.2 bouyer * Go and handle errors now.
624 1.2 bouyer * If it returns ERESTART then we should RETRY
625 1.2 bouyer */
626 1.2 bouyer retry:
627 1.2 bouyer error = sc_err1(xs, 1);
628 1.20 bouyer if (error == ERESTART) {
629 1.4 thorpej switch (scsipi_command_direct(xs)) {
630 1.2 bouyer case SUCCESSFULLY_QUEUED:
631 1.2 bouyer return;
632 1.2 bouyer
633 1.2 bouyer case TRY_AGAIN_LATER:
634 1.2 bouyer xs->error = XS_BUSY;
635 1.2 bouyer case COMPLETE:
636 1.2 bouyer goto retry;
637 1.2 bouyer }
638 1.20 bouyer }
639 1.2 bouyer
640 1.2 bouyer bp = xs->bp;
641 1.2 bouyer if (bp) {
642 1.2 bouyer if (error) {
643 1.2 bouyer bp->b_error = error;
644 1.2 bouyer bp->b_flags |= B_ERROR;
645 1.2 bouyer bp->b_resid = bp->b_bcount;
646 1.2 bouyer } else {
647 1.2 bouyer bp->b_error = 0;
648 1.2 bouyer bp->b_resid = xs->resid;
649 1.2 bouyer }
650 1.2 bouyer }
651 1.2 bouyer if (sc_link->device->done) {
652 1.2 bouyer /*
653 1.2 bouyer * Tell the device the operation is actually complete.
654 1.2 bouyer * No more will happen with this xfer. This for
655 1.2 bouyer * notification of the upper-level driver only; they
656 1.2 bouyer * won't be returning any meaningful information to us.
657 1.2 bouyer */
658 1.2 bouyer (*sc_link->device->done)(xs);
659 1.2 bouyer }
660 1.9 scottr /*
661 1.9 scottr * If this was an asynchronous operation (i.e. adapter
662 1.9 scottr * returned SUCCESSFULLY_QUEUED when the command was
663 1.9 scottr * submitted), we need to free the scsipi_xfer here.
664 1.9 scottr */
665 1.24 thorpej if (xs->xs_control & XS_CTL_ASYNC) {
666 1.31 enami s = splbio();
667 1.24 thorpej scsipi_free_xs(xs, XS_CTL_NOSLEEP);
668 1.22 pk splx(s);
669 1.22 pk }
670 1.2 bouyer if (bp)
671 1.2 bouyer biodone(bp);
672 1.2 bouyer }
673 1.2 bouyer
674 1.2 bouyer int
675 1.2 bouyer scsipi_execute_xs(xs)
676 1.2 bouyer struct scsipi_xfer *xs;
677 1.2 bouyer {
678 1.11 scottr int async;
679 1.2 bouyer int error;
680 1.2 bouyer int s;
681 1.2 bouyer
682 1.24 thorpej xs->xs_status &= ~XS_STS_DONE;
683 1.2 bouyer xs->error = XS_NOERROR;
684 1.2 bouyer xs->resid = xs->datalen;
685 1.5 thorpej xs->status = 0;
686 1.2 bouyer
687 1.2 bouyer retry:
688 1.2 bouyer /*
689 1.2 bouyer * Do the transfer. If we are polling we will return:
690 1.2 bouyer * COMPLETE, Was poll, and scsipi_done has been called
691 1.2 bouyer * TRY_AGAIN_LATER, Adapter short resources, try again
692 1.3 enami *
693 1.2 bouyer * if under full steam (interrupts) it will return:
694 1.2 bouyer * SUCCESSFULLY_QUEUED, will do a wakeup when complete
695 1.2 bouyer * TRY_AGAIN_LATER, (as for polling)
696 1.2 bouyer * After the wakeup, we must still check if it succeeded
697 1.3 enami *
698 1.24 thorpej * If we have a XS_CTL_ASYNC (typically because we have a buf)
699 1.2 bouyer * we just return. All the error proccessing and the buffer
700 1.2 bouyer * code both expect us to return straight to them, so as soon
701 1.2 bouyer * as the command is queued, return.
702 1.2 bouyer */
703 1.2 bouyer #ifdef SCSIDEBUG
704 1.2 bouyer if (xs->sc_link->flags & SDEV_DB3) {
705 1.2 bouyer printf("scsipi_exec_cmd: ");
706 1.2 bouyer show_scsipi_xs(xs);
707 1.2 bouyer printf("\n");
708 1.2 bouyer }
709 1.2 bouyer #endif
710 1.24 thorpej async = (xs->xs_control & XS_CTL_ASYNC);
711 1.4 thorpej switch (scsipi_command_direct(xs)) {
712 1.2 bouyer case SUCCESSFULLY_QUEUED:
713 1.11 scottr if (async) {
714 1.11 scottr /* scsipi_done() will free the scsipi_xfer. */
715 1.3 enami return (EJUSTRETURN);
716 1.9 scottr }
717 1.2 bouyer #ifdef DIAGNOSTIC
718 1.24 thorpej if (xs->xs_control & XS_CTL_ASYNC)
719 1.24 thorpej panic("scsipi_execute_xs: ASYNC and POLL");
720 1.2 bouyer #endif
721 1.11 scottr s = splbio();
722 1.24 thorpej while ((xs->xs_status & XS_STS_DONE) == 0)
723 1.2 bouyer tsleep(xs, PRIBIO + 1, "scsipi_cmd", 0);
724 1.2 bouyer splx(s);
725 1.2 bouyer case COMPLETE: /* Polling command completed ok */
726 1.2 bouyer if (xs->bp)
727 1.9 scottr return (0);
728 1.2 bouyer doit:
729 1.2 bouyer SC_DEBUG(xs->sc_link, SDEV_DB3, ("back in cmd()\n"));
730 1.2 bouyer if ((error = sc_err1(xs, 0)) != ERESTART)
731 1.3 enami return (error);
732 1.2 bouyer goto retry;
733 1.2 bouyer
734 1.2 bouyer case TRY_AGAIN_LATER: /* adapter resource shortage */
735 1.2 bouyer xs->error = XS_BUSY;
736 1.2 bouyer goto doit;
737 1.2 bouyer
738 1.2 bouyer default:
739 1.2 bouyer panic("scsipi_execute_xs: invalid return code");
740 1.2 bouyer }
741 1.2 bouyer
742 1.2 bouyer #ifdef DIAGNOSTIC
743 1.2 bouyer panic("scsipi_execute_xs: impossible");
744 1.2 bouyer #endif
745 1.3 enami return (EINVAL);
746 1.2 bouyer }
747 1.2 bouyer
748 1.3 enami int
749 1.2 bouyer sc_err1(xs, async)
750 1.2 bouyer struct scsipi_xfer *xs;
751 1.2 bouyer int async;
752 1.2 bouyer {
753 1.2 bouyer int error;
754 1.2 bouyer
755 1.2 bouyer SC_DEBUG(xs->sc_link, SDEV_DB3, ("sc_err1,err = 0x%x \n", xs->error));
756 1.2 bouyer
757 1.2 bouyer /*
758 1.2 bouyer * If it has a buf, we might be working with
759 1.2 bouyer * a request from the buffer cache or some other
760 1.2 bouyer * piece of code that requires us to process
761 1.2 bouyer * errors at inetrrupt time. We have probably
762 1.2 bouyer * been called by scsipi_done()
763 1.2 bouyer */
764 1.2 bouyer switch (xs->error) {
765 1.2 bouyer case XS_NOERROR: /* nearly always hit this one */
766 1.2 bouyer error = 0;
767 1.2 bouyer break;
768 1.2 bouyer
769 1.2 bouyer case XS_SENSE:
770 1.13 bouyer case XS_SHORTSENSE:
771 1.3 enami if ((error = (*xs->sc_link->scsipi_interpret_sense)(xs)) ==
772 1.3 enami ERESTART)
773 1.2 bouyer goto retry;
774 1.2 bouyer SC_DEBUG(xs->sc_link, SDEV_DB3,
775 1.2 bouyer ("scsipi_interpret_sense returned %d\n", error));
776 1.2 bouyer break;
777 1.2 bouyer
778 1.2 bouyer case XS_BUSY:
779 1.2 bouyer if (xs->retries) {
780 1.24 thorpej if ((xs->xs_control & XS_CTL_POLL) != 0)
781 1.2 bouyer delay(1000000);
782 1.33 enami else if ((xs->xs_control &
783 1.33 enami (XS_CTL_NOSLEEP|XS_CTL_DISCOVERY)) == 0)
784 1.2 bouyer tsleep(&lbolt, PRIBIO, "scbusy", 0);
785 1.2 bouyer else
786 1.2 bouyer #if 0
787 1.2 bouyer timeout(scsipi_requeue, xs, hz);
788 1.2 bouyer #else
789 1.2 bouyer goto lose;
790 1.2 bouyer #endif
791 1.2 bouyer }
792 1.2 bouyer case XS_TIMEOUT:
793 1.2 bouyer retry:
794 1.12 thorpej if (xs->retries) {
795 1.12 thorpej xs->retries--;
796 1.2 bouyer xs->error = XS_NOERROR;
797 1.24 thorpej xs->xs_status &= ~XS_STS_DONE;
798 1.3 enami return (ERESTART);
799 1.2 bouyer }
800 1.2 bouyer case XS_DRIVER_STUFFUP:
801 1.2 bouyer lose:
802 1.2 bouyer error = EIO;
803 1.2 bouyer break;
804 1.2 bouyer
805 1.2 bouyer case XS_SELTIMEOUT:
806 1.2 bouyer /* XXX Disable device? */
807 1.12 thorpej error = EIO;
808 1.12 thorpej break;
809 1.12 thorpej
810 1.12 thorpej case XS_RESET:
811 1.12 thorpej if (xs->retries) {
812 1.12 thorpej SC_DEBUG(xs->sc_link, SDEV_DB3,
813 1.12 thorpej ("restarting command destroyed by reset\n"));
814 1.12 thorpej goto retry;
815 1.12 thorpej }
816 1.2 bouyer error = EIO;
817 1.2 bouyer break;
818 1.2 bouyer
819 1.2 bouyer default:
820 1.3 enami (*xs->sc_link->sc_print_addr)(xs->sc_link);
821 1.2 bouyer printf("unknown error category from scsipi driver\n");
822 1.2 bouyer error = EIO;
823 1.2 bouyer break;
824 1.2 bouyer }
825 1.2 bouyer
826 1.3 enami return (error);
827 1.2 bouyer }
828 1.2 bouyer
829 1.14 thorpej /*
830 1.14 thorpej * Add a reference to the adapter pointed to by the provided
831 1.14 thorpej * link, enabling the adapter if necessary.
832 1.14 thorpej */
833 1.14 thorpej int
834 1.14 thorpej scsipi_adapter_addref(link)
835 1.14 thorpej struct scsipi_link *link;
836 1.14 thorpej {
837 1.14 thorpej struct scsipi_adapter *adapter = link->adapter;
838 1.14 thorpej int s, error = 0;
839 1.14 thorpej
840 1.14 thorpej s = splbio();
841 1.14 thorpej if (adapter->scsipi_refcnt++ == 0 &&
842 1.14 thorpej adapter->scsipi_enable != NULL) {
843 1.14 thorpej error = (*adapter->scsipi_enable)(link->adapter_softc, 1);
844 1.14 thorpej if (error)
845 1.14 thorpej adapter->scsipi_refcnt--;
846 1.14 thorpej }
847 1.14 thorpej splx(s);
848 1.14 thorpej return (error);
849 1.14 thorpej }
850 1.14 thorpej
851 1.14 thorpej /*
852 1.14 thorpej * Delete a reference to the adapter pointed to by the provided
853 1.14 thorpej * link, disabling the adapter if possible.
854 1.14 thorpej */
855 1.14 thorpej void
856 1.14 thorpej scsipi_adapter_delref(link)
857 1.14 thorpej struct scsipi_link *link;
858 1.14 thorpej {
859 1.14 thorpej struct scsipi_adapter *adapter = link->adapter;
860 1.14 thorpej int s;
861 1.14 thorpej
862 1.14 thorpej s = splbio();
863 1.14 thorpej if (adapter->scsipi_refcnt-- == 1 &&
864 1.14 thorpej adapter->scsipi_enable != NULL)
865 1.14 thorpej (void) (*adapter->scsipi_enable)(link->adapter_softc, 0);
866 1.14 thorpej splx(s);
867 1.14 thorpej }
868 1.14 thorpej
869 1.2 bouyer #ifdef SCSIDEBUG
870 1.2 bouyer /*
871 1.2 bouyer * Given a scsipi_xfer, dump the request, in all it's glory
872 1.2 bouyer */
873 1.2 bouyer void
874 1.2 bouyer show_scsipi_xs(xs)
875 1.2 bouyer struct scsipi_xfer *xs;
876 1.2 bouyer {
877 1.3 enami
878 1.2 bouyer printf("xs(%p): ", xs);
879 1.24 thorpej printf("xs_control(0x%08x)", xs->xs_control);
880 1.24 thorpej printf("xs_status(0x%08x)", xs->xs_status);
881 1.2 bouyer printf("sc_link(%p)", xs->sc_link);
882 1.2 bouyer printf("retr(0x%x)", xs->retries);
883 1.2 bouyer printf("timo(0x%x)", xs->timeout);
884 1.2 bouyer printf("cmd(%p)", xs->cmd);
885 1.2 bouyer printf("len(0x%x)", xs->cmdlen);
886 1.2 bouyer printf("data(%p)", xs->data);
887 1.2 bouyer printf("len(0x%x)", xs->datalen);
888 1.2 bouyer printf("res(0x%x)", xs->resid);
889 1.2 bouyer printf("err(0x%x)", xs->error);
890 1.2 bouyer printf("bp(%p)", xs->bp);
891 1.2 bouyer show_scsipi_cmd(xs);
892 1.2 bouyer }
893 1.2 bouyer
894 1.2 bouyer void
895 1.2 bouyer show_scsipi_cmd(xs)
896 1.2 bouyer struct scsipi_xfer *xs;
897 1.2 bouyer {
898 1.2 bouyer u_char *b = (u_char *) xs->cmd;
899 1.3 enami int i = 0;
900 1.2 bouyer
901 1.3 enami (*xs->sc_link->sc_print_addr)(xs->sc_link);
902 1.2 bouyer printf("command: ");
903 1.2 bouyer
904 1.24 thorpej if ((xs->xs_control & XS_CTL_RESET) == 0) {
905 1.2 bouyer while (i < xs->cmdlen) {
906 1.2 bouyer if (i)
907 1.2 bouyer printf(",");
908 1.2 bouyer printf("0x%x", b[i++]);
909 1.2 bouyer }
910 1.2 bouyer printf("-[%d bytes]\n", xs->datalen);
911 1.2 bouyer if (xs->datalen)
912 1.2 bouyer show_mem(xs->data, min(64, xs->datalen));
913 1.2 bouyer } else
914 1.2 bouyer printf("-RESET-\n");
915 1.2 bouyer }
916 1.2 bouyer
917 1.2 bouyer void
918 1.2 bouyer show_mem(address, num)
919 1.2 bouyer u_char *address;
920 1.2 bouyer int num;
921 1.2 bouyer {
922 1.2 bouyer int x;
923 1.2 bouyer
924 1.2 bouyer printf("------------------------------");
925 1.2 bouyer for (x = 0; x < num; x++) {
926 1.2 bouyer if ((x % 16) == 0)
927 1.2 bouyer printf("\n%03d: ", x);
928 1.2 bouyer printf("%02x ", *address++);
929 1.2 bouyer }
930 1.2 bouyer printf("\n------------------------------\n");
931 1.2 bouyer }
932 1.2 bouyer #endif /*SCSIDEBUG */
933