From 181311508173b9c70205bd14450f104550fe7bac Mon Sep 17 00:00:00 2001 From: njl Date: Fri, 18 Oct 2002 22:03:39 +0000 Subject: [PATCH] * Add CDRIOC{READ,WRITE}SPEED ioctls to cd(4). Units are in KB/sec. * Change atapi-cd ioctls to use the same units. * Change burncd, cdcontrol to convert CDROM speed to KB/sec before calling the ioctl. Add a "max" speed option for their command lines. This change does not break ABI but does change the units passed through the ioctl so 3rd party software that uses cdrio.h will have to convert (most likely by multiplying CDROM speed by 177 to get KB/s). PR: kern/36845 Submitted by: Philipp Mergenthaler (CAM ioctls) Reviewed by: sos, ken MFC after: 1 month --- sys/cam/scsi/scsi_cd.c | 47 ++++++++++++++++++++++++++++++++++ sys/cam/scsi/scsi_cd.h | 11 ++++++++ sys/dev/ata/atapi-cd.c | 4 +-- sys/sys/cdrio.h | 1 + usr.sbin/burncd/burncd.8 | 1 + usr.sbin/burncd/burncd.c | 5 +++- usr.sbin/cdcontrol/cdcontrol.1 | 6 ++--- usr.sbin/cdcontrol/cdcontrol.c | 9 ++++--- 8 files changed, 74 insertions(+), 10 deletions(-) diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c index a7af9babbb24..3984f776104f 100644 --- a/sys/cam/scsi/scsi_cd.c +++ b/sys/cam/scsi/scsi_cd.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -230,6 +231,8 @@ static int cdplaytracks(struct cam_periph *periph, static int cdpause(struct cam_periph *periph, u_int32_t go); static int cdstopunit(struct cam_periph *periph, u_int32_t eject); static int cdstartunit(struct cam_periph *periph); +static int cdsetspeed(struct cam_periph *periph, + u_int32_t rdspeed, u_int32_t wrspeed); static int cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo); static int cdsendkey(struct cam_periph *periph, @@ -2379,6 +2382,12 @@ cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) /* return (cd_reset(periph)); */ error = ENOTTY; break; + case CDRIOCREADSPEED: + error = cdsetspeed(periph, *(u_int32_t *)addr, CDR_MAX_SPEED); + break; + case CDRIOCWRITESPEED: + error = cdsetspeed(periph, CDR_MAX_SPEED, *(u_int32_t *)addr); + break; case DVDIOCSENDKEY: case DVDIOCREPORTKEY: { struct dvd_authinfo *authinfo; @@ -2955,6 +2964,44 @@ cdstopunit(struct cam_periph *periph, u_int32_t eject) return(error); } +static int +cdsetspeed(struct cam_periph *periph, u_int32_t rdspeed, u_int32_t wrspeed) +{ + struct scsi_set_speed *scsi_cmd; + struct ccb_scsiio *csio; + union ccb *ccb; + int error; + + error = 0; + ccb = cdgetccb(periph, /* priority */ 1); + csio = &ccb->csio; + + cam_fill_csio(csio, + /* retries */ 1, + /* cbfcnp */ cddone, + /* flags */ CAM_DIR_NONE, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /* data_ptr */ NULL, + /* dxfer_len */ 0, + /* sense_len */ SSD_FULL_SIZE, + sizeof(struct scsi_set_speed), + /* timeout */ 50000); + + scsi_cmd = (struct scsi_set_speed *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + + scsi_cmd->opcode = SET_CD_SPEED; + scsi_ulto2b(rdspeed, scsi_cmd->readspeed); + scsi_ulto2b(wrspeed, scsi_cmd->writespeed); + + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); + + xpt_release_ccb(ccb); + + return(error); +} + static int cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) { diff --git a/sys/cam/scsi/scsi_cd.h b/sys/cam/scsi/scsi_cd.h index fc521197425b..f24213965a8d 100644 --- a/sys/cam/scsi/scsi_cd.h +++ b/sys/cam/scsi/scsi_cd.h @@ -169,6 +169,16 @@ struct scsi_read_cd_capacity u_int8_t control; }; +struct scsi_set_speed +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t readspeed[2]; + u_int8_t writespeed[2]; + u_int8_t reserved[5]; + u_int8_t control; +}; + struct scsi_report_key { u_int8_t opcode; @@ -251,6 +261,7 @@ struct scsi_read_dvd_structure #define PLAY_12 0xa5 /* cdrom pause in 'play audio' mode */ #define PLAY_TRACK_REL_BIG 0xa9 /* cdrom play track/index mode */ #define READ_DVD_STRUCTURE 0xad /* read dvd structure */ +#define SET_CD_SPEED 0xbb /* set c/dvd speed */ struct scsi_report_key_data_header { diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index 6e91ef7e904d..d3bcd60dbced 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -1021,11 +1021,11 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) break; case CDRIOCREADSPEED: - error = acd_set_speed(cdp, 177 * (*(int *)addr), -1); + error = acd_set_speed(cdp, *(int *)addr, CDR_MAX_SPEED); break; case CDRIOCWRITESPEED: - error = acd_set_speed(cdp, -1, 177 * (*(int *)addr)); + error = acd_set_speed(cdp, CDR_MAX_SPEED, *(int *)addr); break; case CDRIOCGETBLOCKSIZE: diff --git a/sys/sys/cdrio.h b/sys/sys/cdrio.h index 77cb1be59313..b664a585af15 100644 --- a/sys/sys/cdrio.h +++ b/sys/sys/cdrio.h @@ -129,6 +129,7 @@ struct cdr_format_params { #define CDRIOCFIXATE _IOW('c', 106, int) #define CDRIOCREADSPEED _IOW('c', 107, int) #define CDRIOCWRITESPEED _IOW('c', 108, int) +#define CDR_MAX_SPEED 0xffff #define CDRIOCGETBLOCKSIZE _IOR('c', 109, int) #define CDRIOCSETBLOCKSIZE _IOW('c', 110, int) #define CDRIOCGETPROGRESS _IOR('c', 111, int) diff --git a/usr.sbin/burncd/burncd.8 b/usr.sbin/burncd/burncd.8 index 47dc84f0455c..520ed9a2c925 100644 --- a/usr.sbin/burncd/burncd.8 +++ b/usr.sbin/burncd/burncd.8 @@ -69,6 +69,7 @@ quiet, do not print progress messages. .It Fl s Ar speed set the speed of the burner device. Defaults to 1. +Specify "max" to use the drive's fastest speed. .It Fl t test write, do not actually write on the media. .It Fl v diff --git a/usr.sbin/burncd/burncd.c b/usr.sbin/burncd/burncd.c index 1d3d2fd540ca..9f3738ef566b 100644 --- a/usr.sbin/burncd/burncd.c +++ b/usr.sbin/burncd/burncd.c @@ -116,7 +116,10 @@ main(int argc, char **argv) break; case 's': - speed = atoi(optarg); + if (strcasecmp("max", optarg) == 0) + speed = CDR_MAX_SPEED; + else + speed = atoi(optarg); if (speed <= 0) errx(EX_USAGE, "Invalid speed: %s", optarg); break; diff --git a/usr.sbin/cdcontrol/cdcontrol.1 b/usr.sbin/cdcontrol/cdcontrol.1 index 3f986fe4e6e7..94214f944844 100644 --- a/usr.sbin/cdcontrol/cdcontrol.1 +++ b/usr.sbin/cdcontrol/cdcontrol.1 @@ -164,9 +164,9 @@ Set minute-second-frame ioctl mode (default). .It Ic set Cm lba Set LBA ioctl mode. .It Ic speed Ar s -Set the highest speed that the drive should use. -The speed is a multiple of the single speed. -This command is currently only supported on ATAPI drives. +Set the highest speed that the drive should use for reading data. +The units are multiples of a single speed CDROM (150 KB/s). +Specify "max" to use the drive's fastest speed. .It Ic quit Quit the program. .El diff --git a/usr.sbin/cdcontrol/cdcontrol.c b/usr.sbin/cdcontrol/cdcontrol.c index f497c5240aa2..5dd058599b73 100644 --- a/usr.sbin/cdcontrol/cdcontrol.c +++ b/usr.sbin/cdcontrol/cdcontrol.c @@ -282,7 +282,6 @@ int run (int cmd, char *arg) { long speed; int l, r, rc; - char *ep; switch (cmd) { @@ -435,9 +434,11 @@ int run (int cmd, char *arg) return (0); errno = 0; - speed = strtol(arg, &ep, 10); - if (*ep || ep == arg || speed <= 0 || speed > INT_MAX || - errno != 0) { + if (strcasecmp("max", arg) == 0) + speed = CDR_MAX_SPEED; + else + speed = strtol(arg, NULL, 10) * 177; + if (speed <= 0 || speed > INT_MAX) { warnx("invalid command arguments %s", arg); return (0); }