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