From owner-freebsd-bugs Thu Jun 19 19:40:06 1997 Return-Path: Received: (from root@localhost) by hub.freebsd.org (8.8.5/8.8.5) id TAA04920 for bugs-outgoing; Thu, 19 Jun 1997 19:40:06 -0700 (PDT) Received: (from gnats@localhost) by hub.freebsd.org (8.8.5/8.8.5) id TAA04889; Thu, 19 Jun 1997 19:40:02 -0700 (PDT) Resent-Date: Thu, 19 Jun 1997 19:40:02 -0700 (PDT) Resent-Message-Id: <199706200240.TAA04889@hub.freebsd.org> Resent-From: gnats (GNATS Management) Resent-To: freebsd-bugs Resent-Reply-To: FreeBSD-gnats@FreeBSD.ORG, mmcg@mjolnir.cs.monash.edu.au Received: from mjolnir.cs.monash.edu.au (heraclitus.cs.monash.edu.au [130.194.64.241]) by hub.freebsd.org (8.8.5/8.8.5) with ESMTP id TAA04522 for ; Thu, 19 Jun 1997 19:33:59 -0700 (PDT) Received: (from mmcg@localhost) by mjolnir.cs.monash.edu.au (8.8.5/8.8.5) id MAA06498; Fri, 20 Jun 1997 12:33:07 +1000 (EST) Message-Id: <199706200233.MAA06498@mjolnir.cs.monash.edu.au> Date: Fri, 20 Jun 1997 12:33:07 +1000 (EST) From: Mike McGaughey Reply-To: mmcg@mjolnir.cs.monash.edu.au To: FreeBSD-gnats-submit@FreeBSD.ORG X-Send-Pr-Version: 3.2 Subject: kern/3909: Patches - new worm drivers for CDrom burners: Philips CDD522 and T.Yuden EW-50 Sender: owner-bugs@FreeBSD.ORG X-Loop: FreeBSD.org Precedence: bulk >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: