From owner-freebsd-bugs Wed Jul 10 13:50:54 2002 Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id EEC7037B401 for ; Wed, 10 Jul 2002 13:50:07 -0700 (PDT) Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 4075A43E31 for ; Wed, 10 Jul 2002 13:50:07 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.12.4/8.12.4) with ESMTP id g6AKo7JU041017 for ; Wed, 10 Jul 2002 13:50:07 -0700 (PDT) (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.4/8.12.4/Submit) id g6AKo7Tv041016; Wed, 10 Jul 2002 13:50:07 -0700 (PDT) Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id B4C7937B400 for ; Wed, 10 Jul 2002 13:48:58 -0700 (PDT) Received: from talri.sapros.com (rularan.sapros.com [204.182.55.17]) by mx1.FreeBSD.org (Postfix) with ESMTP id 247EB43E09 for ; Wed, 10 Jul 2002 13:48:58 -0700 (PDT) (envelope-from peterh@talri.sapros.com) Received: from talri.sapros.com (localhost [127.0.0.1]) by talri.sapros.com (8.12.3/8.12.3) with ESMTP id g6AKms7W000327 for ; Wed, 10 Jul 2002 13:48:54 -0700 (PDT) (envelope-from peterh@talri.sapros.com) Message-Id: <200207102048.g6AKms7W000327@talri.sapros.com> Date: Wed, 10 Jul 2002 13:48:54 -0700 From: Peter Haight Reply-To: Peter Haight To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Subject: misc/40430: Writing to DVD+RW using burncd does not work. Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org >Number: 40430 >Category: misc >Synopsis: Writing to DVD+RW using burncd does not work. >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Wed Jul 10 13:50:03 PDT 2002 >Closed-Date: >Last-Modified: >Originator: Peter Haight >Release: FreeBSD 4.6-STABLE i386 >Organization: >Environment: System: FreeBSD talri.sapros.com 4.6-STABLE FreeBSD 4.6-STABLE #15: Sun Jun 30 18:34:25 PDT 2002 peterh@talri.sapros.com:/usr/src/sys/compile/TALRI i386 Sony DVD+RW DRU-120A IDE >Description: When you try to use burncd to write to a DVD+RW, you get an Input/Output error. I've come up with a patch that lets you write to a DVD+RW using burncd. >How-To-Repeat: burncd -d /dev/acd0c data foo.iso >Fix: I've provided a patch to the kernel and burncd that lets you write to DVD+RW drives. There are two reasons why it wasn't working before this patch. The first is that DVD+RW media needs to be formatted before it is used. You can accomplish this using the ATAPI_FORMAT_UNIT command. I added an ioctl command that will let you read the format capacities (DVDREADFORMATCAPS) and then use one of those format capacity descriptiors to format the DVD+RW (DVDFORMATUNIT). I added code to burncd to execute these commands. (You can use 'burncd format' to make it do this). The other problem was that burncd expects tracks like on a CD-R and DVD+RW doesn't really have tracks. I added a new write command to burncd to take this lack of tracks into account. You can use 'burncd dvdwrite ' to use this method of writing. Here's the patch. It is against 4.6-STABLE that I cvsupped from 6/30/02. --- sys/dev/ata/atapi-all.h.orig Sun Jun 30 20:07:17 2002 +++ sys/dev/ata/atapi-all.h Sat Jun 29 15:37:22 2002 @@ -66,6 +66,7 @@ #define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */ #define ATAPI_REZERO 0x01 /* rewind */ #define ATAPI_REQUEST_SENSE 0x03 /* get sense data */ +#define ATAPI_FORMAT_UNIT 0x04 /* format unit */ #define ATAPI_READ 0x08 /* read data */ #define ATAPI_WRITE 0x0a /* write data */ #define ATAPI_WEOF 0x10 /* write filemark */ @@ -81,6 +82,7 @@ #define SS_RETENSION 0x02 #define SS_EJECT 0x04 #define ATAPI_PREVENT_ALLOW 0x1e /* media removal */ +#define ATAPI_READ_FORMAT_CAPACITIES 0x23 /* get format capacities */ #define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */ #define ATAPI_READ_BIG 0x28 /* read data */ #define ATAPI_WRITE_BIG 0x2a /* write data */ --- sys/dev/ata/atapi-cd.c.orig Sat Jun 29 13:11:37 2002 +++ sys/dev/ata/atapi-cd.c Sun Jun 30 18:34:06 2002 @@ -100,6 +100,10 @@ static int acd_mode_select(struct acd_softc *, caddr_t, int); static int acd_set_speed(struct acd_softc *, int, int); static void acd_get_cap(struct acd_softc *); +static int acd_read_format_caps(struct acd_softc *, struct dvd_format_cap_trans *); +static int acd_format_unit(struct acd_softc *, struct dvd_format_params *); +static int acd_get_format_progress(struct acd_softc *, int *); + /* internal vars */ static u_int32_t acd_lun_map = 0; @@ -1046,6 +1050,18 @@ ((struct partinfo *)addr)->part = &cdp->disklabel.d_partitions[0]; break; + case DVDIOREADFORMATCAPS: + error = acd_read_format_caps(cdp, (struct dvd_format_cap_trans *)addr); + break; + + case DVDIOFORMATUNIT: + error = acd_format_unit(cdp, (struct dvd_format_params *)addr); + break; + + case DVDIOFORMATPROGRESS: + error = acd_get_format_progress(cdp, (int *) addr); + break; + default: error = ENOTTY; } @@ -1991,4 +2007,69 @@ cdp->cap.cur_write_speed = max(ntohs(cdp->cap.cur_write_speed), 177); cdp->cap.max_vol_levels = ntohs(cdp->cap.max_vol_levels); cdp->cap.buf_size = ntohs(cdp->cap.buf_size); +} + +static int +acd_read_format_caps(struct acd_softc *cdp, struct dvd_format_cap_trans* trans) +{ + int error; + int8_t *kernel_buf; + int8_t ccb[16] = { ATAPI_READ_FORMAT_CAPACITIES, 0, 0, 0, 0, 0, 0, + (trans->buf_len >> 8) & 0xff, trans->buf_len & 0xff, + 0, 0, 0, 0, 0, 0, 0 }; + + kernel_buf = malloc(trans->buf_len, M_ACD, M_NOWAIT); + if (kernel_buf == NULL) { + return ENOMEM; + } + +#define DVD_READ_FORMAT_CAPS_TIMEOUT 30 + error = atapi_queue_cmd(cdp->device, ccb, kernel_buf, trans->buf_len, + ATPR_F_READ, DVD_READ_FORMAT_CAPS_TIMEOUT, + NULL, NULL); + if (!error) { + error = copyout(kernel_buf, trans->buf, trans->buf_len); + } + + free(kernel_buf, M_ACD); + + return error; +} + +static int +acd_format_unit(struct acd_softc *cdp, struct dvd_format_params* params) +{ + int error; + int8_t ccb[16] = { ATAPI_FORMAT_UNIT, 0x11, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 }; + +#define DVD_FORMAT_UNIT_TIMEOUT 30 + error = atapi_queue_cmd(cdp->device, ccb, (u_int8_t *)params, + sizeof(struct dvd_format_params), 0, + DVD_FORMAT_UNIT_TIMEOUT, NULL, NULL); + + return error; +} + +static int +acd_get_format_progress(struct acd_softc *cdp, int *finished) +{ + int error; + int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0, + sizeof(struct atapi_reqsense), 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; + struct atapi_reqsense response; + + error = atapi_queue_cmd(cdp->device, ccb, (u_int8_t *) &response, + sizeof(struct atapi_reqsense), ATPR_F_READ, + 30, NULL, NULL); + if (error) + { + return error; + } + if (response.sksv) + *finished = ((response.sk_specific2 | (response.sk_specific1 << 8)) * 100) / 65535; + else + *finished = 0; + return 0; } --- sys/sys/dvdio.h.orig Sun Jun 30 20:10:24 2002 +++ sys/sys/dvdio.h Sun Jun 30 18:24:03 2002 @@ -107,4 +107,46 @@ #define DVDIOCSENDKEY _IOWR('c', 201, struct dvd_authinfo) #define DVDIOCREADSTRUCTURE _IOWR('c', 202, struct dvd_struct) +struct dvd_format_cap { + u_int32_t num_blocks; + u_int8_t reserved:2; + u_int8_t format_type:6; + u_int8_t type_param[3]; +}; + +struct dvd_format_cap_list_header { + u_int8_t reserved[3]; + u_int8_t cap_list_len; +}; + +struct dvd_cur_cap_desc { + u_int32_t num_blocks; + u_int8_t descriptor_type:2; + u_int8_t reserved:6; + u_int8_t block_len[3]; +}; + +struct dvd_format_cap_trans { + u_int16_t buf_len; + u_int8_t *buf; +}; + +struct dvd_format_params { + u_int8_t reserved; + u_int8_t vs:1; + u_int8_t immed:1; + u_int8_t try_out:1; + u_int8_t ip:1; + u_int8_t stpf:1; + u_int8_t dcrt:1; + u_int8_t dpry:1; + u_int8_t fov:1; + u_int16_t desc_len; + struct dvd_format_cap desc; +}; + +#define DVDIOREADFORMATCAPS _IOWR('c', 203, struct dvd_format_cap_trans) +#define DVDIOFORMATUNIT _IOW('c', 204, struct dvd_format_params) +#define DVDIOFORMATPROGRESS _IOR('c', 205, struct dvd_format_params) + #endif _SYS_DVDIO_H_ --- usr.sbin/burncd/burncd.c.orig Sat Jun 29 16:09:23 2002 +++ usr.sbin/burncd/burncd.c Sun Jun 30 19:39:48 2002 @@ -40,6 +40,7 @@ #include #include #include +#include #include #define BLOCKS 16 @@ -58,7 +59,8 @@ void add_track(char *, int, int, int); void do_DAO(int, int); -void do_TAO(int, int); +void do_TAO(int, int, int); +void do_format(int, int); int write_file(struct track_info *); int roundup_blocks(struct track_info *); void cue_ent(struct cdr_cue_entry *, int, int, int, int, int, int, int); @@ -70,11 +72,11 @@ { int ch, arg, addr; int dao = 0, eject = 0, fixate = 0, list = 0, multi = 0, preemp = 0; - int nogap = 0, speed = 4, test_write = 0; - int block_size = 0, block_type = 0, cdopen = 0; + int nogap = 0, speed = 4, test_write = 0, format = 0, force_format = 0; + int block_size = 0, block_type = 0, cdopen = 0, dvdprw=0; const char *dev = "/dev/acd0c"; - while ((ch = getopt(argc, argv, "def:lmnpqs:tv")) != -1) { + while ((ch = getopt(argc, argv, "def:Flmnpqs:tv")) != -1) { switch (ch) { case 'd': dao = 1; @@ -87,6 +89,10 @@ case 'f': dev = optarg; break; + + case 'F': + force_format = 1; + break; case 'l': list = 1; @@ -148,6 +154,10 @@ fixate = 1; break; } + if (!strcasecmp(argv[arg], "format")) { + format = 1; + break; + } if (!strcasecmp(argv[arg], "msinfo")) { struct ioc_read_toc_single_entry entry; struct ioc_toc_header header; @@ -226,6 +236,13 @@ nogap = 1; continue; } + if (!strcasecmp(argv[arg], "dvdprw")) { + block_type = CDR_DB_ROM_MODE1; + block_size = 2048; + dvdprw = 1; + continue; + } + if (!block_size) err(EX_NOINPUT, "no data format selected"); if (list) { @@ -251,6 +268,8 @@ add_track(argv[arg], block_size, block_type, nogap); } if (notracks) { + if (dvdprw && notracks > 1) + err(EX_USAGE, "DVD+RW drives can only write one track"); if (ioctl(fd, CDIOCSTART, 0) < 0) err(EX_IOERR, "ioctl(CDIOCSTART)"); if (!cdopen) { @@ -261,7 +280,7 @@ if (dao) do_DAO(test_write, multi); else - do_TAO(test_write, preemp); + do_TAO(test_write, preemp, dvdprw); } if (fixate && !dao) { if (!quiet) @@ -270,6 +289,10 @@ err(EX_IOERR, "ioctl(CDRIOCFIXATE)"); } + if (format) { + do_format(fd, force_format); + } + if (ioctl(fd, CDRIOCSETBLOCKSIZE, &saved_block_size) < 0) { err_set_exit(NULL); err(EX_IOERR, "ioctl(CDRIOCSETBLOCKSIZE)"); @@ -435,7 +458,7 @@ } void -do_TAO(int test_write, int preemp) +do_TAO(int test_write, int preemp, int dvdprw) { struct cdr_track track; int i; @@ -447,8 +470,13 @@ if (ioctl(fd, CDRIOCINITTRACK, &track) < 0) err(EX_IOERR, "ioctl(CDRIOCINITTRACK)"); - if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, &tracks[i].addr) < 0) - err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)"); + if (dvdprw) + tracks[i].addr = 0; + else + if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, + &tracks[i].addr) < 0) + err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)"); + if (!quiet) fprintf(stderr, "next writeable LBA %d\n", tracks[i].addr); @@ -457,6 +485,86 @@ if (ioctl(fd, CDRIOCFLUSH) < 0) err(EX_IOERR, "ioctl(CDRIOCFLUSH)"); } +} + +#define BURNCD_MAX_FORMAT_CAP_LEN 1024 +void +do_format(int fd, int force_format) +{ + int result; + int i; + int percent; + int started; + int num_caps; + int cap_to_use = -1; + u_int8_t *buf_pos; + struct dvd_format_cap_list_header *cap_list_header; + struct dvd_cur_cap_desc *cap_desc; + struct dvd_format_cap *format_cap; + struct dvd_format_cap_trans trans; + struct dvd_format_params format_params; + u_int8_t fmt_cap_buf[BURNCD_MAX_FORMAT_CAP_LEN]; + + trans.buf_len = BURNCD_MAX_FORMAT_CAP_LEN; + trans.buf = fmt_cap_buf; + if (ioctl(fd, DVDIOREADFORMATCAPS, &trans) == -1) + err(EX_IOERR, "ioctl(DVDIOREADFORMATCAPS)"); + + buf_pos = trans.buf; + cap_list_header = (struct dvd_format_cap_list_header *) buf_pos; + if (cap_list_header->cap_list_len + + sizeof(struct dvd_format_cap_list_header) + + sizeof(struct dvd_cur_cap_desc) > BURNCD_MAX_FORMAT_CAP_LEN) + err(EX_SOFTWARE, "did not allocate enough memory for cap list"); + + buf_pos += sizeof(struct dvd_format_cap_list_header); + cap_desc = (struct dvd_cur_cap_desc *) buf_pos; + if (verbose) { + fprintf(stderr, "format_cap_header: cap_list_len=%d\n", + cap_list_header->cap_list_len); + fprintf(stderr, "cur_cap_desc: num_blocks=%u, descriptor_type=0x%x, block_len=%u\n", ntohl(cap_desc->num_blocks), cap_desc->descriptor_type, cap_desc->block_len[0] << 16 | cap_desc->block_len[1] << 8 | cap_desc->block_len[2]); + } + buf_pos += sizeof(struct dvd_cur_cap_desc); + + num_caps = cap_list_header->cap_list_len/sizeof(struct dvd_format_cap); + for (i = 0; i < num_caps; ++i) { + format_cap = (struct dvd_format_cap *) buf_pos; + if (verbose) + fprintf(stderr, "format_cap: num_blocks=%u, format_type=0x%x, type_param=%u\n", ntohl(format_cap->num_blocks), format_cap->format_type, format_cap->type_param[0] << 16 | format_cap->type_param[1] << 8 | format_cap->type_param[2]); + if (format_cap->format_type == 0x26) + cap_to_use = i; + buf_pos += sizeof(struct dvd_format_cap); + } + if (cap_to_use == -1) + err(EX_IOERR, "could not finde a format capacity with format type = 0x26."); + + if (!force_format && cap_desc->descriptor_type == 2) + err(EX_IOERR, "the media in the drive is already formatted (use -F to override)"); + + memset(&format_params, 0, sizeof(struct dvd_format_params)); + format_params.immed = 1; + format_params.desc_len = ntohs(sizeof(struct dvd_format_cap)); + buf_pos = trans.buf + sizeof(struct dvd_format_cap_list_header) + + sizeof(struct dvd_cur_cap_desc) + + (cap_to_use * sizeof(struct dvd_format_cap)); + memcpy(&format_params.desc, buf_pos, sizeof(struct dvd_format_cap)); + if(ioctl(fd, DVDIOFORMATUNIT, &format_params) == -1) + err(EX_IOERR, "ioctl(DVDIOFORMATUNIT)"); + + started = 0; + while (1) { + sleep(1); + if (ioctl(fd, DVDIOFORMATPROGRESS, &percent) == -1) + err(EX_IOERR, "ioctl(DVDIOFORMATPROGRESS)"); + if (percent > 0) + started = 1; + if (percent > 0 && !quiet) + fprintf(stderr, "formating DVD - %d %% done \r", + percent); + if (percent == 100 || (started && percent == 0)) + break; + } + } int >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message