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>
