1 /* @(#)sinfo.c	1.39 13/04/30 Copyright 1988-2013 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)sinfo.c	1.39 13/04/30 Copyright 1988-2013 J. Schilling";
6 #endif
7 /*
8  *	Copyright (c) 1988-2013 J. Schilling
9  */
10 /*
11  * The contents of this file are subject to the terms of the
12  * Common Development and Distribution License, Version 1.0 only
13  * (the "License").  You may not use this file except in compliance
14  * with the License.
15  *
16  * See the file CDDL.Schily.txt in this distribution for details.
17  * A copy of the CDDL is also available via the Internet at
18  * http://www.opensource.org/licenses/cddl1.txt
19  *
20  * When distributing Covered Code, include this CDDL HEADER in each
21  * file and include the License file CDDL.Schily.txt from this distribution.
22  */
23 
24 #include <schily/param.h>	/* Include various defs needed with some OS */
25 #include <schily/stdio.h>
26 #include <schily/standard.h>
27 #include <schily/unistd.h>
28 #include <schily/stdlib.h>
29 #include <schily/string.h>
30 #include <schily/time.h>
31 #include <schily/hostname.h>
32 #include <schily/schily.h>
33 
34 /*#include <scg/scgcmd.h>*/
35 
36 #include "fmt.h"
37 
38 #include <scg/scsireg.h>
39 #include <scg/scsidefs.h>
40 #include <scg/scsitransp.h>
41 
42 #include "scsicmds.h"
43 
44 LOCAL long	sibuf[8*1024/sizeof (long)];
45 
46 extern	char	*Sbuf;
47 extern	long	Sbufsize;
48 
49 /*
50  * The next two structures always contain
51  * Mototola / network byte order.
52  */
53 struct si_stamp {
54 	u_long	si_xtime;	/* Reserve for year > 2038 */
55 	u_long	si_time;	/* 'sformat' format time */
56 	char	si_serial[16];	/* Hardware serial */
57 	char	si_uname[16];	/* user name */
58 	char	si_hname[64];	/* host name */
59 	char	si_dname[64];	/* domain name */
60 };
61 
62 struct sinfo {
63 	u_long	si_id;		/* some id */
64 	u_long	si_magic;	/* The magic to see if release >= 3.0 */
65 	u_long	si_release;	/* The release (for later enhancements) */
66 	u_long	si_reformats;	/* # of times the disk has been reformatted */
67 	u_short	si_ncyl;	/* # of cyls (may be we need this for dos) */
68 	u_short	si_spt;		/* # of sectors/track (see above) */
69 	u_char	si_nhead;	/* # of heads (may be we need this for dos) */
70 	u_char	si_cres[3];	/* Fill up to long boundary */
71 	u_long	si_res[2];	/* Reserved for later enhancements */
72 	struct si_stamp si_last; /* The data for the last format on this disk */
73 	struct si_stamp si_first; /* Data for the first sformat on this disk */
74 };
75 
76 #define	SI_MAGIC	0x4A534348
77 #define	SI_RELEASE	3
78 
79 extern	int	autoformat;
80 
81 LOCAL	u_long	sinfo_chksum	__PR((SCSI *scgp, u_long *));
82 LOCAL	void	fill_blk	__PR((SCSI *scgp, u_long *, u_long));
83 LOCAL	void	fill_sinfo	__PR((SCSI *scgp, struct sinfo *sinfo));
84 LOCAL	void	fill_stamp	__PR((struct si_stamp *stamp));
85 LOCAL	void	print_stamp	__PR((FILE *f, const char *fmt, struct si_stamp *stamp));
86 LOCAL	void	sinfo_geom	__PR((SCSI *scgp, struct disk *, long *, long *, long *));
87 EXPORT	void	print_sinfo	__PR((FILE *, SCSI *scgp));
88 EXPORT	BOOL	read_sinfo	__PR((SCSI *scgp, struct disk *, BOOL));
89 EXPORT	BOOL	write_sinfo	__PR((SCSI *scgp, struct disk *));
90 
91 /*
92 void
93 print_bk(dp, n)
94 	struct disk	*dp;
95 	long	n;
96 {
97 	long	cy;
98 	long	hd;
99 	long	se;
100 	long	sx;
101 	long	xx;
102 
103 	sx = dp->spt;
104 	if (dp->tpz != 0)
105 		sx -= dp->aspz/dp->tpz;
106 	xx = sx * dp->nhead;
107 	cy = 1 + n / xx;
108 	hd = n % xx;
109 	se = hd % sx;
110 	hd /= sx;
111 
112 	printf("Cyl: %ld Head: %ld Sec: %ld\n", cy, hd, se);
113 }
114 */
115 
116 LOCAL u_long
sinfo_chksum(scgp,lp)117 sinfo_chksum(scgp, lp)
118 	SCSI		*scgp;
119 	register u_long	*lp;
120 {
121 	register u_long	chksum;
122 	register int	i;
123 
124 	chksum = 0L;
125 	for (i = scgp->cap->c_bsize/sizeof (u_long) - 1; --i >= 0; ) {
126 		chksum ^= *lp++;
127 	}
128 	return (chksum);
129 }
130 
131 LOCAL void
fill_blk(scgp,blk,v)132 fill_blk(scgp, blk, v)
133 	SCSI		*scgp;
134 		u_long	*blk;
135 	register u_long	v;
136 {
137 	register u_long	*lp;
138 	register int	i;
139 
140 	lp = blk;
141 	srand((int)v);
142 	for (i = scgp->cap->c_bsize/sizeof (u_long) - 1; --i >= 0; ) {
143 		*lp++ = v;
144 		v = rand();
145 	}
146 }
147 
148 LOCAL void
fill_sinfo(scgp,sinfo)149 fill_sinfo(scgp, sinfo)
150 	SCSI		*scgp;
151 	struct sinfo	*sinfo;
152 {
153 /*	print_sinfo(stdout, scgp);*/
154 	fill_blk(scgp, (u_long *)sinfo, 0);
155 	sinfo->si_magic = SI_MAGIC;
156 	sinfo->si_release = SI_RELEASE;
157 	sinfo->si_reformats = 0;
158 
159 	sinfo->si_ncyl  = 0;
160 	sinfo->si_spt   = 0;
161 	sinfo->si_nhead = 0;
162 
163 	fill_stamp(&sinfo->si_first);
164 	fill_stamp(&sinfo->si_last);
165 
166 	((u_long *)sibuf)[scgp->cap->c_bsize/sizeof (u_long) - 1] =
167 					sinfo_chksum(scgp, (u_long *)sinfo);
168 }
169 
170 LOCAL void
fill_stamp(stamp)171 fill_stamp(stamp)
172 	struct si_stamp	*stamp;
173 {
174 	struct	timeval	tv;
175 	char	*uname;
176 
177 	gettimeofday(&tv, (struct timezone *)0);
178 	stamp->si_time = tv.tv_sec;
179 	stamp->si_xtime = 0;
180 
181 	sprintf(stamp->si_serial, "%lX", (unsigned long)gethostid());
182 
183 	uname = getlogin();
184 	if (uname == NULL)
185 		uname = getenv("USER");
186 	stamp->si_uname[0] = '\0';
187 	if (uname != NULL)
188 		strncpy(stamp->si_uname, uname, sizeof (stamp->si_uname));
189 	stamp->si_uname[sizeof (stamp->si_uname)-1] = '\0';
190 
191 	gethostname(stamp->si_hname, sizeof (stamp->si_hname)-1);
192 	stamp->si_hname[sizeof (stamp->si_hname)-1] = '\0';
193 
194 	getdomainname(stamp->si_dname, sizeof (stamp->si_dname)-1);
195 	stamp->si_dname[sizeof (stamp->si_dname)-1] = '\0';
196 }
197 
198 LOCAL void
print_stamp(f,fmt,stamp)199 print_stamp(f, fmt, stamp)
200 	FILE		*f;
201 	const	char	*fmt;
202 	struct si_stamp	*stamp;
203 {
204 	fprintf(f, "%s formatted with sformat id %s by:\n\t%s@%s%s%s on %s",
205 			fmt,
206 			stamp->si_serial,
207 			stamp->si_uname, stamp->si_hname,
208 			stamp->si_dname[0] == '.' ? "":".", stamp->si_dname,
209 			asctime(localtime((time_t *)&stamp->si_time)));
210 }
211 
212 LOCAL void
sinfo_geom(scgp,dp,sptp,aspzp,tpzp)213 sinfo_geom(scgp, dp, sptp, aspzp, tpzp)
214 	SCSI		*scgp;
215 	struct 	disk	*dp;
216 	long	*sptp;	/* Sectors/Track */
217 	long	*aspzp;	/* Alternate Sectors/Zone */
218 	long	*tpzp;	/* Tracks/Zone */
219 {
220 	if (dp->spt < 0 || dp->aspz < 0 || dp->tpz < 0) {
221 		scgp->silent++;
222 		dp->formatted++;
223 		get_defaults(scgp, dp);
224 		dp->formatted--;
225 		scgp->silent--;
226 	}
227 	*sptp  = dp->spt;
228 	*aspzp = dp->aspz;
229 	*tpzp  = dp->tpz;
230 	/*
231 	 * Wenn tpz == 0 (die ganze Platte ist eine Zone), dann wird
232 	 * aspz == 0 und tpz == 1, damit wird (spt - aspz/tpz) == spt,
233 	 * was der Realitaet entspricht.
234 	 */
235 	if (dp->tpz == 0) {
236 		*tpzp = 1L;
237 		*aspzp = 0L;
238 	}
239 	/*
240 	 * Bei unbekannter Geometrie kommen der primaere und der sekundaere
241 	 * Sformat info Block direkt hintereinander: (spt - aspz/tpz) == 1.
242 	 */
243 	if (dp->spt < 0 || dp->aspz < 0 || dp->tpz < 0) {
244 		*sptp = *tpzp = 1L;
245 		*aspzp = 0L;
246 	}
247 }
248 
249 EXPORT void
print_sinfo(f,scgp)250 print_sinfo(f, scgp)
251 	FILE	*f;
252 	SCSI	*scgp;
253 {
254 	struct sinfo	*sinfo = (struct sinfo *)sibuf;
255 
256 	fprintf(f, "Disk info:\n");
257 	if (sinfo->si_id != 0)
258 		fprintf(f, "\tSinfo id: %ld\n", sinfo->si_id);
259 	if (sinfo->si_magic != SI_MAGIC)
260 		fprintf(f, "\tSinfo magic: 0x%lX\n", sinfo->si_magic);
261 
262 	if (sinfo->si_magic != SI_MAGIC ||
263 			(sinfo_chksum(scgp, (u_long *)sibuf) !=
264 			((u_long *)sibuf)[scgp->cap->c_bsize/sizeof (u_long) - 1])) {
265 		fprintf(f, "\tDisk seems not to be formatted with sformat (release >= 3.0) before.\n");
266 		return;
267 	}
268 	fprintf(f, "\tNumber of reformats: %ld\n", sinfo->si_reformats);
269 
270 	print_stamp(f, "\tFirst", &sinfo->si_first);
271 	if (sinfo->si_reformats > 0)
272 		print_stamp(f, "\tLast ", &sinfo->si_last);
273 	fprintf(f, "\n");
274 }
275 
276 EXPORT BOOL
read_sinfo(scgp,dp,isformat)277 read_sinfo(scgp, dp, isformat)
278 	SCSI		*scgp;
279 	struct disk	*dp;
280 	BOOL		isformat;
281 {
282 	int	overbose;
283 	long	spt;
284 	long	aspz;
285 	long	tpz;
286 	BOOL	ret = TRUE;
287 
288 	overbose = scgp->verbose;
289 	scgp->silent++;
290 	if (read_capacity(scgp) < 0) {
291 		scgp->silent--;
292 		scgp->verbose = overbose;
293 		return (FALSE);
294 	}
295 	if (scgp->cap->c_bsize > sizeof (sibuf))
296 		comerrno(EX_BAD, "PANIC Sectorsize.\n");
297 
298 	sinfo_geom(scgp, dp, &spt, &aspz, &tpz);
299 
300 	fillbytes((caddr_t)sibuf, sizeof (sibuf), '\0');
301 	if (read_scsi(scgp, (caddr_t)sibuf, scgp->cap->c_baddr, 1) < 0 &&
302 	    read_scsi(scgp, (caddr_t)sibuf, scgp->cap->c_baddr - (spt - aspz/tpz), 1) < 0) {
303 		errmsgno(EX_BAD, "Cannot read sformat info.\n");
304 		scgp->silent--;
305 		scgp->verbose = overbose;
306 		return (FALSE);
307 	}
308 	scgp->silent--;
309 	scgp->verbose = overbose;
310 
311 	if (sinfo_chksum(scgp, (u_long *)sibuf) !=
312 			((u_long *)sibuf)[scgp->cap->c_bsize/sizeof (u_long) - 1]) {
313 		errmsgno(EX_BAD, "Sformat info not initialized or damaged.\n");
314 		ret = FALSE;
315 	}
316 	if (isformat) {
317 		if (((struct sinfo *)sibuf)->si_magic != SI_MAGIC ||
318 				((struct sinfo *)sibuf)->si_release < SI_RELEASE) {
319 			/*
320 			 * Need to upgrade sinfo
321 			 */
322 			fill_sinfo(scgp, (struct sinfo *)sibuf);
323 		} else {
324 			/*
325 			 * Need to mark this format action
326 			 */
327 			((struct sinfo *)sibuf)->si_reformats++;
328 			fill_stamp(&((struct sinfo *)sibuf)->si_last);
329 			((u_long *)sibuf)[scgp->cap->c_bsize/sizeof (u_long) - 1] =
330 						sinfo_chksum(scgp, (u_long *)sibuf);
331 		}
332 	}
333 	return (ret);
334 }
335 
336 EXPORT BOOL
write_sinfo(scgp,dp)337 write_sinfo(scgp, dp)
338 	SCSI		*scgp;
339 	struct disk	*dp;
340 {
341 	int	overbose;
342 	long	spt;
343 	long	aspz;
344 	long	tpz;
345 
346 	overbose = scgp->verbose;
347 	scgp->silent++;
348 	if (read_capacity(scgp) < 0) {
349 		scgp->silent--;
350 		scgp->verbose = overbose;
351 		return (FALSE);
352 	}
353 	if (scgp->cap->c_bsize > sizeof (sibuf))
354 		comerrno(EX_BAD, "PANIC Sectorsize.\n");
355 
356 	sinfo_geom(scgp, dp, &spt, &aspz, &tpz);
357 
358 	if (write_scsi(scgp, (caddr_t)sibuf, scgp->cap->c_baddr, 1) < 0) {
359 		errmsgno(EX_BAD, "Cannot write sformat info.\n");
360 		scgp->silent--;
361 		scgp->verbose = overbose;
362 		return (FALSE);
363 	}
364 	if (write_scsi(scgp, (caddr_t)sibuf, scgp->cap->c_baddr - (spt - aspz/tpz), 1) < 0) {
365 		errmsgno(EX_BAD, "Cannot write backup sformat info.\n");
366 		scgp->silent--;
367 		scgp->verbose = overbose;
368 		return (FALSE);
369 	}
370 	scgp->silent--;
371 	scgp->verbose = overbose;
372 	return (TRUE);
373 }
374 
375