1 /* @(#)drv_simul.c	1.61 10/12/19 Copyright 1998-2010 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)drv_simul.c	1.61 10/12/19 Copyright 1998-2010 J. Schilling";
6 #endif
7 /*
8  *	Simulation device driver
9  *
10  *	Copyright (c) 1998-2010 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #ifndef	DEBUG
27 #define	DEBUG
28 #endif
29 #include <schily/mconfig.h>
30 
31 #include <schily/stdio.h>
32 #include <schily/standard.h>
33 #include <schily/stdlib.h>
34 #include <schily/unistd.h>
35 #include <schily/errno.h>
36 #include <schily/string.h>
37 #include <schily/time.h>
38 #include <schily/utypes.h>
39 #include <schily/btorder.h>
40 #include <schily/schily.h>
41 #include <schily/nlsdefs.h>
42 
43 /*#include <scgio.h>*/
44 #include <scg/scsidefs.h>
45 #include <scg/scsireg.h>
46 #include <scg/scsitransp.h>
47 
48 #include <schily/libport.h>
49 
50 #include "cdrecord.h"
51 
52 extern	int	silent;
53 extern	int	verbose;
54 extern	int	lverbose;
55 
56 LOCAL	int	simul_load		__PR((SCSI *scgp, cdr_t *));
57 LOCAL	int	simul_unload		__PR((SCSI *scgp, cdr_t *));
58 LOCAL	cdr_t	*identify_simul		__PR((SCSI *scgp, cdr_t *, struct scsi_inquiry *));
59 LOCAL	int	init_simul		__PR((SCSI *scgp, cdr_t *dp));
60 LOCAL	int	getdisktype_simul	__PR((SCSI *scgp, cdr_t *dp));
61 LOCAL	int	speed_select_simul	__PR((SCSI *scgp, cdr_t *dp, int *speedp));
62 LOCAL	int	next_wr_addr_simul	__PR((SCSI *scgp, track_t *trackp, long *ap));
63 LOCAL	int	cdr_write_simul		__PR((SCSI *scgp, caddr_t bp, long sectaddr, long size, int blocks, BOOL islast));
64 LOCAL	int	open_track_simul	__PR((SCSI *scgp, cdr_t *dp, track_t *trackp));
65 LOCAL	int	close_track_simul	__PR((SCSI *scgp, cdr_t *dp, track_t *trackp));
66 LOCAL	int	open_session_simul	__PR((SCSI *scgp, cdr_t *dp, track_t *trackp));
67 LOCAL	int	fixate_simul		__PR((SCSI *scgp, cdr_t *dp, track_t *trackp));
68 LOCAL	void	tv_sub			__PR((struct timeval *tvp1, struct timeval *tvp2));
69 
70 LOCAL int
simul_load(scgp,dp)71 simul_load(scgp, dp)
72 	SCSI	*scgp;
73 	cdr_t	*dp;
74 {
75 	return (0);
76 }
77 
78 LOCAL int
simul_unload(scgp,dp)79 simul_unload(scgp, dp)
80 	SCSI	*scgp;
81 	cdr_t	*dp;
82 {
83 	return (0);
84 }
85 
86 cdr_t	cdr_cdr_simul = {
87 	0, 0, 0,
88 	CDR_TAO|CDR_SAO|CDR_PACKET|CDR_RAW|CDR_RAW16|CDR_RAW96P|CDR_RAW96R|CDR_SRAW96P|CDR_SRAW96R|CDR_TRAYLOAD|CDR_SIMUL,
89 	0,
90 	CDR_CDRW_ALL,
91 	WM_SAO,
92 	40, 372,
93 	"cdr_simul",
94 	"simulation CD-R driver for timing/speed tests",
95 	0,
96 	(dstat_t *)0,
97 	identify_simul,
98 	drive_attach,
99 	init_simul,
100 	getdisktype_simul,
101 	no_diskstatus,
102 	simul_load,
103 	simul_unload,
104 	buf_dummy,
105 	cmd_dummy,					/* recovery_needed */
106 	(int(*)__PR((SCSI *, cdr_t *, int)))cmd_dummy,	/* recover	*/
107 	speed_select_simul,
108 	select_secsize,
109 	next_wr_addr_simul,
110 	(int(*)__PR((SCSI *, Ulong)))cmd_ill,	/* reserve_track	*/
111 	cdr_write_simul,
112 	(int(*)__PR((track_t *, void *, BOOL)))cmd_dummy,	/* gen_cue */
113 	(int(*)__PR((SCSI *scgp, cdr_t *, track_t *)))cmd_dummy, /* send_cue */
114 	(int(*)__PR((SCSI *, cdr_t *, track_t *)))cmd_dummy, /* leadin */
115 	open_track_simul,
116 	close_track_simul,
117 	open_session_simul,
118 	cmd_dummy,
119 	cmd_dummy,					/* abort	*/
120 	read_session_offset,
121 	fixate_simul,
122 	cmd_dummy,					/* stats	*/
123 	blank_dummy,
124 	format_dummy,
125 	(int(*)__PR((SCSI *, caddr_t, int, int)))NULL,	/* no OPC	*/
126 	cmd_dummy,					/* opt1		*/
127 	cmd_dummy,					/* opt2		*/
128 };
129 
130 cdr_t	cdr_dvd_simul = {
131 	0, 0, 0,
132 	CDR_TAO|CDR_SAO|CDR_PACKET|CDR_RAW|CDR_RAW16|CDR_RAW96P|CDR_RAW96R|CDR_SRAW96P|CDR_SRAW96R|CDR_DVD|CDR_TRAYLOAD|CDR_SIMUL,
133 	CDR2_NOCD,
134 	CDR_CDRW_ALL,
135 	WM_SAO,
136 	2, 1000,
137 	"dvd_simul",
138 	"simulation DVD-R driver for timing/speed tests",
139 	0,
140 	(dstat_t *)0,
141 	identify_simul,
142 	drive_attach,
143 	init_simul,
144 	getdisktype_simul,
145 	no_diskstatus,
146 	simul_load,
147 	simul_unload,
148 	buf_dummy,
149 	cmd_dummy,					/* recovery_needed */
150 	(int(*)__PR((SCSI *, cdr_t *, int)))cmd_dummy,	/* recover	*/
151 	speed_select_simul,
152 	select_secsize,
153 	next_wr_addr_simul,
154 	(int(*)__PR((SCSI *, Ulong)))cmd_ill,	/* reserve_track	*/
155 	cdr_write_simul,
156 	(int(*)__PR((track_t *, void *, BOOL)))cmd_dummy,	/* gen_cue */
157 	(int(*)__PR((SCSI *scgp, cdr_t *, track_t *)))cmd_dummy, /* send_cue */
158 	(int(*)__PR((SCSI *, cdr_t *, track_t *)))cmd_dummy, /* leadin */
159 	open_track_simul,
160 	close_track_simul,
161 	open_session_simul,
162 	cmd_dummy,
163 	cmd_dummy,					/* abort	*/
164 	read_session_offset,
165 	fixate_simul,
166 	cmd_dummy,					/* stats	*/
167 	blank_dummy,
168 	format_dummy,
169 	(int(*)__PR((SCSI *, caddr_t, int, int)))NULL,	/* no OPC	*/
170 	cmd_dummy,					/* opt1		*/
171 	cmd_dummy,					/* opt2		*/
172 };
173 
174 cdr_t	cdr_bd_simul = {
175 	0, 0, 0,
176 	CDR_TAO|CDR_SAO|CDR_PACKET|CDR_TRAYLOAD|CDR_SIMUL,
177 	CDR2_NOCD|CDR2_BD,
178 	CDR_CDRW_ALL,
179 	WM_SAO,
180 	2, 1000,
181 	"bd_simul",
182 	"simulation BD-R driver for timing/speed tests",
183 	0,
184 	(dstat_t *)0,
185 	identify_simul,
186 	drive_attach,
187 	init_simul,
188 	getdisktype_simul,
189 	no_diskstatus,
190 	simul_load,
191 	simul_unload,
192 	buf_dummy,
193 	cmd_dummy,					/* recovery_needed */
194 	(int(*)__PR((SCSI *, cdr_t *, int)))cmd_dummy,	/* recover	*/
195 	speed_select_simul,
196 	select_secsize,
197 	next_wr_addr_simul,
198 	(int(*)__PR((SCSI *, Ulong)))cmd_ill,	/* reserve_track	*/
199 	cdr_write_simul,
200 	(int(*)__PR((track_t *, void *, BOOL)))cmd_dummy,	/* gen_cue */
201 	(int(*)__PR((SCSI *scgp, cdr_t *, track_t *)))cmd_dummy, /* send_cue */
202 	(int(*)__PR((SCSI *, cdr_t *, track_t *)))cmd_dummy, /* leadin */
203 	open_track_simul,
204 	close_track_simul,
205 	open_session_simul,
206 	cmd_dummy,
207 	cmd_dummy,					/* abort	*/
208 	read_session_offset,
209 	fixate_simul,
210 	cmd_dummy,					/* stats	*/
211 	blank_dummy,
212 	format_dummy,
213 	(int(*)__PR((SCSI *, caddr_t, int, int)))NULL,	/* no OPC	*/
214 	cmd_dummy,					/* opt1		*/
215 	cmd_dummy,					/* opt2		*/
216 };
217 
218 LOCAL cdr_t *
identify_simul(scgp,dp,ip)219 identify_simul(scgp, dp, ip)
220 	SCSI			*scgp;
221 	cdr_t			*dp;
222 	struct scsi_inquiry	*ip;
223 {
224 	return (dp);
225 }
226 
227 LOCAL	long	simul_nwa;
228 LOCAL	int	simul_speed = 1;
229 LOCAL	int	simul_dummy;
230 LOCAL	int	simul_isdvd;
231 LOCAL	int	simul_isbd;
232 LOCAL	int	simul_bufsize = 1024;
233 LOCAL	Uint	sleep_rest;
234 LOCAL	Uint	sleep_max;
235 LOCAL	Uint	sleep_min;
236 
237 LOCAL int
init_simul(scgp,dp)238 init_simul(scgp, dp)
239 	SCSI	*scgp;
240 	cdr_t	*dp;
241 {
242 	return (speed_select_simul(scgp, dp, NULL));
243 }
244 
245 LOCAL int
getdisktype_simul(scgp,dp)246 getdisktype_simul(scgp, dp)
247 	SCSI	*scgp;
248 	cdr_t	*dp;
249 {
250 	dstat_t	*dsp = dp->cdr_dstat;
251 
252 	if (strcmp(dp->cdr_drname, cdr_cdr_simul.cdr_drname) == 0) {
253 		dsp->ds_maxblocks = 333000;
254 		simul_isdvd = FALSE;
255 	} else if (strcmp(dp->cdr_drname, cdr_dvd_simul.cdr_drname) == 0) {
256 		dsp->ds_maxblocks = 2464153;	/* 4.7 GB  */
257 /*		dsp->ds_maxblocks = 1927896;*/	/* 3.95 GB */
258 		dsp->ds_flags |= DSF_NOCD|DSF_DVD;
259 		simul_isdvd = TRUE;
260 	} else {
261 		dsp->ds_maxblocks = 12219392;	/* 25 GB  */
262 		dsp->ds_flags |= DSF_NOCD|DSF_BD;
263 		simul_isbd = TRUE;
264 	}
265 	return (drive_getdisktype(scgp, dp));
266 }
267 
268 
269 LOCAL int
speed_select_simul(scgp,dp,speedp)270 speed_select_simul(scgp, dp, speedp)
271 	SCSI	*scgp;
272 	cdr_t	*dp;
273 	int	*speedp;
274 {
275 	long	val;
276 	char	*p;
277 	BOOL	dummy = (dp->cdr_cmdflags & F_DUMMY) != 0;
278 
279 	if (speedp)
280 		simul_speed = *speedp;
281 	simul_dummy = dummy;
282 
283 	if ((p = getenv("CDR_SIMUL_BUFSIZE")) != NULL) {
284 		if (getnum(p, &val) == 1)
285 			simul_bufsize = val / 1024;
286 	}
287 
288 	/*
289 	 * sleep_max is the time to empty the drive's buffer in �s.
290 	 * sector size is from 2048 bytes to 2352 bytes.
291 	 * If sector size is 2048 bytes, 1k takes 6.666 ms.
292 	 * If sector size is 2352 bytes, 1k takes 5.805 ms.
293 	 * We take the 6 ms as an average between both values.
294 	 * simul_bufsize is the number of kilobytes in drive buffer.
295 	 */
296 	sleep_max = 6 * 1000 * simul_bufsize / simul_speed;
297 
298 	/*
299 	 * DVD single speed is 1385 * 1000 Bytes/s (676.27 sectors/s)
300 	 */
301 	if ((dp->cdr_flags & CDR_DVD) != 0)
302 		sleep_max = 739 * simul_bufsize / simul_speed;
303 
304 	/*
305 	 * BD single speed is 4495.5 * 1000 Bytes/s (2195.07 sectors/s)
306 	 */
307 	if ((dp->cdr_flags2 & CDR2_BD) != 0)
308 		sleep_max = 228 * simul_bufsize / simul_speed;
309 
310 	if (lverbose) {
311 		printf(_("Simulation drive buffer size: %d KB\n"), simul_bufsize);
312 		printf(_("Maximum reserve time in drive buffer: %d.%3.3d ms for speed %dx\n"),
313 					sleep_max / 1000,
314 					sleep_max % 1000,
315 					simul_speed);
316 	}
317 	return (0);
318 }
319 
320 LOCAL int
next_wr_addr_simul(scgp,trackp,ap)321 next_wr_addr_simul(scgp, trackp, ap)
322 	SCSI	*scgp;
323 	track_t	*trackp;
324 	long	*ap;
325 {
326 	/*
327 	 * This will most likely not 100% correct for TAO CDs
328 	 * but it is better than returning 0 in all cases.
329 	 */
330 	if (ap)
331 		*ap = simul_nwa;
332 	return (0);
333 }
334 
335 LOCAL int
cdr_write_simul(scgp,bp,sectaddr,size,blocks,islast)336 cdr_write_simul(scgp, bp, sectaddr, size, blocks, islast)
337 	SCSI	*scgp;
338 	caddr_t	bp;		/* address of buffer */
339 	long	sectaddr;	/* disk address (sector) to put */
340 	long	size;		/* number of bytes to transfer */
341 	int	blocks;		/* sector count */
342 	BOOL	islast;		/* last write for track */
343 {
344 	Uint	sleep_time;
345 	Uint	sleep_diff;
346 
347 	struct timeval	tv1;
348 static	struct timeval	tv2;
349 
350 	if (lverbose > 1 && islast)
351 		printf(_("\nWriting last record for this track.\n"));
352 
353 	simul_nwa += blocks;
354 
355 	gettimeofday(&tv1, (struct timezone *)0);
356 	if (tv2.tv_sec != 0) {		/* Already did gettimeofday(&tv2) */
357 		tv_sub(&tv1, &tv2);
358 		if (sleep_rest != 0) {
359 			sleep_diff = tv1.tv_sec * 1000000 + tv1.tv_usec;
360 
361 			if (sleep_min > (sleep_rest - sleep_diff))
362 				sleep_min = (sleep_rest - sleep_diff);
363 
364 			if (sleep_diff > sleep_rest) {
365 				printf(_("Buffer underrun: actual delay was %d.%3.3d ms, max delay was %d.%3.3d ms.\n"),
366 						sleep_diff / 1000,
367 						sleep_diff % 1000,
368 						sleep_rest / 1000,
369 						sleep_rest % 1000);
370 				if (!simul_dummy)
371 					return (-1);
372 			}
373 			/*
374 			 * If we spent time outside the write function
375 			 * subtract this time.
376 			 */
377 			sleep_diff = tv1.tv_sec * 1000000 + tv1.tv_usec;
378 			if (sleep_rest >= sleep_diff)
379 				sleep_rest -= sleep_diff;
380 			else
381 				sleep_rest = 0;
382 		}
383 	}
384 	/*
385 	 * Speed 1 ist 150 Sektoren/s
386 	 * Bei DVD 676.27 Sektoren/s
387 	 * Bei BD 2195.07 Sektoren/s
388 	 */
389 	sleep_time = 1000000 * blocks / 75 / simul_speed;
390 	if (simul_isdvd)
391 		sleep_time = 1000000 * blocks / 676 / simul_speed;
392 	if (simul_isbd)
393 		sleep_time = 1000000 * blocks / 2195 / simul_speed;
394 
395 	sleep_time += sleep_rest;
396 
397 	if (sleep_time > sleep_max) {
398 		int	mod;
399 		long	rsleep;
400 
401 		sleep_rest = sleep_max;
402 		sleep_time -= sleep_rest;
403 		mod = sleep_time % 20000;
404 		sleep_rest += mod;
405 		sleep_time -= mod;
406 		if (sleep_time > 0) {
407 			gettimeofday(&tv1, (struct timezone *)0);
408 			usleep(sleep_time);
409 			gettimeofday(&tv2, (struct timezone *)0);
410 			tv2.tv_sec -= tv1.tv_sec;
411 			tv2.tv_usec -= tv1.tv_usec;
412 			rsleep = tv2.tv_sec * 1000000 + tv2.tv_usec;
413 			sleep_rest -= rsleep - sleep_time;
414 		}
415 	} else {
416 		sleep_rest = sleep_time;
417 	}
418 
419 	gettimeofday(&tv2, (struct timezone *)0);
420 	return (size);
421 }
422 
423 LOCAL int
open_track_simul(scgp,dp,trackp)424 open_track_simul(scgp, dp, trackp)
425 	SCSI	*scgp;
426 	cdr_t	*dp;
427 	track_t *trackp;
428 {
429 	sleep_min = 999 * 1000000;
430 	return (0);
431 }
432 
433 LOCAL int
close_track_simul(scgp,dp,trackp)434 close_track_simul(scgp, dp, trackp)
435 	SCSI	*scgp;
436 	cdr_t	*dp;
437 	track_t	*trackp;
438 {
439 	if (lverbose) {
440 		printf(_("Remaining reserve time in drive buffer: %d.%3.3d ms\n"),
441 					sleep_rest / 1000,
442 					sleep_rest % 1000);
443 		printf(_("Minimum reserve time in drive buffer: %d.%3.3d ms\n"),
444 					sleep_min / 1000,
445 					sleep_min % 1000);
446 	}
447 	usleep(sleep_rest);
448 	sleep_rest = 0;
449 	return (0);
450 }
451 
452 LOCAL int
open_session_simul(scgp,dp,trackp)453 open_session_simul(scgp, dp, trackp)
454 	SCSI	*scgp;
455 	cdr_t	*dp;
456 	track_t	*trackp;
457 {
458 	simul_nwa = 0L;
459 	return (0);
460 }
461 
462 LOCAL int
fixate_simul(scgp,dp,trackp)463 fixate_simul(scgp, dp, trackp)
464 	SCSI	*scgp;
465 	cdr_t	*dp;
466 	track_t	*trackp;
467 {
468 	return (0);
469 }
470 
471 LOCAL void
tv_sub(tvp1,tvp2)472 tv_sub(tvp1, tvp2)
473 	struct timeval	*tvp1;
474 	struct timeval	*tvp2;
475 {
476 	tvp1->tv_sec -= tvp2->tv_sec;
477 	tvp1->tv_usec -= tvp2->tv_usec;
478 
479 	while (tvp1->tv_usec < 0) {
480 		tvp1->tv_usec += 1000000;
481 		tvp1->tv_sec -= 1;
482 	}
483 }
484