Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 20 Jun 1997 12:33:07 +1000 (EST)
From:      Mike McGaughey <mmcg@mjolnir.cs.monash.edu.au>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   kern/3909: Patches - new worm drivers for CDrom burners: Philips CDD522 and T.Yuden EW-50
Message-ID:  <199706200233.MAA06498@mjolnir.cs.monash.edu.au>
Resent-Message-ID: <199706200240.TAA04889@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         3909
>Category:       kern
>Synopsis:       A patch supporting some new worm drivers
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jun 19 19:40:01 PDT 1997
>Last-Modified:
>Originator:     Mike McGaughey
>Organization:
Monash University
>Release:        FreeBSD 2.2.2-RELEASE i386
>Environment:

Tested on:

2.2.2-RELEASE
T.YUDEN EW-50 CDrom burner (on slow scsi board)

>Description:

Here is a modification to the 2.2.2-RELEASE worm.c which implements
support for the Philips CDD 522 and T.Yuden EW-50 (very cheap in
Australia).  I suspect that the CDD522 is the `philips' in
`Philips/IMS/Kodak' drives, so this may work for many other CD burners.

NOTE: I have made a slight change to the handling of other CDrom
cutters.  In particular, the spindown/medium unload commands are
now sent *after* the cache flush when finalizing a track.  I suspect
this is the way it should have been in the first place, but am
interested in hearing reports on whether or not it made a difference.

I have burned a bunch of data CDs using this; I haven't tried
audios, multi-track, or multi-session disks (the multisession
support looks broken anyway, due to a block addressing issue).

>How-To-Repeat:

Apply the patch below.

>Fix:

Context diffs for /usr/src/sys/scsi/worm.c (the only
file that I modified).

*** worm.c.orig	Thu Jun 12 08:19:47 1997
--- worm.c	Sat Jun 14 20:54:00 1997
***************
*** 142,147 ****
--- 142,152 ----
  static errval hp4020i_finalize_track(struct scsi_link *);
  static errval hp4020i_finalize_disk(struct scsi_link *, int toc_type, int onp);
  
+ static errval cdd522_prepare_disk(struct scsi_link *, int dummy, int speed);
+ static errval cdd522_prepare_track(struct scsi_link *, int audio, int preemp);
+ static errval cdd522_finalize_track(struct scsi_link *);
+ static errval cdd522_finalize_disk(struct scsi_link *, int toc_type, int onp);
+ 
  static worm_devsw_installed = 0;
  
  static	d_open_t	wormopen;
***************
*** 205,210 ****
--- 210,226 ----
  		hp4020i_prepare_disk, hp4020i_prepare_track,
  		hp4020i_finalize_track, hp4020i_finalize_disk
  	},
+ 	{
+ 		"PHILIPS", "CDD522",
+ 		cdd522_prepare_disk, cdd522_prepare_track,
+ 		cdd522_finalize_track, cdd522_finalize_disk
+ 	},
+ 	{
+ 	/* (aic0:4:0): "T.YUDEN CD-WO EW-50 2.16" type 4 removable SCSI 2 */
+ 		"T.YUDEN", "EW-50",
+ 		cdd522_prepare_disk, cdd522_prepare_track,
+ 		cdd522_finalize_track, cdd522_finalize_disk
+ 	},
  	{0}
  };
  
***************
*** 563,577 ****
  	error = 0;
  
  	if ((worm->worm_flags & WORMFL_IOCTL_ONLY) == 0) {
- 		scsi_stop_unit(sc_link, 0, SCSI_SILENT);
- 		scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
  
! 		sc_link->flags &= ~SDEV_OPEN;
  
  		if ((flags & FWRITE) != 0) {
  			worm->worm_flags &= ~WORMFL_TRACK_PREPED;
  			error = (worm->quirks->finalize_track)(sc_link);
  		}
  	}
  	sc_link->flags &= ~SDEV_OPEN;
  	worm->worm_flags &= ~WORMFL_IOCTL_ONLY;
--- 579,603 ----
  	error = 0;
  
  	if ((worm->worm_flags & WORMFL_IOCTL_ONLY) == 0) {
  
! 		/*
! 		 * XXX: My T.YUDEN dies if we issue the stop_unit and allow_eject
! 		 * before flushing the cache, so I have called the finalizer before
! 		 * stopping the unit.  I suspect this is a far more reasonable
! 		 * ordering (but do not know if this breaks anything else) - MMCG
! 		 *
! 		 * It is concievable that another driver could break if its
! 		 * finalize_track routine relied on SDEV_OPEN having been reset
! 		 * by the time it is called (subtly different error semantics?)
! 		 */
  
  		if ((flags & FWRITE) != 0) {
  			worm->worm_flags &= ~WORMFL_TRACK_PREPED;
  			error = (worm->quirks->finalize_track)(sc_link);
  		}
+ 
+ 		scsi_stop_unit(sc_link, 0, SCSI_SILENT);
+ 		scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
  	}
  	sc_link->flags &= ~SDEV_OPEN;
  	worm->worm_flags &= ~WORMFL_IOCTL_ONLY;
***************
*** 1385,1388 ****
--- 1411,1698 ----
  
  /*
   * End HP C4324/C4325 (4020i) section.
+  */
+ 
+ /*
+  * Philips CDD522/Taiyo Yuden EW-50 section.
+  *
+  * Ack: I am very grateful to Philips, who supplied me with a SCSI manual
+  * for their unit.  Taiyo Yuden considers their manual proprietry.
+  *
+  * This section was written using the CDD522 SCSI manual, but has only
+  * been tested on my T.YUDEN EW-50 (it's a long story).
+  */
+ 
+ struct cdd_522_pages
+ {
+ 	u_char	page_code;
+ #define CDD522_PAGE_CODE_20 0x20
+ #define CDD522_PAGE_CODE_21 0x21
+ #define CDD522_PAGE_CODE_22 0x22
+ #define CDD522_PAGE_CODE_23 0x23
+ #define CDD522_PAGE_CODE_24 0x24
+ #define CDD522_PAGE_CODE_25 0x25
+ 	u_char	param_len;
+ 	union
+ 	{
+ 		/* page 0x20 omitted by now */
+ 		struct
+ 		{
+ 			u_char	reserved1;
+ 			u_char	mode;
+ #define CDD522_RAW_MODE		0x10	/* raw mode enabled */
+ #define CDD522_MIXED_MODE	0x08	/* mixed mode data enabled */
+ #define CDD522_AUDIO_MODE	0x04	/* audio mode data enabled */
+ #define CDD522_MODE_1		0x01	/* mode 1 blocks are enabled */
+ #define CDD522_MODE_2		0x02	/* mode 2 blocks are enabled */
+ 			u_char	track_number;
+ 			u_char	isrc_i1; /* country code, ASCII */
+ 			u_char	isrc_i2;
+ 			u_char	isrc_i3; /* owner code, ASCII */
+ 			u_char	isrc_i4;
+ 			u_char	isrc_i5;
+ 			u_char	isrc_i6_7; /* country code, BCD */
+ 			u_char	isrc_i8_9; /* serial number, BCD */
+ 			u_char	isrc_i10_11;
+ 			u_char	isrc_i12_0;
+ 			u_char	reserved2[2];
+ 		}
+ 		page_0x21;
+ 		/* mode page 0x22 omitted by now */
+ 		struct
+ 		{
+ 			u_char	speed_select;
+ #define CDD522_SPEED_AUDIO	0x01
+ #define CDD522_SPEED_DOUBLE	0x02
+ 			u_char	dummy_write;
+ #define CDD522_DUMMY_WRITE	0x01
+ 			u_char	reserved[4];
+ 		}
+ 		page_0x23;
+ 		/* pages 0x24 and 0x25 omitted by now */
+ 	}
+ 	pages;
+ };
+ 
+ 
+ static errval
+ cdd522_prepare_disk(struct scsi_link *sc_link, int dummy, int speed)
+ {
+ 	struct scsi_mode_select scsi_cmd;
+ 	struct {
+ 		struct scsi_mode_header header;
+ 		struct cdd_522_pages page;
+ 	} dat;
+ 	u_int32_t pagelen, dat_len;
+ 
+ 	pagelen = sizeof(dat.page.pages.page_0x23) + PAGE_HEADERLEN;
+ 	dat_len = sizeof(struct scsi_mode_header) + pagelen;
+ 
+ 	SC_DEBUG(sc_link, SDEV_DB2, ("cdd522_prepare_disk"));
+ 
+ 	if (speed != CDD522_SPEED_AUDIO && speed != CDD522_SPEED_DOUBLE)
+ 		return EINVAL;
+ 
+ 	/*
+ 	 * Set up a mode page 0x23
+ 	 */
+ 	bzero(&dat, sizeof(dat));
+ 	bzero(&scsi_cmd, sizeof(scsi_cmd));
+ 	scsi_cmd.op_code = MODE_SELECT;
+ 	scsi_cmd.byte2 |= SMS_PF;
+ 	scsi_cmd.length = dat_len;
+ 	/* dat.header.dev_spec = host application code; (see spec) */
+ 	dat.page.page_code = CDD522_PAGE_CODE_23;
+ 	dat.page.param_len = sizeof(dat.page.pages.page_0x23);
+ 	dat.page.pages.page_0x23.speed_select = speed;
+ 	dat.page.pages.page_0x23.dummy_write = dummy? CDD522_DUMMY_WRITE: 0;
+ 	/*
+ 	 * Fire it off.
+ 	 */
+ 	return scsi_scsi_cmd(sc_link,
+ 			     (struct scsi_generic *) &scsi_cmd,
+ 			     sizeof(scsi_cmd),
+ 			     (u_char *) &dat,
+ 			     dat_len,
+ 			     /*WORM_RETRIES*/ 4,
+ 			     5000,
+ 			     NULL,
+ 			     SCSI_DATA_OUT);
+ }
+ 
+ 
+ static errval
+ cdd522_prepare_track(struct scsi_link *sc_link, int audio, int preemp)
+ {
+ 	struct scsi_mode_select scsi_cmd;
+ 	struct {
+ 		struct scsi_mode_header header;
+ 		struct blk_desc blk_desc;
+ 		struct cdd_522_pages page;
+ 	} dat;
+ 	u_int32_t pagelen, dat_len, blk_len;
+ 	errval cmd_1_val;
+ 
+ 	pagelen = sizeof(dat.page.pages.page_0x21) + PAGE_HEADERLEN;
+ 	dat_len = sizeof(struct scsi_mode_header)
+ 		+ sizeof(struct blk_desc)
+ 		+ pagelen;
+ 
+ 	SC_DEBUG(sc_link, SDEV_DB2, ("cdd522_prepare_track"));
+ 
+ 	if (!audio && preemp)
+ 		return EINVAL;
+ 
+ 	/*
+ 	 * By now, make a simple decision about the block length to be
+ 	 * used.  It's just only Red Book (Audio) == 2352 bytes, or
+ 	 * Yellow Book (CD-ROM) Mode 1 == 2048 bytes.
+ 	 */
+ 	blk_len = audio? 2352: 2048;
+ 
+ 	/*
+ 	 * It turns out that the Yuden needs a WRITE_TRACK command.
+ 	 * It is simplest to send the original page 21 mode select
+ 	 * command, then to follow it with an unadorned WRITE_TRACK.
+ 	 */
+ 	bzero(&dat, sizeof(dat));
+ 	bzero(&scsi_cmd, sizeof(scsi_cmd));
+ 	scsi_cmd.op_code = MODE_SELECT;
+ 	scsi_cmd.byte2 |= SMS_PF;
+ 	scsi_cmd.length = dat_len;
+ 	dat.header.blk_desc_len = sizeof(struct blk_desc);
+ 	/* dat.header.dev_spec = host application code; (see spec) */
+ 	scsi_uto3b(blk_len, dat.blk_desc.blklen);
+ 	dat.page.page_code = CDD522_PAGE_CODE_21;
+ 	dat.page.param_len = sizeof(dat.page.pages.page_0x21);
+ 	dat.page.pages.page_0x21.mode =
+ 		(audio? CDD522_AUDIO_MODE: CDD522_MODE_1) +
+ 		(preemp? CDD522_MODE_1: 0);
+ 	/* dat.page.pages.page_0x21.track_number = 0; (current track) */
+ 	
+ 	/*
+ 	 * Send the mode select.
+ 	 */
+ 	cmd_1_val = scsi_scsi_cmd(sc_link,
+ 			     (struct scsi_generic *) &scsi_cmd,
+ 			     sizeof(scsi_cmd),
+ 			     (u_char *) &dat,
+ 			     dat_len,
+ 			     /*WORM_RETRIES*/ 4,
+ 			     5000,
+ 			     NULL,
+ 			     SCSI_DATA_OUT);
+ 
+ 	/*
+ 	 * Abort now if error.
+ 	 */
+ 
+ 	if (cmd_1_val)
+ 	{
+ 		return cmd_1_val;
+ 	}
+ 
+ 	/*
+ 	 * Next: an explicit WRITE_TRACK command - CDD522 Spec: `The WRITE
+ 	 * command is available only when the limited command set (after
+ 	 * a WRITE_TRACK command) is available'.  I.e. it's insufficient
+ 	 * for us to rely on the mode select command.  It appears that
+ 	 * WRITE_TRACK triggers my Yuden to start doing a laser power
+ 	 * calibration - which can take 10-20 secs - before it will accept
+ 	 * any data.  Hence the 60 second timeout.
+ 	 *
+ 	 * NB: This 60s timeout probably obviates the need for the 100 second
+ 	 * timeout in the strategy routine (but only when using this burner) -
+ 	 * that timeout could instead be set to a small multiple of the expected
+ 	 * time to transfer the given data at the given recording speed (or a
+ 	 * buffer full of data - 2M on my CD cutter - if it is larger).
+ 	 * Not that it matters...
+ 	 */
+ 	{
+ 	struct scsi_write_track cmd2;
+ 	
+ 	SC_DEBUG(sc_link, SDEV_DB2, ("cdd522_prepare_track (WRITE_TRACK)"));
+ 
+ 	bzero(&cmd2, sizeof(cmd2));
+ 	cmd2.op_code = WRITE_TRACK;
+ 	cmd2.mode =
+ 		(audio? WORM_TRACK_MODE_AUDIO: WORM_TRACK_MODE_MODE1) +
+ 		(preemp? WORM_TRACK_MODE_MODE1: 0);
+ 	return scsi_scsi_cmd(sc_link,
+ 			     (struct scsi_generic *) &cmd2,
+ 			     sizeof(cmd2),
+ 			     0,	/* no data transfer */
+ 			     0, /* no retries (it'd be bad form) */
+ 			     1,
+ 			     60000,
+ 			     NULL,
+ 			     0);
+ 	}
+ }
+ 
+ 
+ static errval
+ cdd522_finalize_track(struct scsi_link *sc_link)
+ {
+ 	struct scsi_synchronize_cache cmd;
+ 	
+ 	SC_DEBUG(sc_link, SDEV_DB2, ("cdd522_finalize_track"));
+ 
+ 	/*
+ 	 * Only a "synchronize cache" is needed.
+ 	 * NB: the Yuden gets confused if the
+ 	 * spindown (stop unit) is issued before the cache flush.
+ 	 */
+ 	bzero(&cmd, sizeof(cmd));
+ 	cmd.op_code = SYNCHRONIZE_CACHE;
+ 	return scsi_scsi_cmd(sc_link,
+ 			     (struct scsi_generic *) &cmd,
+ 			     sizeof(cmd),
+ 			     0,	/* no data transfer */
+ 			     0,
+ 			     1,
+ 			     120000, /* XXX: Upped out of caution */
+ 			     NULL,
+ 			     0);
+ }
+ 
+ 
+ static errval
+ cdd522_finalize_disk(struct scsi_link *sc_link, int toc_type, int onp)
+ {
+ 	struct scsi_fixation cmd;
+ 
+ 	SC_DEBUG(sc_link, SDEV_DB2, ("cdd522_finalize_disk"));
+ 
+ 	if (toc_type < 0 || toc_type > WORM_TOC_TYPE_CDI)
+ 		return EINVAL;
+ 
+ 	/*
+ 	 * Fixate this session.  Mark the next one as opened if onp
+ 	 * is true.  Otherwise, the disk will be finalized once and
+ 	 * for all.  ONP stands for "open next program area".
+ 	 *
+ 	 * XXX: If we're planning on multiple sessions, we need to fix the
+ 	 * block writes to go to the correct logical address on the CD (it
+ 	 * only starts at 0 for the first track).  IE, start off with
+ 	 * a FIRST_WRITEABLE_ADDR query (or force the writes to specify
+ 	 * addresses of 0).
+ 	 */
+ 	
+ 	bzero(&cmd, sizeof(cmd));
+ 	cmd.op_code = FIXATION;
+ 	cmd.action = (onp? WORM_FIXATION_ONP: 0) + toc_type;
+ 	return scsi_scsi_cmd(sc_link,
+ 			     (struct scsi_generic *) &cmd,
+ 			     sizeof(cmd),
+ 			     0,	/* no data transfer */
+ 			     0,
+ 			     1,
+ 			     20*60*1000, /* takes a huge amount of time */
+ 			     NULL,
+ 			     0);
+ }
+ 
+ /*
+  * End Philips CDD522/T.Yuden EW-50 section.
   */
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199706200233.MAA06498>