1 /*
2  *   libdi - scsipt SCSI Device Interface Library
3  *
4  *   Copyright (C) 1993-2004  Ti Kan
5  *   E-mail: xmcd@amb.org
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 #ifndef lint
22 static char *_cdsim_c_ident_ = "@(#)cdsim.c	6.33 04/03/11";
23 #endif
24 
25 #include "common_d/appenv.h"
26 #include "common_d/util.h"
27 #include "libdi_d/libdi.h"
28 #include "libdi_d/scsipt.h"
29 
30 #ifdef DEMO_ONLY
31 
32 #ifndef CDSIM_VERS
33 #define CDSIM_VERS		"2.00"	/* CD-ROM simulator version */
34 #endif
35 
36 extern appdata_t		app_data;
37 extern FILE			*errfp;
38 
39 STATIC simstat_t		cdsim_stat;
40 STATIC time_t			cdsim_start_time,
41 				cdsim_pause_time,
42 				cdsim_pause_elapsed,
43 				cdsim_prev_pause,
44 				cdsim_elapsed,
45 				cdsim_now;
46 
47 STATIC inquiry_data_t		cdsim_inqdata;
48 STATIC byte_t			cdsim_tocdata1[SZ_RDTOC],
49 				cdsim_tocdata2[SZ_RDTOC];
50 
51 STATIC int			cdsim_sfd,
52 				cdsim_rfd;
53 
54 
55 /*
56  * cdsim_sendpkt
57  *	Write a CD simulator packet down the pipe
58  *
59  * Args:
60  *	name - The text string describing the caller module
61  *	fd - Pipe file descriptor
62  *	s - Pointer to the packet data
63  *
64  * Return:
65  *	TRUE - pipe write successful
66  *	FALSE - pipe write failed
67  */
68 bool_t
cdsim_sendpkt(char * name,int fd,simpkt_t * s)69 cdsim_sendpkt(char *name, int fd, simpkt_t *s)
70 {
71 	byte_t	*p = (byte_t *) s;
72 	int	i,
73 		ret;
74 
75 	if (fd < 0)
76 		return FALSE;
77 
78 	/* Brand packet with magic number */
79 	s->magic = CDSIM_MAGIC;
80 
81 	/* Send a packet */
82 	i = CDSIM_PKTSZ;
83 	while ((ret = write(fd, p, i)) < i) {
84 		if (ret < 0 && errno != EBADF) {
85 			(void) fprintf(errfp,
86 				       "%s: packet write error (errno=%d)\n",
87 				       name, errno);
88 			return FALSE;
89 		}
90 
91 		if (ret == 0) {
92 			/* avoid hogging CPU */
93 			util_delayms(1000);
94 		}
95 		else {
96 			i -= ret;
97 			p += ret;
98 		}
99 	}
100 
101 	return TRUE;
102 }
103 
104 
105 /*
106  * cdsim_getpkt
107  *	Read a CD simulator packet from the pipe
108  *
109  * Args:
110  *	name - The text string describing the caller module
111  *	fd - Pipe file descriptor
112  *	s - Pointer to the packet data
113  *
114  * Return:
115  *	TRUE - pipe read successful
116  *	FALSE - pipe read failed
117  */
118 bool_t
cdsim_getpkt(char * name,int fd,simpkt_t * r)119 cdsim_getpkt(char *name, int fd, simpkt_t *r)
120 {
121 	byte_t	*p = (byte_t *) r;
122 	int	i,
123 		ret;
124 
125 	if (fd < 0)
126 		return FALSE;
127 
128 	/* Get a packet */
129 	i = CDSIM_PKTSZ;
130 	while ((ret = read(fd, p, i)) < i) {
131 		if (ret < 0 && errno != EBADF) {
132 			(void) fprintf(errfp,
133 				       "%s: packet read error (errno=%d)\n",
134 				       name, errno);
135 			return FALSE;
136 		}
137 
138 		if (ret == 0) {
139 			/* avoid hogging CPU */
140 			util_delayms(1000);
141 		}
142 		else {
143 			i -= ret;
144 			p += ret;
145 		}
146 	}
147 
148 	/* Check packet for magic number */
149 	if (r->magic != CDSIM_MAGIC) {
150 		(void) fprintf(errfp, "%s: bad packet magic number.\n", name);
151 		return FALSE;
152 	}
153 
154 	return TRUE;
155 }
156 
157 
158 /*
159  * cdsim_sig
160  *	CD simulator process signal handler
161  *
162  * Args:
163  *	sig - The signal number
164  *
165  * Return:
166  *	Nothing.
167  */
168 /*ARGSUSED*/
169 STATIC void
cdsim_sig(int sig)170 cdsim_sig(int sig)
171 {
172 	(void) fprintf(errfp, "CD-ROM simulator pid=%d exiting.\n",
173 			(int) getpid());
174 	(void) close(cdsim_sfd);
175 	(void) close(cdsim_rfd);
176 	_exit(0);
177 }
178 
179 
180 /*
181  * cdsim_s_test
182  *	Test Unit Ready command simulation function
183  *
184  * Args:
185  *	r - Pointer to the command packet
186  *	s - Pointer to the response packet
187  *
188  * Return:
189  *	Command completion status code
190  */
191 /*ARGSUSED*/
192 STATIC byte_t
cdsim_s_test(simpkt_t * r,simpkt_t * s)193 cdsim_s_test(simpkt_t *r, simpkt_t *s)
194 {
195 	if (cdsim_stat.status == CDSIM_NODISC)
196 		return CDSIM_COMPERR;
197 	else
198 		return CDSIM_COMPOK;
199 }
200 
201 
202 /*
203  * cdsim_s_inquir
204  *	Inquiry command simulation function
205  *
206  * Args:
207  *	r - Pointer to the command packet
208  *	s - Pointer to the response packet
209  *
210  * Return:
211  *	Command completion status code
212  */
213 STATIC byte_t
cdsim_s_inquir(simpkt_t * r,simpkt_t * s)214 cdsim_s_inquir(simpkt_t *r, simpkt_t *s)
215 {
216 	s->len = (r->len > CDSIM_INQSZ) ? CDSIM_INQSZ : r->len;
217 
218 	/* Copy inquiry data into packet */
219 	(void) memcpy(s->data, (byte_t *) &cdsim_inqdata, s->len);
220 
221 	return CDSIM_COMPOK;
222 }
223 
224 
225 /*
226  * cdsim_s_mselect
227  *	Mode Select (6) command simulation function
228  *
229  * Args:
230  *	r - Pointer to the command packet
231  *	s - Pointer to the response packet
232  *
233  * Return:
234  *	Command completion status code
235  */
236 /*ARGSUSED*/
237 STATIC byte_t
cdsim_s_mselect(simpkt_t * r,simpkt_t * s)238 cdsim_s_mselect(simpkt_t *r, simpkt_t *s)
239 {
240 	return CDSIM_COMPOK;
241 }
242 
243 
244 /*
245  * cdsim_m_mselect
246  *	Mode Select (10) command simulation function
247  *
248  * Args:
249  *	r - Pointer to the command packet
250  *	s - Pointer to the response packet
251  *
252  * Return:
253  *	Command completion status code
254  */
255 /*ARGSUSED*/
256 STATIC byte_t
cdsim_m_mselect(simpkt_t * r,simpkt_t * s)257 cdsim_m_mselect(simpkt_t *r, simpkt_t *s)
258 {
259 	return CDSIM_COMPOK;
260 }
261 
262 
263 /*
264  * cdsim_s_msense
265  *	Mode Sense (6) command simulation function
266  *
267  * Args:
268  *	r - Pointer to the command packet
269  *	s - Pointer to the response packet
270  *
271  * Return:
272  *	Command completion status code
273  */
274 /*ARGSUSED*/
275 STATIC byte_t
cdsim_s_msense(simpkt_t * r,simpkt_t * s)276 cdsim_s_msense(simpkt_t *r, simpkt_t *s)
277 {
278 	return CDSIM_COMPOK;
279 }
280 
281 
282 /*
283  * cdsim_m_msense
284  *	Mode Sense (10) command simulation function
285  *
286  * Args:
287  *	r - Pointer to the command packet
288  *	s - Pointer to the response packet
289  *
290  * Return:
291  *	Command completion status code
292  */
293 /*ARGSUSED*/
294 STATIC byte_t
cdsim_m_msense(simpkt_t * r,simpkt_t * s)295 cdsim_m_msense(simpkt_t *r, simpkt_t *s)
296 {
297 	return CDSIM_COMPOK;
298 }
299 
300 
301 /*
302  * cdsim_s_start
303  *	Start/Stop Unit command simulation function
304  *
305  * Args:
306  *	r - Pointer to the command packet
307  *	s - Pointer to the response packet
308  *
309  * Return:
310  *	Command completion status code
311  */
312 /*ARGSUSED*/
313 STATIC byte_t
cdsim_s_start(simpkt_t * r,simpkt_t * s)314 cdsim_s_start(simpkt_t *r, simpkt_t *s)
315 {
316 	cdsim_start_time = 0;
317 	cdsim_elapsed = 0;
318 	cdsim_pause_time = 0;
319 	cdsim_pause_elapsed = 0;
320 	cdsim_prev_pause = 0;
321 
322 	if (r->cdb[4] & 0x01) {
323 		/* Start unit */
324 		if (r->cdb[4] & 0x02) {
325 			/* Load disc */
326 			cdsim_stat.status = CDSIM_STOPPED;
327 			return CDSIM_COMPOK;
328 		}
329 		else if (cdsim_stat.status == CDSIM_NODISC)
330 			return CDSIM_COMPERR;
331 	}
332 	else {
333 		/* Stop unit */
334 		if (cdsim_stat.status == CDSIM_NODISC)
335 			return CDSIM_COMPERR;
336 		else if (r->cdb[4] & 0x02) {
337 			/* Eject disc */
338 			if (cdsim_stat.caddylock)
339 				return CDSIM_COMPERR;
340 			else {
341 				cdsim_stat.status = CDSIM_NODISC;
342 				return CDSIM_COMPOK;
343 			}
344 		}
345 		else {
346 			/* Stop disc */
347 			cdsim_stat.status = CDSIM_STOPPED;
348 			return CDSIM_COMPOK;
349 		}
350 	}
351 	return CDSIM_COMPOK;
352 }
353 
354 
355 /*
356  * cdsim_s_prevent
357  *	Prevent/Allow Medium Removal command simulation function
358  *
359  * Args:
360  *	r - Pointer to the command packet
361  *	s - Pointer to the response packet
362  *
363  * Return:
364  *	Command completion status code
365  */
366 /*ARGSUSED*/
367 STATIC byte_t
cdsim_s_prevent(simpkt_t * r,simpkt_t * s)368 cdsim_s_prevent(simpkt_t *r, simpkt_t *s)
369 {
370 	if (r->cdb[4] & 0x01)
371 		cdsim_stat.caddylock = TRUE;
372 	else
373 		cdsim_stat.caddylock = FALSE;
374 
375 	return CDSIM_COMPOK;
376 }
377 
378 
379 /*
380  * cdsim_m_rdsubq
381  *	Read Subchannel command simulation function
382  *
383  * Args:
384  *	r - Pointer to the command packet
385  *	s - Pointer to the response packet
386  *
387  * Return:
388  *	Command completion status code
389  */
390 STATIC byte_t
cdsim_m_rdsubq(simpkt_t * r,simpkt_t * s)391 cdsim_m_rdsubq(simpkt_t *r, simpkt_t *s)
392 {
393 	subq_hdr_t	*h = (subq_hdr_t *)(void *) s->data;
394 	subq_01_t	*s1 = (subq_01_t *)(void *)
395 			      (s->data + sizeof(subq_hdr_t));
396 
397 	/* Subchannel formats */
398 	switch (r->cdb[3]) {
399 	case SUB_CURPOS:
400 		h->subch_len = 15;
401 
402 		s1->fmt_code = SUB_CURPOS;
403 		s1->preemph = 0;
404 		s1->copyallow = 0;
405 		s1->trktype = 0;
406 		s1->audioch = 0;
407 		s1->adr = 0;
408 
409 		s1->trkno = cdsim_stat.trkno;
410 		s1->idxno = cdsim_stat.idxno;
411 
412 		if (r->cdb[1] & 0x02) {
413 			util_blktomsf(
414 				cdsim_stat.absaddr,
415 				&s1->abs_addr.msf.min,
416 				&s1->abs_addr.msf.sec,
417 				&s1->abs_addr.msf.frame,
418 				MSF_OFFSET
419 			);
420 
421 			util_blktomsf(
422 				cdsim_stat.reladdr,
423 				&s1->rel_addr.msf.min,
424 				&s1->rel_addr.msf.sec,
425 				&s1->rel_addr.msf.frame,
426 				0
427 			);
428 		}
429 		else {
430 			s1->abs_addr.logical = util_bswap32(cdsim_stat.absaddr);
431 			s1->rel_addr.logical = util_bswap32(cdsim_stat.reladdr);
432 		}
433 
434 		s->len = sizeof(subq_hdr_t) + sizeof(subq_01_t);
435 
436 		break;
437 
438 	default:
439 		/* The other formats are not implemented */
440 		return CDSIM_COMPERR;
441 	}
442 
443 	switch (cdsim_stat.status) {
444 	case CDSIM_PLAYING:
445 		h->audio_status = AUDIO_PLAYING;
446 		break;
447 
448 	case CDSIM_PAUSED:
449 		h->audio_status = AUDIO_PAUSED;
450 		break;
451 
452 	default:
453 		h->audio_status = AUDIO_COMPLETED;
454 		break;
455 	}
456 
457 	return CDSIM_COMPOK;
458 }
459 
460 
461 /*
462  * cdsim_m_rdtoc
463  *	Read TOC command simulation function
464  *
465  * Args:
466  *	r - Pointer to the command packet
467  *	s - Pointer to the response packet
468  *
469  * Return:
470  *	Command completion status code
471  */
472 STATIC byte_t
cdsim_m_rdtoc(simpkt_t * r,simpkt_t * s)473 cdsim_m_rdtoc(simpkt_t *r, simpkt_t *s)
474 {
475 	byte_t	*startoff,
476 		fmt;
477 
478 	fmt = (r->cdb[2] & 0x0f);
479 
480 	switch (fmt) {
481 	case 0:
482 		/* Read track TOC */
483 		break;
484 	case 1: /* Session info */
485 	case 2:	/* Full TOC */
486 	case 3:	/* PMA */
487 	case 4:	/* ATIP */
488 	case 5:	/* CD-TEXT */
489 		/* These are not supported */
490 		return CDSIM_PARMERR;
491 	}
492 
493 	if (r->cdb[1] & 0x02)
494 		startoff = cdsim_tocdata2 + sizeof(toc_hdr_t);
495 	else
496 		startoff = cdsim_tocdata1 + sizeof(toc_hdr_t);
497 
498 	s->len = (r->len > SZ_RDTOC) ? SZ_RDTOC : r->len;
499 
500 	if (r->cdb[6] > 1) {
501 		int	skip;
502 
503 		skip = ((int) r->cdb[6] - 1) *
504 			sizeof(toc_trk_descr_t);
505 		s->len -= skip;
506 		startoff += skip;
507 	}
508 
509 	/* Copy TOC data into packet */
510 
511 	/* Header info */
512 	(void) memcpy(s->data, cdsim_tocdata1, sizeof(toc_hdr_t));
513 
514 	/* TOC data */
515 	(void) memcpy(s->data + sizeof(toc_hdr_t), startoff, s->len);
516 
517 	return CDSIM_COMPOK;
518 }
519 
520 
521 /*
522  * cdsim_m_play
523  *	Play Audio (10) command simulation function
524  *
525  * Args:
526  *	r - Pointer to the command packet
527  *	s - Pointer to the response packet
528  *
529  * Return:
530  *	Command completion status code
531  */
532 /*ARGSUSED*/
533 STATIC byte_t
cdsim_m_play(simpkt_t * r,simpkt_t * s)534 cdsim_m_play(simpkt_t *r, simpkt_t *s)
535 {
536 	cdsim_stat.startaddr = (r->cdb[2] << 24) | (r->cdb[3] << 16) |
537 		(r->cdb[4] << 8) | r->cdb[5];
538 	cdsim_stat.endaddr = cdsim_stat.startaddr +
539 		((r->cdb[7] << 8) | r->cdb[8]);
540 
541 	if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
542 		return CDSIM_PARMERR;
543 
544 	cdsim_start_time = cdsim_now;
545 	cdsim_elapsed = 0;
546 	cdsim_pause_time = 0;
547 	cdsim_pause_elapsed = 0;
548 	cdsim_prev_pause = 0;
549 
550 	cdsim_stat.status = CDSIM_PLAYING;
551 
552 	return CDSIM_COMPOK;
553 }
554 
555 
556 /*
557  * cdsim_m_playmsf
558  *	Play Audio MSF command simulation function
559  *
560  * Args:
561  *	r - Pointer to the command packet
562  *	s - Pointer to the response packet
563  *
564  * Return:
565  *	Command completion status code
566  */
567 /*ARGSUSED*/
568 STATIC byte_t
cdsim_m_playmsf(simpkt_t * r,simpkt_t * s)569 cdsim_m_playmsf(simpkt_t *r, simpkt_t *s)
570 {
571 	util_msftoblk(
572 		r->cdb[3],
573 		r->cdb[4],
574 		r->cdb[5],
575 		&cdsim_stat.startaddr,
576 		MSF_OFFSET
577 	);
578 	util_msftoblk(
579 		r->cdb[6],
580 		r->cdb[7],
581 		r->cdb[8],
582 		&cdsim_stat.endaddr,
583 		MSF_OFFSET
584 	);
585 
586 	if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
587 		return CDSIM_PARMERR;
588 
589 	cdsim_start_time = cdsim_now;
590 	cdsim_elapsed = 0;
591 	cdsim_pause_time = 0;
592 	cdsim_pause_elapsed = 0;
593 	cdsim_prev_pause = 0;
594 
595 	cdsim_stat.status = CDSIM_PLAYING;
596 
597 	return CDSIM_COMPOK;
598 }
599 
600 
601 /*
602  * cdsim_m_playti
603  *	Play Audio Track/index command simulation function
604  *
605  * Args:
606  *	r - Pointer to the command packet
607  *	s - Pointer to the response packet
608  *
609  * Return:
610  *	Command completion status code
611  */
612 /*ARGSUSED*/
613 STATIC byte_t
cdsim_m_playti(simpkt_t * r,simpkt_t * s)614 cdsim_m_playti(simpkt_t *r, simpkt_t *s)
615 {
616 	int	strk = (int) r->cdb[4],
617 		sidx = (int) r->cdb[5],
618 		etrk = (int) r->cdb[7],
619 		eidx = (int) r->cdb[8];
620 
621 	if (sidx > (int) cdsim_stat.trk[strk - 1].nidxs) {
622 		strk++;
623 		sidx = 1;
624 	}
625 
626 	if (strk > (int) cdsim_stat.ntrks || etrk > (int) cdsim_stat.ntrks)
627 		return CDSIM_PARMERR;
628 
629 	if (eidx > (int) cdsim_stat.trk[strk - 1].nidxs)
630 		eidx = (int) cdsim_stat.trk[strk - 1].nidxs;
631 
632 	cdsim_stat.startaddr = cdsim_stat.trk[strk - 1].iaddr[sidx - 1];
633 	cdsim_stat.endaddr = cdsim_stat.trk[etrk].iaddr[eidx - 1];
634 
635 	if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
636 		return CDSIM_PARMERR;
637 
638 	cdsim_start_time = cdsim_now;
639 	cdsim_elapsed = 0;
640 	cdsim_pause_time = 0;
641 	cdsim_pause_elapsed = 0;
642 	cdsim_prev_pause = 0;
643 
644 	cdsim_stat.status = CDSIM_PLAYING;
645 
646 	return CDSIM_COMPOK;
647 }
648 
649 
650 /*
651  * cdsim_m_pause
652  *	Pause/Resume command simulation function
653  *
654  * Args:
655  *	r - Pointer to the command packet
656  *	s - Pointer to the response packet
657  *
658  * Return:
659  *	Command completion status code
660  */
661 /*ARGSUSED*/
662 STATIC byte_t
cdsim_m_pause(simpkt_t * r,simpkt_t * s)663 cdsim_m_pause(simpkt_t *r, simpkt_t *s)
664 {
665 	if (cdsim_stat.status == CDSIM_PAUSED && r->cdb[8] & 0x01) {
666 		/* Resume */
667 		cdsim_stat.status = CDSIM_PLAYING;
668 		cdsim_prev_pause += cdsim_pause_elapsed;
669 		cdsim_pause_elapsed = 0;
670 
671 		return CDSIM_COMPOK;
672 	}
673 	else {
674 		cdsim_stat.status = CDSIM_PAUSED;
675 		cdsim_pause_time = time(NULL);
676 		return CDSIM_COMPOK;
677 	}
678 }
679 
680 
681 /*
682  * cdsim_l_play
683  *	Play Audio (12) command simulation function
684  *
685  * Args:
686  *	r - Pointer to the command packet
687  *	s - Pointer to the response packet
688  *
689  * Return:
690  *	Command completion status code
691  */
692 /*ARGSUSED*/
693 STATIC byte_t
cdsim_l_play(simpkt_t * r,simpkt_t * s)694 cdsim_l_play(simpkt_t *r, simpkt_t *s)
695 {
696 	cdsim_stat.startaddr = (r->cdb[2] << 24) | (r->cdb[3] << 16) |
697 		(r->cdb[4] << 8) | r->cdb[5];
698 	cdsim_stat.endaddr = cdsim_stat.startaddr +
699 		((r->cdb[6] << 24) | (r->cdb[7] << 16) |
700 		 (r->cdb[8] << 8) | r->cdb[9]);
701 
702 	if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
703 		return CDSIM_PARMERR;
704 
705 	cdsim_start_time = cdsim_now;
706 	cdsim_elapsed = 0;
707 	cdsim_pause_time = 0;
708 	cdsim_pause_elapsed = 0;
709 	cdsim_prev_pause = 0;
710 
711 	cdsim_stat.status = CDSIM_PLAYING;
712 
713 	return CDSIM_COMPOK;
714 }
715 
716 
717 /*
718  * cdsim_l_readcd
719  *	MMC Read CD (12) command simulation function
720  *
721  * Args:
722  *	r - Pointer to the command packet
723  *	s - Pointer to the response packet
724  *
725  * Return:
726  *	Command completion status code
727  */
728 /*ARGSUSED*/
729 STATIC byte_t
cdsim_l_readcd(simpkt_t * r,simpkt_t * s)730 cdsim_l_readcd(simpkt_t *r, simpkt_t *s)
731 {
732 	int	i;
733 	byte_t	*p;
734 	char	c;
735 
736 	cdsim_stat.startaddr = (r->cdb[2] << 24) | (r->cdb[3] << 16) |
737 		(r->cdb[4] << 8) | r->cdb[5];
738 	cdsim_stat.endaddr = cdsim_stat.startaddr +
739 		((r->cdb[6] << 16) | (r->cdb[7] << 8) | r->cdb[8]);
740 
741 	if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
742 		return CDSIM_PARMERR;
743 
744 	cdsim_start_time = cdsim_now;
745 	cdsim_elapsed = 0;
746 	cdsim_pause_time = 0;
747 	cdsim_pause_elapsed = 0;
748 	cdsim_prev_pause = 0;
749 
750 	cdsim_stat.status = CDSIM_PLAYING;
751 
752 	/* Write printable ASCII character pattern into buffer */
753 	c = (byte_t) 0x20;
754 	for (i = 0, p = s->data; i < sizeof(s->data); i++, p++) {
755 		*p = c;
756 		if (++c == 0x7f)
757 			c = 0x20;
758 	}
759 
760 	return CDSIM_COMPOK;
761 }
762 
763 
764 /*
765  * cdsim_svccmd
766  *	Service a command
767  *
768  * Args:
769  *	r - Pointer to the command packet
770  *	s - Pointer to the response packet
771  *
772  * Return:
773  *	TRUE - success
774  *	FALSE - failure
775  */
776 STATIC bool_t
cdsim_svccmd(simpkt_t * r,simpkt_t * s)777 cdsim_svccmd(simpkt_t *r, simpkt_t *s)
778 {
779 	(void) memset(s, 0, CDSIM_PKTSZ);
780 
781 	DBGPRN(DBG_DEVIO)(errfp, "\ncdsim: pktid=%d cdbsz=%d len=%d dir=%d",
782 		r->pktid, r->cdbsz, r->len, r->dir);
783 
784 	DBGDUMP(DBG_DEVIO)("cdsim: SCSI CDB bytes",
785 		(byte_t *) r->cdb, (int) r->cdbsz);
786 
787 	/* Set return packet id */
788 	s->pktid = r->pktid;
789 
790 	/* Copy CDB */
791 	s->cdbsz = r->cdbsz;
792 	(void) memcpy(s->cdb, r->cdb, r->cdbsz);
793 
794 	/* Truncate if necessary */
795 	if (s->len > CDSIM_MAX_DATALEN)
796 		s->len = CDSIM_MAX_DATALEN;
797 
798 	/* Direction flag */
799 	s->dir = r->dir;
800 
801 	/* Interpret CDB and service the command */
802 	switch (r->cdb[0]) {
803 	case OP_S_TEST:
804 		/* Test unit ready */
805 		s->retcode = cdsim_s_test(r, s);
806 		break;
807 
808 	case OP_S_INQUIR:
809 		/* Inquiry */
810 		s->retcode = cdsim_s_inquir(r, s);
811 		break;
812 
813 	case OP_S_MSELECT:
814 		/* Mode select (6) */
815 		s->retcode = cdsim_s_mselect(r, s);
816 		break;
817 
818 	case OP_M_MSELECT:
819 		/* Mode select (10) */
820 		s->retcode = cdsim_m_mselect(r, s);
821 		break;
822 
823 	case OP_S_MSENSE:
824 		/* Mode sense (6) */
825 		s->retcode = cdsim_s_msense(r, s);
826 		break;
827 
828 	case OP_M_MSENSE:
829 		/* Mode sense (10) */
830 		s->retcode = cdsim_m_msense(r, s);
831 		break;
832 
833 	case OP_S_START:
834 		/* Start/stop unit */
835 		s->retcode = cdsim_s_start(r, s);
836 		break;
837 
838 	case OP_S_PREVENT:
839 		/* Prevent/allow medium removal */
840 		s->retcode = cdsim_s_prevent(r, s);
841 		break;
842 
843 	case OP_M_RDSUBQ:
844 		/* Read subchannel */
845 		s->retcode = cdsim_m_rdsubq(r, s);
846 		break;
847 
848 	case OP_M_RDTOC:
849 		/* Read TOC */
850 		s->retcode = cdsim_m_rdtoc(r, s);
851 		break;
852 
853 	case OP_M_PLAY:
854 		/* Play audio (10) */
855 		s->retcode = cdsim_m_play(r, s);
856 		break;
857 
858 	case OP_M_PLAYMSF:
859 		/* Play audio MSF */
860 		s->retcode = cdsim_m_playmsf(r, s);
861 		break;
862 
863 	case OP_M_PLAYTI:
864 		/* Play audio track/index */
865 		s->retcode = cdsim_m_playti(r, s);
866 		break;
867 
868 	case OP_M_PAUSE:
869 		/* Pause/resume */
870 		s->retcode = cdsim_m_pause(r, s);
871 		break;
872 
873 	case OP_L_PLAY:
874 		/* Play audio (12) */
875 		s->retcode = cdsim_l_play(r, s);
876 		break;
877 
878 	case OP_L_READCD:
879 		/* MMC Read CD (12) */
880 		s->retcode = cdsim_l_readcd(r, s);
881 		break;
882 
883 	default:
884 		/* Command not implemented */
885 		s->retcode = CDSIM_NOTSUPP;
886 		break;
887 	}
888 
889 	return (cdsim_sendpkt("cdsim", cdsim_rfd, s));
890 }
891 
892 
893 /*
894  * cdsim_init
895  *	Initialize the CD-simulator subsystem
896  *
897  * Args:
898  *	Nothing.
899  *
900  * Return:
901  *	Nothing.
902  */
903 STATIC void
cdsim_init(void)904 cdsim_init(void)
905 {
906 	int		i,
907 			j;
908 	toc_hdr_t	*h1 = (toc_hdr_t *)(void *) cdsim_tocdata1,
909 			*h2 = (toc_hdr_t *)(void *) cdsim_tocdata2;
910 	toc_trk_descr_t	*t1,
911 			*t2;
912 
913 	/* Initialize internal states */
914 	cdsim_stat.status = CDSIM_STOPPED;
915 	cdsim_stat.ntrks = CDSIM_NTRKS;
916 	cdsim_stat.absaddr = 0;
917 	cdsim_stat.reladdr = 0;
918 	cdsim_stat.startaddr = 0;
919 	cdsim_stat.endaddr = 0;
920 	cdsim_stat.caddylock = 0;
921 
922 	/* Addresses for each simulated track and index */
923 	for (i = 0; i < CDSIM_NTRKS; i++) {
924 		if (i == 0)
925 			cdsim_stat.trk[i].addr = 0;
926 		else
927 			cdsim_stat.trk[i].addr = (i * CDSIM_TRKLEN) - 150;
928 
929 		cdsim_stat.trk[i].nidxs = CDSIM_NIDXS;
930 
931 		for (j = 0; j < (int) cdsim_stat.trk[i].nidxs; j++) {
932 			cdsim_stat.trk[i].iaddr[j] = (j * CDSIM_IDXLEN) +
933 						     cdsim_stat.trk[i].addr;
934 		}
935 	}
936 
937 	/* Simulated lead-out track */
938 	cdsim_stat.trk[i].addr = (i * CDSIM_TRKLEN) - 150;
939 	cdsim_stat.trk[i].nidxs = 0;
940 	for (j = 0; j < CDSIM_NIDXS; j++)
941 		cdsim_stat.trk[i].iaddr[j] = cdsim_stat.trk[i].addr;
942 
943 	/* Initialize inquiry data */
944 	cdsim_inqdata.type = DEV_ROM;
945 	cdsim_inqdata.pqual = 0;
946 	cdsim_inqdata.qualif = 0;
947 	cdsim_inqdata.rmb = 1;
948 	cdsim_inqdata.ver = 2;
949 	cdsim_inqdata.len = 38;
950 	(void) strncpy((char *) cdsim_inqdata.vendor, "XMCD    ", 8);
951 	(void) strncpy((char *) cdsim_inqdata.prod, "CD-ROM SIMULATOR", 16);
952 	(void) strncpy((char *) cdsim_inqdata.revnum, CDSIM_VERS, 4);
953 
954 	/* Initialize TOC data */
955 	h1->data_len = h2->data_len = util_bswap16(
956 		((CDSIM_NTRKS + 1) * sizeof(toc_trk_descr_t)) + 2
957 	);
958 
959 	h1->first_trk = h2->first_trk = 1;
960 	h1->last_trk = h2->last_trk = CDSIM_NTRKS;
961 
962 	t1 = (toc_trk_descr_t *)(void *) (cdsim_tocdata1 + sizeof(toc_hdr_t));
963 	t2 = (toc_trk_descr_t *)(void *) (cdsim_tocdata2 + sizeof(toc_hdr_t));
964 
965 	for (i = 0; i < CDSIM_NTRKS; i++) {
966 		t1->preemph = t2->preemph = 0;
967 		t1->copyallow = t2->copyallow = 0;
968 		t1->trktype = t2->trktype = 0;
969 		t1->audioch = t2->audioch = 0;
970 		t1->adr = t2->adr = 0;
971 		t1->trkno = t2->trkno = i + 1;
972 		t1->abs_addr.logical = util_bswap32(cdsim_stat.trk[i].addr);
973 		util_blktomsf(
974 			cdsim_stat.trk[i].addr,
975 			&t2->abs_addr.msf.min,
976 			&t2->abs_addr.msf.sec,
977 			&t2->abs_addr.msf.frame,
978 			MSF_OFFSET
979 		);
980 
981 		t1 = (toc_trk_descr_t *)(void *)
982 			((byte_t *)(void *) t1 + sizeof(toc_trk_descr_t));
983 		t2 = (toc_trk_descr_t *)(void *)
984 			((byte_t *)(void *) t2 + sizeof(toc_trk_descr_t));
985 	}
986 
987 	/* Lead-out track */
988 	t1->preemph = t2->preemph = 0;
989 	t1->copyallow = t2->copyallow = 0;
990 	t1->trktype = t2->trktype = 0;
991 	t1->audioch = t2->audioch = 0;
992 	t1->adr = t2->adr = 0;
993 	t1->trkno = t2->trkno = LEAD_OUT_TRACK;
994 	t1->abs_addr.logical = util_bswap32(cdsim_stat.trk[i].addr);
995 	util_blktomsf(
996 		cdsim_stat.trk[i].addr,
997 		&t2->abs_addr.msf.min,
998 		&t2->abs_addr.msf.sec,
999 		&t2->abs_addr.msf.frame,
1000 		MSF_OFFSET
1001 	);
1002 }
1003 
1004 
1005 /*
1006  * cdsim_main
1007  *	The CD simulator main function
1008  *
1009  * Args:
1010  *	sfd - The packet send file descriptor
1011  *	rfd - The packet recv file descriptor
1012  *
1013  * Return:
1014  *	Nothing.
1015  */
1016 void
cdsim_main(int sfd,int rfd)1017 cdsim_main(int sfd, int rfd)
1018 {
1019 	int		i,
1020 			j;
1021 	simpkt_t	spkt,
1022 			rpkt;
1023 
1024 	(void) fprintf(errfp,
1025 		       "CD-ROM simulator version %s (pid=%d) starting...\n",
1026 		       CDSIM_VERS, (int) getpid());
1027 
1028 	/* Install signal handlers */
1029 	(void) util_signal(SIGINT, cdsim_sig);
1030 	(void) util_signal(SIGTERM, cdsim_sig);
1031 	(void) util_signal(SIGHUP, cdsim_sig);
1032 
1033 	cdsim_sfd = sfd;
1034 	cdsim_rfd = rfd;
1035 
1036 	/* Initialize CD-ROM simulator */
1037 	cdsim_init();
1038 
1039 	/* Main simulation service loop */
1040 	for (;;) {
1041 		/* Get SCSI request */
1042 		if (!cdsim_getpkt("cdsim", cdsim_sfd, &rpkt))
1043 			continue;
1044 
1045 		cdsim_now = time(NULL);
1046 
1047 		/* Update status */
1048 		switch (cdsim_stat.status) {
1049 		case CDSIM_PLAYING:
1050 			cdsim_elapsed = cdsim_now - cdsim_start_time -
1051 				cdsim_pause_elapsed - cdsim_prev_pause;
1052 
1053 			cdsim_stat.absaddr = cdsim_elapsed * FRAME_PER_SEC +
1054 				cdsim_stat.startaddr;
1055 
1056 			cdsim_stat.trkno = 0;
1057 			for (i = 0; i < (int) cdsim_stat.ntrks; i++) {
1058 				if (cdsim_stat.trk[i].addr > cdsim_stat.absaddr)
1059 					break;
1060 				cdsim_stat.trkno++;
1061 			}
1062 
1063 			cdsim_stat.idxno = 0;
1064 			for (j = 0; j < (int) cdsim_stat.trk[i-1].nidxs; j++) {
1065 				if (cdsim_stat.trk[i-1].iaddr[j] >
1066 				    cdsim_stat.absaddr)
1067 					break;
1068 				cdsim_stat.idxno++;
1069 			}
1070 
1071 			cdsim_stat.reladdr = cdsim_stat.absaddr -
1072 				cdsim_stat.trk[i-1].addr;
1073 
1074 			if (cdsim_stat.absaddr > cdsim_stat.endaddr) {
1075 				cdsim_stat.status = CDSIM_STOPPED;
1076 				cdsim_elapsed = 0;
1077 				cdsim_start_time = 0;
1078 				cdsim_pause_time = 0;
1079 				cdsim_prev_pause = 0;
1080 				cdsim_pause_elapsed = 0;
1081 			}
1082 			break;
1083 
1084 		case CDSIM_PAUSED:
1085 			cdsim_pause_elapsed = cdsim_now - cdsim_pause_time;
1086 			break;
1087 		}
1088 
1089 		/* Process SCSI request */
1090 		(void) cdsim_svccmd(&rpkt, &spkt);
1091 	}
1092 }
1093 
1094 #endif	/* DEMO_ONLY */
1095 
1096