xref: /original-bsd/sbin/scsiformat/scsiformat.c (revision 860e07fc)
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  *
11  *	@(#)scsiformat.c	5.2 (Berkeley) 07/20/92
12  */
13 
14 #include <sys/param.h>
15 #include <sys/ioctl.h>
16 #include <hp300/dev/scsireg.h>
17 
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 
25 struct scsi_inquiry inqbuf;
26 struct {
27 	int blks;
28 	int blksize;
29 } capbuf;
30 struct {
31 	struct scsi_modesense_hdr h;
32 	u_char p[126-12];
33 } msbuf;
34 
35 struct scsi_fmt_cdb inq = {
36 	6,
37 	CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
38 };
39 struct scsi_fmt_cdb cap = {
40 	10,
41 	CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
42 };
43 struct scsi_fmt_cdb modesense = {
44 	6,
45 	CMD_MODE_SENSE, 0, 0x3f, 0, sizeof(msbuf), 0
46 };
47 
48 int fd;
49 char *device;
50 
51 void	do_command __P((int, struct scsi_fmt_cdb *, u_char *, int));
52 void	print_capacity __P((void));
53 void	print_inquiry __P((void));
54 u_char *print_mode_page __P((u_char *));
55 void	print_mode_sense __P((void));
56 void	usage __P((void));
57 
58 int
59 main (argc, argv)
60 	int argc;
61 	char *argv[];
62 {
63 	int ch;
64 
65 	while ((ch = getopt(argc, argv, "")) != EOF)
66 		switch(ch) {
67 		case '?':
68 		default:
69 			usage();
70 		}
71 	argc -= optind;
72 	argv += optind;
73 
74 	if (argc != 1)
75 		usage();
76 
77 	device = *argv;
78 	if ((fd = open(device, O_RDWR, 0)) < 0) {
79 		(void)fprintf(stderr,
80 		    "scsiformat: %s: %s\n", device, strerror(errno));
81 		exit(1);
82 	}
83 	print_inquiry();
84 	print_capacity();
85 	print_mode_sense();
86 	exit(0);
87 }
88 
89 void
90 print_inquiry()
91 {
92 	char idstr[32];
93 	int i;
94 
95 	do_command(fd, &inq, (u_char *)&inqbuf, sizeof(inqbuf));
96 	printf("%s: ", device);
97 
98 	if (inqbuf.version != 1) {
99 		printf("type 0x%x, qual 0x%x, ver %d\n", inqbuf.type,
100 			inqbuf.qual, inqbuf.version);
101 		return;
102 	}
103 	switch (inqbuf.type) {
104 	case 0:		printf("(disk)"); break;
105 	case 4:		printf("(WORM)"); break;
106 	case 5:		printf("(CD-ROM)"); break;
107 	case 7:		printf("(MO-DISK)"); break;
108 	default:	printf("(??)"); break;
109 	}
110 	bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
111 	for (i = 27; i > 23; --i)
112 		if (idstr[i] != ' ')
113 			break;
114 	idstr[i+1] = 0;
115 	for (i = 23; i > 7; --i)
116 		if (idstr[i] != ' ')
117 			break;
118 	idstr[i+1] = 0;
119 	for (i = 7; i >= 0; --i)
120 		if (idstr[i] != ' ')
121 			break;
122 	idstr[i+1] = 0;
123 	printf(" %s %s rev %s:", idstr, &idstr[8], &idstr[24]);
124 }
125 
126 void
127 print_capacity()
128 {
129 	do_command(fd, &cap, (u_char *)&capbuf, sizeof(capbuf));
130 	printf(" %d blocks of %d bytes each\n", capbuf.blks, capbuf.blksize);
131 }
132 
133 void
134 print_mode_sense()
135 {
136 	u_char *cp;
137 	u_char *ep;
138 
139 	do_command(fd, &modesense, (u_char *)&msbuf, sizeof(msbuf));
140 
141 	printf("\n%d bytes of mode sense data.  ", msbuf.h.len);
142 	printf("media type %d, %swrite protected\n", msbuf.h.media_type,
143 		msbuf.h.wp? "" : "not ");
144 	if (msbuf.h.block_desc_len) {
145 		printf("density 0x%x, ", msbuf.h.density);
146 		if (msbuf.h.number_blocks)
147 			printf("%d blocks of length %d\n",
148 				msbuf.h.number_blocks, msbuf.h.block_length);
149 		else
150 			printf("all blocks of length %d\n",
151 				msbuf.h.block_length);
152 		cp = msbuf.p;
153 	} else
154 		cp = &msbuf.h.block_desc_len + 1;
155 
156 	ep = (u_char *)&msbuf + msbuf.h.len;
157 	while (cp < ep)
158 		cp = print_mode_page(cp);
159 }
160 
161 u_char *
162 print_mode_page(cp)
163 	u_char *cp;
164 {
165 	int n = cp[1];
166 	int i;
167 	char c;
168 
169 	printf("\npage type %d%s (%d bytes): ", cp[0] & 0x7f,
170 		(cp[0] & 0x80)? " (saveable)" : "", n);
171 	switch (cp[0] & 0x7f) {
172 	case 1:
173 		printf("Error Recovery parameters.\n");
174 		printf("\tflags = 0x%x ", i = cp[2]);
175 		c = '<';
176 		if (i & 0x80) {
177 			printf("%cAWRE", c);
178 			c = ',';
179 		}
180 		if (i & 0x40) {
181 			printf("%cARRE", c);
182 			c = ',';
183 		}
184 		if (i & 0x20) {
185 			printf("%cTB", c);
186 			c = ',';
187 		}
188 		if (i & 0x10) {
189 			printf("%cRC", c);
190 			c = ',';
191 		}
192 		if (i & 0x08) {
193 			printf("%cEEC", c);
194 			c = ',';
195 		}
196 		if (i & 0x04) {
197 			printf("%cPER", c);
198 			c = ',';
199 		}
200 		if (i & 0x02) {
201 			printf("%cDTE", c);
202 			c = ',';
203 		}
204 		if (i & 0x01) {
205 			printf("%cDCR", c);
206 			c = ',';
207 		}
208 		if (c == ',')
209 			printf(">");
210 
211 		printf("\n\t%d retries, %d correction span bits,\n", cp[3],
212 			cp[4]);
213 		printf("\t%d head offsets, %d data strobe offsets,\n\t",
214 			cp[5], cp[6]);
215 		if (cp[7] != 0xff)
216 			printf("%d", cp[7]);
217 		else
218 			printf("no");
219 		printf(" recovery time limit.\n");
220 		cp += 8;
221 		break;
222 
223 	case 2:
224 		printf("Disconnect/Reconnect control.\n");
225 		printf("\tbuffer full ratio %d, buffer empty ratio %d,\n",
226 			cp[2], cp[3]);
227 		printf("\ttime limits: %d bus inactivity, ",
228 			*(u_short *)&cp[4]);
229 		printf("%d disconnect, %d connect.\n",
230 			*(u_short *)&cp[6],*(u_short *)&cp[8]);
231 		cp += 12;
232 		break;
233 
234 	case 3:
235 		{
236 		struct scsi_format *sf = (struct scsi_format *)cp;
237 		printf("Format parameters.\n");
238 		printf("\t%d tracks/zone, %d alt.sect./zone, ",
239 			sf->tracks_per_zone, sf->alt_sect_zone);
240 		printf("%d alt.tracks/zone,\n\t%d alt.tracks/vol., ",
241 			sf->alt_tracks_zone, sf->alt_tracks_vol);
242 		printf("%d sectors/track, %d bytes/sector, interleave %d\n",
243 			sf->sect_track, sf->data_sect, sf->interleave);
244 		printf("\ttrack skew %d, cylinder skew %d,\n",
245 			sf->track_skew_factor, sf->cyl_skew_factor);
246 		printf("\tdrive type 0x%x ", i = cp[20]);
247 		c = '<';
248 		if (i & 0x80) {
249 			printf("%cSSEC", c);
250 			c = ',';
251 		}
252 		if (i & 0x40) {
253 			printf("%cHSEC", c);
254 			c = ',';
255 		}
256 		if (i & 0x20) {
257 			printf("%cRMB", c);
258 			c = ',';
259 		}
260 		if (i & 0x10) {
261 			printf("%cSURF", c);
262 			c = ',';
263 		}
264 		if (i & 0x08) {
265 			printf("%cINS", c);
266 			c = ',';
267 		}
268 		if (i & 0x04) {
269 			printf("%c?", c);
270 			c = ',';
271 		}
272 		if (i & 0x02) {
273 			printf("%c?", c);
274 			c = ',';
275 		}
276 		if (i & 0x01) {
277 			printf("%c?", c);
278 			c = ',';
279 		}
280 		if (c == ',')
281 			printf(">");
282 		printf("\n");
283 		cp += 24;
284 		}
285 		break;
286 
287 	case 4:
288 		printf("Disk Geometry parameters.\n");
289 		printf("\t%d cylinders, %d heads.\n",
290 			(cp[2] << 16) | (cp[3] << 8) | cp[4], cp[5]);
291 		cp += cp[1] + 2;
292 		break;
293 
294 	default:
295 		printf("Unknown page type.");
296 		for (cp += 2, i = 0; i < n; ++i) {
297 			if ((i & 7) == 0)
298 				printf("\n\t%2d ", i);
299 			printf(" %02x", *cp++);
300 		}
301 		printf("\n");
302 		break;
303 	}
304 	return (cp);
305 }
306 
307 void
308 do_command(fd, cdb, buf, len)
309 	int fd;
310 	struct scsi_fmt_cdb *cdb;
311 	u_char *buf;
312 	int len;
313 {
314 	static int on = 1;
315 	static int off = 0;
316 
317 	if (ioctl(fd, SDIOCSFORMAT, &on) < 0) {
318 		(void)fprintf(stderr,
319 		    "scsiformat: SDIOCSFORMAT (on): %s\n", strerror(errno));
320 		return;
321 	}
322 	if (ioctl(fd, SDIOCSCSICOMMAND, cdb) < 0)
323 		(void)fprintf(stderr,
324 		    "scsiformat: SDIOCSCSICOMMAND: %s\n", strerror(errno));
325 	else if (read(fd, buf, len) < 0)
326 		(void)fprintf(stderr,
327 		    "scsiformat: read: %s\n", strerror(errno));
328 
329 	if (ioctl(fd, SDIOCSFORMAT, &off) < 0)
330 		(void)fprintf(stderr,
331 		    "scsiformat: SDIOCSFORMAT (off): %s\n", strerror(errno));
332 }
333 
334 void
335 usage()
336 {
337 	(void)fprintf(stderr, "usage: scsiformat device\n");
338 	exit(1);
339 }
340