Commit | Line | Data |
---|---|---|
3a637e8d KB |
1 | /*- |
2 | * Copyright (c) 1992 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This software was developed by the Computer Systems Engineering group | |
6 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | |
7 | * contributed to Berkeley. | |
8 | * | |
9 | * %sccs.include.redist.c% | |
10 | * | |
df3858fd | 11 | * @(#)scsiformat.c 5.4 (Berkeley) %G% |
3a637e8d KB |
12 | */ |
13 | ||
df3858fd KB |
14 | #ifndef lint |
15 | char copyright[] = | |
16 | "@(#) Copyright (c) 1993 The Regents of the University of California.\n\ | |
17 | All rights reserved.\n"; | |
18 | #endif /* not lint */ | |
19 | ||
20 | #ifndef lint | |
21 | static char sccsid[] = "@(#)scsiformat.c 5.4 (Berkeley) %G%"; | |
22 | #endif /* not lint */ | |
23 | ||
3a637e8d KB |
24 | #include <sys/param.h> |
25 | #include <sys/ioctl.h> | |
3a637e8d | 26 | |
df3858fd KB |
27 | #include <dev/scsi/scsi.h> |
28 | #include <dev/scsi/disk.h> | |
29 | #include <dev/scsi/disktape.h> | |
30 | #include <dev/scsi/scsi_ioctl.h> | |
31 | ||
32 | #define COMPAT_HPSCSI | |
33 | ||
3a637e8d | 34 | #include <errno.h> |
df3858fd | 35 | #include <fcntl.h> |
3a637e8d | 36 | #include <stdio.h> |
df3858fd | 37 | #include <stdlib.h> |
3a637e8d | 38 | #include <string.h> |
df3858fd | 39 | #include <unistd.h> |
3a637e8d KB |
40 | |
41 | int fd; | |
42 | char *device; | |
43 | ||
df3858fd KB |
44 | void scsi_str __P((char *, char *, int)); |
45 | void do_command __P((int, struct scsi_cdb *, void *, int)); | |
be2c1524 | 46 | void do_format __P((void)); |
3a637e8d KB |
47 | void print_capacity __P((void)); |
48 | void print_inquiry __P((void)); | |
df3858fd | 49 | void prflags __P((int, const char *)); |
3a637e8d KB |
50 | u_char *print_mode_page __P((u_char *)); |
51 | void print_mode_sense __P((void)); | |
52 | void usage __P((void)); | |
53 | ||
df3858fd KB |
54 | #define N2(c, d) (((c) << 8) | (d)) |
55 | #define N3(b, c, d) (((b) << 16) | N2(c, d)) | |
56 | #define N4(a, b, c, d) (((a) << 24) | N3(b, c, d)) | |
57 | ||
58 | int sense_pctl; | |
59 | ||
3a637e8d | 60 | int |
be2c1524 | 61 | main(argc, argv) |
3a637e8d KB |
62 | int argc; |
63 | char *argv[]; | |
64 | { | |
df3858fd KB |
65 | extern char *optarg; |
66 | int ch, readonly; | |
3a637e8d | 67 | |
df3858fd KB |
68 | readonly = 0; |
69 | sense_pctl = SCSI_MSENSE_PCTL_CUR; | |
70 | while ((ch = getopt(argc, argv, "rp:")) != EOF) { | |
3a637e8d | 71 | switch(ch) { |
df3858fd KB |
72 | case 'r': |
73 | readonly = 1; | |
74 | break; | |
75 | case 'p': /* mode sense page control */ | |
76 | switch (*optarg) { | |
77 | case 'c': | |
78 | sense_pctl = SCSI_MSENSE_PCTL_CUR; | |
79 | break; | |
80 | case 'd': | |
81 | sense_pctl = SCSI_MSENSE_PCTL_DFLT; | |
82 | break; | |
83 | case 's': | |
84 | sense_pctl = SCSI_MSENSE_PCTL_SAVED; | |
85 | break; | |
86 | case 'v': | |
87 | (void)printf( | |
88 | "*** note: for variable parameters, 1-bit means ``can write here''\n"); | |
89 | sense_pctl = SCSI_MSENSE_PCTL_VAR; | |
90 | break; | |
91 | } | |
92 | /* FALLTHROUGH */ | |
3a637e8d KB |
93 | case '?': |
94 | default: | |
95 | usage(); | |
96 | } | |
df3858fd | 97 | } |
3a637e8d KB |
98 | argc -= optind; |
99 | argv += optind; | |
100 | ||
101 | if (argc != 1) | |
102 | usage(); | |
103 | ||
873fa9ad | 104 | device = *argv; |
df3858fd KB |
105 | fd = open(device, readonly ? O_RDONLY : O_RDWR, 0); |
106 | if (fd < 0) { | |
3a637e8d KB |
107 | (void)fprintf(stderr, |
108 | "scsiformat: %s: %s\n", device, strerror(errno)); | |
109 | exit(1); | |
110 | } | |
111 | print_inquiry(); | |
112 | print_capacity(); | |
113 | print_mode_sense(); | |
be2c1524 | 114 | |
df3858fd KB |
115 | if (!readonly) |
116 | do_format(); | |
3a637e8d KB |
117 | exit(0); |
118 | } | |
119 | ||
df3858fd KB |
120 | /* |
121 | * Copy a counted string, trimming trailing blanks, and turning the | |
122 | * result into a C-style string. | |
123 | */ | |
3a637e8d | 124 | void |
df3858fd KB |
125 | scsi_str(src, dst, len) |
126 | register char *src, *dst; | |
127 | register int len; | |
3a637e8d | 128 | { |
3a637e8d | 129 | |
df3858fd KB |
130 | while (src[len - 1] == ' ') { |
131 | if (--len == 0) { | |
132 | *dst = 0; | |
133 | return; | |
134 | } | |
135 | } | |
136 | bcopy(src, dst, len); | |
137 | dst[len] = 0; | |
138 | } | |
3a637e8d | 139 | |
df3858fd KB |
140 | void |
141 | print_inquiry() | |
142 | { | |
143 | register struct scsi_inq_ansi *si; | |
144 | int ver; | |
145 | struct scsi_inquiry inqbuf; | |
146 | char vendor[10], product[17], rev[5]; | |
147 | static struct scsi_cdb inq = { | |
148 | CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 | |
149 | }; | |
150 | ||
151 | do_command(fd, &inq, &inqbuf, sizeof(inqbuf)); | |
152 | (void)printf("%s: ", device); | |
153 | ||
154 | ver = (inqbuf.si_version >> VER_ANSI_SHIFT) & VER_ANSI_MASK; | |
155 | if (ver != 1 && ver != 2) { | |
156 | (void)printf("type 0x%x, qual 0x%x, ver 0x%x (ansi %d)\n", | |
157 | inqbuf.si_type, inqbuf.si_qual, inqbuf.si_version, ver); | |
3a637e8d KB |
158 | return; |
159 | } | |
df3858fd KB |
160 | si = (struct scsi_inq_ansi *)&inqbuf; |
161 | switch (si->si_type & TYPE_TYPE_MASK) { | |
162 | ||
163 | case TYPE_DAD: | |
164 | (void)printf("(disk)"); | |
165 | break; | |
166 | ||
167 | case TYPE_WORM: | |
168 | (void)printf("(WORM)"); | |
169 | break; | |
170 | ||
171 | case TYPE_ROM: | |
172 | (void)printf("(CD-ROM)"); | |
173 | break; | |
174 | ||
175 | case TYPE_MO: | |
176 | (void)printf("(MO-DISK)"); | |
177 | break; | |
178 | ||
179 | case TYPE_JUKEBOX: | |
180 | (void)printf("(jukebox)"); | |
181 | break; | |
182 | ||
183 | default: | |
184 | (void)printf("(??)"); | |
185 | break; | |
3a637e8d | 186 | } |
df3858fd KB |
187 | scsi_str(si->si_vendor, vendor, sizeof(si->si_vendor)); |
188 | scsi_str(si->si_product, product, sizeof(si->si_product)); | |
189 | scsi_str(si->si_rev, rev, sizeof(si->si_rev)); | |
190 | (void)printf(" %s %s rev %s:", vendor, product, rev); | |
3a637e8d KB |
191 | } |
192 | ||
193 | void | |
194 | print_capacity() | |
195 | { | |
df3858fd KB |
196 | struct scsi_rc rc; /* for READ CAPACITY */ |
197 | static struct scsi_cdb cap = { CMD_READ_CAPACITY }; | |
198 | ||
199 | do_command(fd, &cap, &rc, sizeof(rc)); | |
200 | (void)printf(" %d blocks of %d bytes each\n", | |
201 | N4(rc.rc_lbah, rc.rc_lbahm, rc.rc_lbalm, rc.rc_lbal) + 1, | |
202 | N4(rc.rc_blh, rc.rc_blhm, rc.rc_bllm, rc.rc_bll)); | |
3a637e8d KB |
203 | } |
204 | ||
873fa9ad KB |
205 | void |
206 | print_mode_sense() | |
207 | { | |
df3858fd KB |
208 | register u_char *cp, *ep; |
209 | register struct scsi_ms_bd *bd; | |
210 | register int n, i, l, len, bdlen; | |
211 | #ifdef TEN_BYTE_SENSE | |
212 | struct { | |
213 | struct scsi_ms10 ms; | |
214 | u_char p[1023 - sizeof(struct scsi_ms10)]; | |
215 | } msbuf; | |
216 | static struct scsi_cdb modesense = { | |
217 | CMD_MODE_SENSE10, SCSI_MSENSE_DBD, 0, 0, 0, 0, 0, | |
218 | sizeof(msbuf) >> 8, sizeof (msbuf), 0 | |
219 | }; | |
220 | ||
221 | CDB10(&modesense)->cdb_lbam = sense_pctl | SCSI_MS_PC_ALL; | |
222 | do_command(fd, &modesense, &msbuf, sizeof(msbuf)); | |
223 | len = N2(msbuf.ms.ms_lenh, msbuf.ms.ms_lenl); | |
224 | bdlen = N2(msbuf.ms.ms_bdlh, msbuf.ms.ms_bdll); | |
225 | #else | |
226 | struct { | |
227 | struct scsi_ms6 ms; | |
228 | u_char p[255 - sizeof(struct scsi_ms6)]; | |
229 | } msbuf; | |
230 | static struct scsi_cdb modesense = { | |
231 | CMD_MODE_SENSE6, 0, 0, 0, sizeof(msbuf), 0 | |
232 | }; | |
233 | ||
234 | CDB6(&modesense)->cdb_lbam = sense_pctl | SCSI_MS_PC_ALL; | |
235 | do_command(fd, &modesense, &msbuf, sizeof(msbuf)); | |
236 | len = msbuf.ms.ms_len; | |
237 | bdlen = msbuf.ms.ms_bdl; | |
238 | #endif | |
239 | (void)printf("\n%d bytes of mode sense data. ", len); | |
240 | (void)printf("medium type 0x%x, %swrite protected\n", | |
241 | msbuf.ms.ms_mt, msbuf.ms.ms_dsp & SCSI_MS_DSP_WP ? "" : "not "); | |
242 | if ((n = bdlen) != 0) { | |
243 | bd = (struct scsi_ms_bd *)msbuf.p; | |
244 | for (n /= sizeof(*bd); --n >= 0; bd++) { | |
245 | (void)printf("\tdensity code 0x%x, ", bd->bd_dc); | |
246 | i = N3(bd->bd_nbh, bd->bd_nbm, bd->bd_nbl); | |
247 | l = N3(bd->bd_blh, bd->bd_blm, bd->bd_bll); | |
248 | if (i) | |
249 | (void)printf("%d blocks of length %d\n", i, l); | |
250 | else | |
251 | (void)printf("all blocks of length %d\n", l); | |
252 | } | |
253 | } | |
254 | /* | |
255 | * Sense header lengths includes the sense header, while mode page | |
256 | * lengths do not ... let's hear it for consistency! | |
257 | */ | |
258 | cp = msbuf.p + bdlen; | |
259 | ep = msbuf.p + len - sizeof(msbuf.ms); | |
873fa9ad KB |
260 | while (cp < ep) |
261 | cp = print_mode_page(cp); | |
262 | } | |
263 | ||
df3858fd KB |
264 | void |
265 | prflags(v, cp) | |
266 | int v; | |
267 | register const char *cp; | |
268 | { | |
269 | register const char *np; | |
270 | char f, sep; | |
271 | ||
272 | for (sep = '<'; (f = *cp++) != 0; cp = np) { | |
273 | for (np = cp; *np >= ' ';) | |
274 | np++; | |
275 | if ((v & (1 << (f - 1))) == 0) | |
276 | continue; | |
277 | printf("%c%.*s", sep, np - cp, cp); | |
278 | sep = ','; | |
279 | } | |
280 | if (sep != '<') | |
281 | putchar('>'); | |
282 | } | |
283 | ||
284 | static char * | |
285 | cache_policy(x) | |
286 | int x; | |
287 | { | |
288 | static char rsvd[30]; | |
289 | ||
290 | switch (x) { | |
291 | ||
292 | case SCSI_CACHE_DEFAULT: | |
293 | return ("default"); | |
294 | ||
295 | case SCSI_CACHE_KEEPPF: | |
296 | return ("toss cmd data, save prefetch"); | |
297 | ||
298 | case SCSI_CACHE_KEEPCMD: | |
299 | return ("toss prefetch data, save cmd"); | |
300 | ||
301 | default: | |
302 | (void)sprintf(rsvd, "reserved %d", x); | |
303 | return (rsvd); | |
304 | } | |
305 | /* NOTREACHED */ | |
306 | } | |
307 | ||
3a637e8d KB |
308 | u_char * |
309 | print_mode_page(cp) | |
310 | u_char *cp; | |
311 | { | |
df3858fd KB |
312 | register struct scsi_ms_page_hdr *mp; |
313 | int len, code, i; | |
314 | u_char *tp; | |
315 | const char *s; | |
316 | ||
317 | mp = (struct scsi_ms_page_hdr *)cp; | |
318 | code = mp->mp_psc & SCSI_MS_PC_MASK; | |
319 | len = mp->mp_len; | |
320 | (void)printf("\npage type %d%s (%d bytes): ", | |
321 | code, mp->mp_psc & SCSI_MS_MP_SAVEABLE ? " (saveable)" : "", len); | |
322 | switch (code) { | |
323 | ||
324 | case SCSI_MS_PC_RWERRREC: | |
325 | #define rw ((struct scsi_page_rwerrrec *)(mp + 1)) | |
326 | (void)printf("Read/Write Error Recovery parameters.\n"); | |
327 | (void)printf("\tflags = 0x%x", rw->rw_flags); | |
328 | prflags(rw->rw_flags, | |
329 | "\10AWRE\7ARRE\6TB\5RC\4EER\3PER\2DTE\1DCR"); | |
330 | (void)printf(",\n\t%d read retries, %d correction span bits,\n", | |
331 | rw->rw_read_retry, rw->rw_corr_span); | |
332 | (void)printf("\t%d head offsets, %d data strobe offsets%s\n", | |
333 | rw->rw_hd_off, rw->rw_ds_off, len > 6 ? "," : "."); | |
334 | if (len <= 6) | |
335 | break; | |
336 | (void)printf("\t%d write retries, ", rw->rw_write_retry); | |
337 | i = N2(rw->rw_rtlh, rw->rw_rtll); | |
338 | if (i != 0xffff) | |
339 | (void)printf("%d", i); | |
3a637e8d | 340 | else |
df3858fd KB |
341 | (void)printf("no"); |
342 | (void)printf(" recovery time limit.\n"); | |
3a637e8d | 343 | break; |
df3858fd KB |
344 | #undef rw |
345 | ||
346 | case SCSI_MS_PC_DR: | |
347 | #define dr ((struct scsi_page_dr *)(mp + 1)) | |
348 | (void)printf("Disconnect/Reconnect control.\n"); | |
349 | (void)printf("\tbuffer full ratio %d, buffer empty ratio %d,\n", | |
350 | dr->dr_full, dr->dr_empty); | |
351 | (void)printf("\ttime limits: %d bus inactivity, ", | |
352 | N2(dr->dr_inacth, dr->dr_inactl)); | |
353 | (void)printf("%d disconnect, %d connect.\n", | |
354 | N2(dr->dr_disconh, dr->dr_disconl), | |
355 | N2(dr->dr_conh, dr->dr_conl)); | |
356 | (void)printf("\tmaximum burst size %d,\n", | |
357 | N2(dr->dr_bursth, dr->dr_burstl)); | |
358 | switch (dr->dr_dtdc & SCSI_DR_DTDC_MASK) { | |
359 | case SCSI_DR_DTDC_NONE: | |
360 | s = "never"; | |
361 | break; | |
362 | case SCSI_DR_DTDC_NOTDATA: | |
363 | s = "during data transfer"; | |
364 | break; | |
365 | case SCSI_DR_DTDC_RSVD: | |
366 | s = "???"; | |
367 | break; | |
368 | case SCSI_DR_DTDC_NOTD2: | |
369 | s = "during and after data transfer"; | |
370 | break; | |
3a637e8d | 371 | } |
df3858fd KB |
372 | (void)printf("\tsuppress disconnect %s.\n", s); |
373 | break; | |
374 | #undef dr | |
375 | ||
376 | case SCSI_MS_PC_FMT: | |
377 | #define fmt ((struct scsi_page_fmt *)(mp + 1)) | |
378 | (void)printf("Format parameters.\n"); | |
379 | (void)printf("\t%d tracks/zone, %d alt.sect./zone, ", | |
380 | N2(fmt->fmt_tpzh, fmt->fmt_tpzl), | |
381 | N2(fmt->fmt_aspzh, fmt->fmt_aspzl)); | |
382 | (void)printf("%d alt.tracks/zone,\n\t%d alt.tracks/vol., ", | |
383 | N2(fmt->fmt_atpzh, fmt->fmt_atpzl), | |
384 | N2(fmt->fmt_atpvh, fmt->fmt_atpvl)); | |
385 | (void)printf("%d sectors/track, %d bytes/phys.sector,\n", | |
386 | N2(fmt->fmt_spth, fmt->fmt_sptl), | |
387 | N2(fmt->fmt_dbppsh, fmt->fmt_dbppsl)); | |
388 | (void)printf("\tinterleave %d, track skew %d, cyl.skew %d,\n", | |
389 | N2(fmt->fmt_ilh, fmt->fmt_ill), | |
390 | N2(fmt->fmt_tsfh, fmt->fmt_tsfl), | |
391 | N2(fmt->fmt_csfh, fmt->fmt_csfl)); | |
392 | (void)printf("\tdrive flags 0x%x", fmt->fmt_flags); | |
393 | prflags(fmt->fmt_flags, "\10SSEC\7HSEC\6RMB\5SURF"); | |
394 | (void)printf(".\n"); | |
395 | break; | |
396 | #undef fmt | |
397 | ||
398 | case SCSI_MS_PC_RDGEOM: | |
399 | #define rd ((struct scsi_page_rdgeom *)(mp + 1)) | |
400 | (void)printf("Disk Geometry parameters.\n"); | |
401 | (void)printf("\t%d cylinders, %d heads,\n", | |
402 | N3(rd->rd_ncylh, rd->rd_ncylm, rd->rd_ncyll), | |
403 | rd->rd_nheads); | |
404 | (void)printf("\tstart write precompensation at cyl %d,\n", | |
405 | N3(rd->rd_wpcylh, rd->rd_wpcylm, rd->rd_wpcyll)); | |
406 | (void)printf("\tstart reduced write current at cyl %d,\n", | |
407 | N3(rd->rd_rwcylh, rd->rd_rwcylm, rd->rd_rwcyll)); | |
408 | (void)printf("\tseek step rate %f us, landing zone cyl %d,\n", | |
409 | N2(rd->rd_steph, rd->rd_stepl) * 0.1, | |
410 | N3(rd->rd_lcylh, rd->rd_lcylm, rd->rd_lcyll)); | |
411 | switch (rd->rd_rpl & SCSI_RD_RPL_MASK) { | |
412 | case SCSI_RD_RPL_NONE: | |
413 | s = "disabled or unsupported"; | |
414 | break; | |
415 | case SCSI_RD_RPL_SLAVE: | |
416 | s = "slave"; | |
417 | break; | |
418 | case SCSI_RD_RPL_MASTER: | |
419 | s = "master"; | |
420 | break; | |
421 | case SCSI_RD_RPL_MCONTROL: | |
422 | s = "master control"; | |
423 | break; | |
3a637e8d | 424 | } |
df3858fd KB |
425 | (void)printf("\trotational synch %s, offset %d/256%s\n", |
426 | s, rd->rd_roff, len > 18 ? "," : "."); | |
427 | if (len > 18) | |
428 | (void)printf("\trotation %d rpm.\n", | |
429 | N2(rd->rd_rpmh, rd->rd_rpml)); | |
3a637e8d | 430 | break; |
df3858fd KB |
431 | #undef rd |
432 | ||
433 | case SCSI_MS_PC_VERRREC: | |
434 | #define v ((struct scsi_page_verrrec *)(mp + 1)) | |
435 | (void)printf("Verify Error Recovery parameters.\n"); | |
436 | (void)printf("\tflags = 0x%x", v->v_flags); | |
437 | prflags(v->v_flags, "\4EER\3PER\2DTE\1DCR"); | |
438 | (void)printf(",\n\t%d verify retries, %d %s span bits,\n\t", | |
439 | v->v_verify_retry, v->v_corr_span, "correction"); | |
440 | (void)printf("%d recovery time limit.\n", | |
441 | N2(v->v_rtlh, v->v_rtll)); | |
442 | break; | |
443 | #undef v | |
444 | ||
445 | case SCSI_MS_PC_CACHE: | |
446 | #define cache ((struct scsi_page_cache *)(mp + 1)) | |
447 | (void)printf("Caching Page.\n"); | |
448 | (void)printf("\tflags = 0x%x", cache->cache_flags); | |
449 | prflags(cache->cache_flags, "\3WCE\2MF\1RCD"); | |
450 | (void)printf( | |
451 | ",\n\tread retention = %s, write retention = %s,\n", | |
452 | cache_policy(SCSI_CACHE_RDPOLICY(cache->cache_reten)), | |
453 | cache_policy(SCSI_CACHE_WRPOLICY(cache->cache_reten))); | |
454 | (void)printf("\tdisable prefetch transfer length = %d,\n", | |
455 | N2(cache->cache_dptlh, cache->cache_dptll)); | |
456 | (void)printf("\tmin prefetch = %d, max prefetch = %d, ", | |
457 | N2(cache->cache_minpfh, cache->cache_minpfl), | |
458 | N2(cache->cache_maxpfh, cache->cache_maxpfl)); | |
459 | (void)printf("max prefetch ceiling = %d.\n", | |
460 | N2(cache->cache_mpch, cache->cache_mpcl)); | |
3a637e8d | 461 | break; |
df3858fd KB |
462 | #undef cache |
463 | ||
464 | case SCSI_MS_PC_CTLMODE: | |
465 | #define cm ((struct scsi_page_ctlmode *)(mp + 1)) | |
466 | (void)printf("Control Mode Page.\n"); | |
467 | (void)printf("\t%s report log-activity error conditions,\n", | |
468 | cm->cm_rlec & SCSI_CM_RLEC ? "do" : "do not"); | |
469 | (void)printf("\tqueue algorithm modifier = %d, flags = 0x%x", | |
470 | SCSI_CM_QMOD(cm->cm_qctl), | |
471 | cm->cm_qctl & (SCSI_CM_QERR|SCSI_CM_DQUE)); | |
472 | prflags(cm->cm_qctl, "\2QERR\1DQUE"); | |
473 | (void)printf(",\n\tECA/AEN flags = 0x%x", cm->cm_ecaaen); | |
474 | prflags(cm->cm_ecaaen, "\10ECA\3RAENP\2UUAENP\1EAENP"); | |
475 | (void)printf(", AEN holdoff period = %d ms.\n", | |
476 | N2(cm->cm_aenholdh, cm->cm_aenholdl)); | |
477 | break; | |
478 | #undef cm | |
479 | ||
480 | /* | |
481 | * Vendor Unique, but what the heck. | |
482 | */ | |
483 | case SCSI_MS_PC_CDCCACHECTL: | |
484 | #define ccm ((struct scsi_page_CDCcachectlmode *)(mp + 1)) | |
485 | (void)printf("CDC-specific Cache Control Mode Page.\n"); | |
486 | (void)printf("\tflags = 0x%x", ccm->ccm_flags); | |
487 | prflags(ccm->ccm_flags, "\7WIE\5ENABLE"); | |
488 | (void)printf(", table size = %d, prefetch threshold = %d\n", | |
489 | SCSI_CDC_CCM_TBLSZ(ccm->ccm_flags), | |
490 | ccm->ccm_pfthresh); | |
491 | (void)printf("\tmaximum %s = %d, maximum %s = %d,\n", | |
492 | "threshold", ccm->ccm_maxthresh, | |
493 | "prefetch multiplier", ccm->ccm_maxpfmult); | |
494 | (void)printf("\tminimum %s = %d, minimum %s = %d.\n", | |
495 | "threshold", ccm->ccm_minthresh, | |
496 | "prefetch multiplier", ccm->ccm_minpfmult); | |
497 | break; | |
498 | #undef ccm | |
3a637e8d KB |
499 | |
500 | default: | |
df3858fd KB |
501 | (void)printf("Unknown page type."); |
502 | for (tp = cp + sizeof(*mp), i = 0; i < len; ++i) { | |
3a637e8d | 503 | if ((i & 7) == 0) |
df3858fd KB |
504 | (void)printf("\n\t%2d: ", i); |
505 | (void)printf(" %02x", *tp++); | |
3a637e8d | 506 | } |
df3858fd | 507 | (void)printf(".\n"); |
3a637e8d KB |
508 | break; |
509 | } | |
df3858fd | 510 | return (cp + sizeof(*mp) + len); |
3a637e8d KB |
511 | } |
512 | ||
be2c1524 KB |
513 | void |
514 | pr_sense(fd) | |
515 | int fd; | |
516 | { | |
517 | static struct scsi_fmt_sense s; | |
df3858fd | 518 | register struct scsi_sense *sn; |
be2c1524 KB |
519 | |
520 | if (ioctl(fd, SDIOCSENSE, &s) < 0) | |
521 | (void)fprintf(stderr, | |
522 | "scsiformat: SDIOCSENSE: %s\n", strerror(errno)); | |
523 | ||
524 | (void)printf("scsi status 0x%x", s.status); | |
525 | if (s.status & STS_CHECKCOND) { | |
df3858fd KB |
526 | sn = (struct scsi_sense *)s.sense; |
527 | ||
528 | (void)printf(" sense class %d, code %d", | |
529 | SENSE_ECLASS(sn), SENSE_ECODE(sn)); | |
530 | if (SENSE_ISXSENSE(sn)) { | |
531 | (void)printf(", key %d", XSENSE_KEY(sn)); | |
532 | if (XSENSE_IVALID(sn)) | |
533 | (void)printf(", blk %d", XSENSE_INFO(sn)); | |
be2c1524 KB |
534 | } |
535 | } | |
536 | (void)printf("\n"); | |
537 | } | |
538 | ||
539 | void | |
540 | do_format() | |
541 | { | |
df3858fd KB |
542 | struct { |
543 | struct scsi_ms6 ms; /* mode select header */ | |
544 | struct scsi_ms_bd bd; /* block descriptor */ | |
545 | struct scsi_ms_page_hdr mp; /* ctl mode page hdr */ | |
546 | struct scsi_page_ctlmode cm; /* ctl mode page */ | |
547 | u_char pad[4]; /* ??? */ | |
548 | } msel; | |
549 | u_char fmtbuf[128]; | |
550 | static struct scsi_cdb modeselect = { | |
551 | CMD_MODE_SELECT6, | |
552 | SCSI_MSEL_SCSI2_DATA | SCSI_MSEL_SAVEPAGES, 0, 0, | |
553 | sizeof(msel), 0 | |
554 | }; | |
555 | static struct scsi_cdb format = { CMD_FORMAT_UNIT }; | |
556 | ||
557 | /* want mostly 0s; set them all zero here */ | |
558 | bzero(&msel, sizeof(msel)); | |
559 | ||
560 | /* one block descriptor */ | |
561 | msel.ms.ms_bdl = sizeof(struct scsi_ms_bd); | |
562 | ||
563 | /* block length = 512 bytes */ | |
564 | msel.bd.bd_blm = 512 / 256; | |
565 | msel.bd.bd_bll = 512 % 256; | |
566 | ||
567 | /* | |
568 | * In the following, the mystery pad region is copied from | |
569 | * the original driver. I have no idea what it is for. | |
570 | * (Anyone got SCSI-2 documents?) | |
571 | */ | |
572 | ||
573 | /* mode page parameters: report log-activity exception conditions */ | |
574 | msel.mp.mp_psc = SCSI_MS_PC_CTLMODE; | |
575 | msel.mp.mp_len = sizeof(msel.cm) + sizeof(msel.pad); | |
576 | msel.cm.cm_rlec = SCSI_CM_RLEC; | |
577 | ||
578 | do_command(fd, &modeselect, &msel, sizeof(msel)); | |
579 | ||
580 | bzero(fmtbuf, sizeof(fmtbuf)); | |
581 | do_command(fd, &format, fmtbuf, sizeof(fmtbuf)); | |
be2c1524 KB |
582 | } |
583 | ||
3a637e8d | 584 | void |
873fa9ad KB |
585 | do_command(fd, cdb, buf, len) |
586 | int fd; | |
df3858fd KB |
587 | struct scsi_cdb *cdb; |
588 | void *buf; | |
873fa9ad | 589 | int len; |
3a637e8d | 590 | { |
df3858fd KB |
591 | static int on = 1, off = 0; |
592 | int user, ret; | |
3a637e8d | 593 | |
df3858fd | 594 | bzero(buf, len); |
873fa9ad KB |
595 | if (ioctl(fd, SDIOCSFORMAT, &on) < 0) { |
596 | (void)fprintf(stderr, | |
597 | "scsiformat: SDIOCSFORMAT (on): %s\n", strerror(errno)); | |
df3858fd KB |
598 | if (ioctl(fd, SDIOCGFORMAT, &user) == 0 && user != 0) |
599 | (void)fprintf(stderr, "scsiformat: pid %d has it\n", | |
600 | user); | |
873fa9ad KB |
601 | return; |
602 | } | |
df3858fd KB |
603 | ret = ioctl(fd, SDIOCSCSICOMMAND, cdb); |
604 | #ifdef COMPAT_HPSCSI | |
605 | if (ret < 0) { | |
606 | static const char scsicmdlen[8] = { 6, 10, 0, 0, 0, 12, 0, 0 }; | |
607 | #define SCSICMDLEN(cmd) scsicmdlen[(cmd) >> 5] | |
608 | struct scsi_fmt_cdb { | |
609 | int len; | |
610 | u_char cdb[28]; | |
611 | } sc; | |
612 | #define OSDIOCSCSICOMMAND _IOW('S', 0x3, struct scsi_fmt_cdb) | |
613 | ||
614 | sc.len = SCSICMDLEN(cdb->cdb_bytes[0]); | |
615 | bcopy(cdb->cdb_bytes, sc.cdb, sc.len); | |
616 | ret = ioctl(fd, OSDIOCSCSICOMMAND, &sc); | |
617 | } | |
618 | #endif | |
619 | if (ret < 0) | |
873fa9ad KB |
620 | (void)fprintf(stderr, |
621 | "scsiformat: SDIOCSCSICOMMAND: %s\n", strerror(errno)); | |
be2c1524 | 622 | else if (read(fd, buf, len) < 0) { |
873fa9ad KB |
623 | (void)fprintf(stderr, |
624 | "scsiformat: read: %s\n", strerror(errno)); | |
be2c1524 KB |
625 | pr_sense(fd); |
626 | } | |
3a637e8d | 627 | |
873fa9ad KB |
628 | if (ioctl(fd, SDIOCSFORMAT, &off) < 0) |
629 | (void)fprintf(stderr, | |
630 | "scsiformat: SDIOCSFORMAT (off): %s\n", strerror(errno)); | |
3a637e8d KB |
631 | } |
632 | ||
633 | void | |
634 | usage() | |
635 | { | |
df3858fd | 636 | (void)fprintf(stderr, "usage: scsiformat [-r] [-p c|d|s|v] device\n"); |
3a637e8d KB |
637 | exit(1); |
638 | } |