www.pudn.com > cdrecord.zip > drv_mmc.c
/* @(#)drv_mmc.c 1.28 98/10/07 Copyright 1997 J. Schilling */ #ifndef lint static char sccsid[] = "@(#)drv_mmc.c 1.28 98/10/07 Copyright 1997 J. Schilling"; #endif /* * CDR device implementation for * SCSI-3/mmc conforming drives * e.g. Yamaha CDR-400, Ricoh MP6200 * * Copyright (c) 1997 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /*#define DEBUG*/ #define PRINT_ATIP #include#include #include #include #include #include #include #include #include #include #include #include #include #include "cdrecord.h" #include "scsitransp.h" extern BOOL isgui; struct scg_cmd scmd; struct scsi_inquiry inq; extern int scsibus; extern int target; extern int lun; extern int silent; extern int verbose; extern int lverbose; LOCAL int curspeed = 1; LOCAL int mmc_load __PR((void)); LOCAL int mmc_unload __PR((void)); LOCAL cdr_t *identify_mmc __PR((cdr_t *, struct scsi_inquiry *)); LOCAL int attach_mmc __PR((cdr_t *)); LOCAL int get_diskinfo __PR((struct disk_info *dip)); LOCAL void di_to_dstat __PR((struct disk_info *dip, dstat_t *dsp)); #ifdef PRINT_ATIP LOCAL int get_pma __PR((void)); #endif LOCAL int getdisktype_mmc __PR((cdr_t *dp, dstat_t *dsp)); LOCAL int speed_select_mmc __PR((int speed, int dummy)); LOCAL int next_wr_addr_mmc __PR((int track, track_t *trackp, long *ap)); LOCAL int open_track_mmc __PR((cdr_t *dp, int track, track_t *trackp)); LOCAL int close_track_mmc __PR((int track, track_t *trackp)); LOCAL int open_session_mmc __PR((int tracks, track_t *trackp, int toctype, int multi)); LOCAL int waitfix_mmc __PR((int secs)); LOCAL int fixate_mmc __PR((int onp, int dummy, int toctype, int tracks, track_t *trackp)); LOCAL int blank_mmc __PR((long addr, int blanktype)); LOCAL int scsi_sony_write __PR((caddr_t bp, long sectaddr, long size, int blocks, BOOL islast)); LOCAL int mmc_load() { return (scsi_load_unload(1)); } LOCAL int mmc_unload() { return (scsi_load_unload(0)); } cdr_t cdr_mmc = { 0, CDR_TAO|CDR_DAO|CDR_PACKET|CDR_SWABAUDIO, "mmc_cdr", "generic SCSI-3/mmc CD-R driver", 0, identify_mmc, attach_mmc, getdisktype_mmc, scsi_load, /* mmc_load,*/ scsi_unload, recovery_needed, recover, speed_select_mmc, select_secsize, next_wr_addr_mmc, reserve_track, scsi_cdr_write, open_track_mmc, close_track_mmc, open_session_mmc, cmd_dummy, read_session_offset, fixate_mmc, blank_mmc, }; cdr_t cdr_mmc_sony = { 0, CDR_TAO|CDR_DAO|CDR_PACKET|CDR_SWABAUDIO, "mmc_cdr_sony", "generic SCSI-3/mmc CD-R driver (Sony 928 variant)", 0, identify_mmc, attach_mmc, getdisktype_mmc, scsi_load, /* mmc_load,*/ scsi_unload, recovery_needed, recover, speed_select_mmc, select_secsize, next_wr_addr_mmc, reserve_track, scsi_sony_write, open_track_mmc, close_track_mmc, open_session_mmc, cmd_dummy, read_session_offset, fixate_mmc, blank_mmc, }; /* * SCSI-3/mmc conformant CD drive */ cdr_t cdr_cd = { 0, CDR_ISREADER|CDR_SWABAUDIO, "mmc_cd", "generic SCSI-3/mmc CD driver", 0, identify_mmc, attach_mmc, drive_getdisktype, scsi_load, scsi_unload, cmd_dummy, /* recovery_needed */ (int(*)__PR((int)))cmd_dummy, /* recover */ speed_select_mmc, select_secsize, (int(*)__PR((int, track_t *, long *)))cmd_dummy, /* next_wr_addr */ reserve_track, scsi_cdr_write, open_track_mmc, close_track_mmc, (int(*)__PR((int, track_t *, int, int)))cmd_dummy, cmd_dummy, read_session_offset, fixation, blank_dummy, }; /* * Old pre SCSI-3/mmc CD drive */ cdr_t cdr_oldcd = { 0, CDR_ISREADER, "scsi2_cd", "generic SCSI-2 CD driver", 0, identify_mmc, drive_attach, drive_getdisktype, scsi_load, scsi_unload, cmd_dummy, /* recovery_needed */ (int(*)__PR((int)))cmd_dummy, /* recover */ speed_select_mmc, select_secsize, (int(*)__PR((int, track_t *, long *)))cmd_dummy, /* next_wr_addr */ reserve_track, scsi_cdr_write, open_track_mmc, close_track_mmc, (int(*)__PR((int, track_t *, int, int)))cmd_dummy, cmd_dummy, read_session_offset_philips, fixation, blank_dummy, }; LOCAL cdr_t * identify_mmc(dp, ip) cdr_t *dp; struct scsi_inquiry *ip; { BOOL cdrr = FALSE; /* Read CD-R */ BOOL cdwr = FALSE; /* Write CD-R */ BOOL cdrrw = FALSE; /* Read CD-RW */ BOOL cdwrw = FALSE; /* Write CD-RW */ Uchar mode[0x100]; struct cd_mode_page_2A *mp; if (ip->type != INQ_WORM && ip->type != INQ_ROMD) return ((cdr_t *)0); allow_atapi(TRUE); /* Try to switch to 10 byte mode cmds */ silent++; mp = mmc_cap(mode); /* Get MMC capabilities */ silent--; if (mp == NULL) return (&cdr_oldcd); /* Pre SCSI-3/mmc drive */ mmc_getval(mp, &cdrr, &cdwr, &cdrrw, &cdwrw, NULL); /* * At this point we know that we have a SCSI-3/mmc compliant drive. * Unfortunately ATAPI drives violate the SCSI spec in returning * a response data format of '1' which from the SCSI spec would * tell us not to use the "PF" bit in mode select. As ATAPI drives * require the "PF" bit to be set, we 'correct' the inquiry data. * * XXX xxx_identify() should not have any side_effects ?? */ if (ip->data_format < 2) ip->data_format = 2; if (strncmp(ip->vendor_info, "SONY", 4) == 0 && strncmp(ip->prod_ident, "CD-R CDU928E", 14) == 0) { dp = &cdr_mmc_sony; } if (!cdwr) /* SCSI-3/mmc CD drive */ dp = &cdr_cd; return (dp); } LOCAL int attach_mmc(dp) cdr_t *dp; { struct cd_mode_page_2A *mp; allow_atapi(TRUE); /* Try to switch to 10 byte mode cmds */ silent++; mp = mmc_cap(NULL); /* Get MMC capabilities in allocated mp */ silent--; if (mp == NULL) return (-1); /* Pre SCSI-3/mmc drive */ dp->cdr_cdcap = mp; /* Store MMC cap pointer */ if (mp->loading_type == LT_TRAY) dp->cdr_flags |= CDR_TRAYLOAD; else if (mp->loading_type == LT_CADDY) dp->cdr_flags |= CDR_CADDYLOAD; return (0); } #ifdef PRINT_ATIP LOCAL int get_atip __PR((struct atipinfo *atp)); void print_di __PR((struct disk_info *dip)); void print_atip __PR((struct atipinfo *atp)); #endif /* PRINT_ATIP */ LOCAL int get_diskinfo(dip) struct disk_info *dip; { int len; int ret; fillbytes((caddr_t)dip, sizeof(*dip), '\0'); if (read_disk_info((caddr_t)dip, 2) < 0) return (-1); len = a_to_u_short(dip->data_len); len += 2; ret = read_disk_info((caddr_t)dip, len); #ifdef DEBUG scsiprbytes("Disk info:", (u_char *)dip, len-scsigetresid()); #endif return (ret); } LOCAL void di_to_dstat(dip, dsp) struct disk_info *dip; dstat_t *dsp; { dsp->ds_diskid = a_to_u_long(dip->disk_id); if (dip->did_v) dsp->ds_flags |= DSF_DID_V; dsp->ds_diskstat = dip->disk_status; dsp->ds_sessstat = dip->sess_status; dsp->ds_maxblocks = msf_to_lba(dip->last_lead_out[1], dip->last_lead_out[2], dip->last_lead_out[3]); /* * Check for 0xFF:0xFF/0xFF which is an indicator for a complete disk */ if (dsp->ds_maxblocks == 716730) dsp->ds_maxblocks = -1L; if (dsp->ds_first_leadin == 0) { dsp->ds_first_leadin = msf_to_lba(dip->last_lead_in[1], dip->last_lead_in[2], dip->last_lead_in[3]); if (dsp->ds_first_leadin > 0) dsp->ds_first_leadin = 0; } if (dsp->ds_last_leadout == 0 && dsp->ds_maxblocks >= 0) dsp->ds_last_leadout = dsp->ds_maxblocks; } #ifdef PRINT_ATIP LOCAL int get_atip(atp) struct atipinfo *atp; { int len; int ret; fillbytes((caddr_t)atp, sizeof(*atp), '\0'); if (read_toc((caddr_t)atp, 0, 2, 0, FMT_ATIP) < 0) return (-1); len = a_to_u_short(atp->hd.len); len += 2; ret = read_toc((caddr_t)atp, 0, len, 0, FMT_ATIP); #ifdef DEBUG scsiprbytes("ATIP info:", (u_char *)atp, len-scsigetresid()); #endif /* * Yamaha sometimes returns zeroed ATIP info for disks without ATIP */ if (atp->desc.lead_in[1] == 0 && atp->desc.lead_in[2] == 0 && atp->desc.lead_in[3] == 0 && atp->desc.lead_out[1] == 0 && atp->desc.lead_out[2] == 0 && atp->desc.lead_out[3] == 0) return (-1); return (ret); } LOCAL int /*get_pma(atp)*/ get_pma() /* struct atipinfo *atp;*/ { int len; int ret; char atp[1024]; fillbytes((caddr_t)atp, sizeof(*atp), '\0'); /* if (read_toc((caddr_t)atp, 0, 2, 1, FMT_PMA) < 0)*/ if (read_toc((caddr_t)atp, 0, 2, 0, FMT_PMA) < 0) return (-1); /* len = a_to_u_short(atp->hd.len);*/ len = a_to_u_short(atp); len += 2; /* ret = read_toc((caddr_t)atp, 0, len, 1, FMT_PMA);*/ ret = read_toc((caddr_t)atp, 0, len, 0, FMT_PMA); #ifdef DEBUG scsiprbytes("PMA:", (u_char *)atp, len-scsigetresid()); #endif ret = read_toc((caddr_t)atp, 0, len, 1, FMT_PMA); #ifdef DEBUG scsiprbytes("PMA:", (u_char *)atp, len-scsigetresid()); #endif return (ret); } #endif /* PRINT_ATIP */ LOCAL int getdisktype_mmc(dp, dsp) cdr_t *dp; dstat_t *dsp; { extern char *buf; struct disk_info *dip; u_char mode[0x100]; char ans[2]; msf_t msf; BOOL did_atip = FALSE; msf.msf_min = msf.msf_sec = msf.msf_frame = 0; #ifdef PRINT_ATIP /* * It seems that there are drives that do not support to * read ATIP (e.g. HP 7100) * Also if a NON CD-R media is inserted, this will never work. * For this reason, make a failure non-fatal. */ silent++; if (get_atip((struct atipinfo *)mode) >= 0) { msf.msf_min = mode[8]; msf.msf_sec = mode[9]; msf.msf_frame = mode[10]; did_atip = TRUE; if (lverbose) { print_atip((struct atipinfo *)mode); pr_manufacturer(&msf); } } silent--; #endif dip = (struct disk_info *)buf; if (get_diskinfo(dip) < 0) return (-1); /* * Check for non writable disk first. */ if (dip->disk_status == DS_COMPLETE) { errmsgno(EX_BAD, "Drive needs to reload the media to return to proper status.\n"); unload_media(dp, F_EJECT); if ((dp->cdr_flags & CDR_TRAYLOAD) == 0) { printf("Re-load disk and hit "); if (isgui) printf("\n"); flush(); getline(ans, 1); } load_media(dp); } if (get_diskinfo(dip) < 0) return (-1); di_to_dstat(dip, dsp); if (!did_atip && dsp->ds_first_leadin < 0) lba_to_msf(dsp->ds_first_leadin, &msf); if (lverbose && !did_atip) { print_min_atip(dsp->ds_first_leadin, dsp->ds_last_leadout); if (dsp->ds_first_leadin < 0) pr_manufacturer(&msf); } dsp->ds_maxrblocks = disk_rcap(&msf, dsp->ds_maxblocks); #ifdef PRINT_ATIP #ifdef DEBUG if (get_atip((struct atipinfo *)mode) < 0) return (-1); /* * Get pma gibt Ärger mit CW-7502 * Wenn Die Disk leer ist, dann stuerzt alles ab. * Firmware 4.02 kann nicht get_pma */ if (dip->disk_status != DS_EMPTY) { /* get_pma();*/ } printf("ATIP lead in: %ld (%02d:%02d/%02d)\n", msf_to_lba(mode[8], mode[9], mode[10]), mode[8], mode[9], mode[10]); printf("ATIP lead out: %ld (%02d:%02d/%02d)\n", msf_to_lba(mode[12], mode[13], mode[14]), mode[12], mode[13], mode[14]); print_di(dip); print_atip((struct atipinfo *)mode); #endif #endif /* PRINT_ATIP */ return (drive_getdisktype(dp, dsp)); } #ifdef PRINT_ATIP #define DOES(what,flag) printf(" Does %s%s\n", flag?"":"not ",what); #define IS(what,flag) printf(" Is %s%s\n", flag?"":"not ",what); #define VAL(what,val) printf(" %s: %d\n", what, val[0]*256 + val[1]); #define SVAL(what,val) printf(" %s: %s\n", what, val); void print_di(dip) struct disk_info *dip; { static char *ds_name[] = { "empty", "incomplete/appendable", "complete", "illegal" }; static char *ss_name[] = { "empty", "incomplete/appendable", "illegal", "complete", }; IS("erasable", dip->erasable); printf("disk status: %s\n", ds_name[dip->disk_status]); printf("session status: %s\n", ss_name[dip->sess_status]); printf("first track: %d number of sessions: %d first track in last sess: %d last track in last sess: %d\n", dip->first_track, dip->numsess, dip->first_track_ls, dip->last_track_ls); IS("unrestricted", dip->uru); printf("Disk type: "); switch (dip->disk_type) { case SES_DA_ROM: printf("CD-DA or CD-ROM"); break; case SES_CDI: printf("CDI"); break; case SES_XA: printf("CD-ROM XA"); break; case SES_UNDEF: printf("undefined"); break; default: printf("reserved"); break; } printf("\n"); if (dip->did_v) printf("Disk id: 0x%lX\n", a_to_u_long(dip->disk_id)); printf("last start of lead in: %ld\n", msf_to_lba(dip->last_lead_in[1], dip->last_lead_in[2], dip->last_lead_in[3])); printf("last start of lead out: %ld\n", msf_to_lba(dip->last_lead_out[1], dip->last_lead_out[2], dip->last_lead_out[3])); if (dip->dbc_v) printf("Disk bar code: 0x%lX%lX\n", a_to_u_long(dip->disk_barcode), a_to_u_long(&dip->disk_barcode[4])); if (dip->num_opc_entries > 0) { printf("OPC table:\n"); } } LOCAL char clv_to_speed[8] = { 0, 2, 4, 6, 8, 0, 0, 0 }; void print_atip(atp) struct atipinfo *atp; { if (verbose) scsiprbytes("ATIP info: ", (Uchar *)atp, sizeof (*atp)); printf("ATIP info from disk:\n"); printf(" Indicated writing power: %d\n", atp->desc.ind_wr_power); if (atp->desc.erasable || atp->desc.ref_speed) printf(" Reference speed: %d\n", clv_to_speed[atp->desc.ref_speed]); IS("unrestricted", atp->desc.uru); IS("erasable", atp->desc.erasable); if (atp->desc.sub_type) printf(" Disk sub type: %d\n", atp->desc.sub_type); printf(" ATIP start of lead in: %ld (%02d:%02d/%02d)\n", msf_to_lba(atp->desc.lead_in[1], atp->desc.lead_in[2], atp->desc.lead_in[3]), atp->desc.lead_in[1], atp->desc.lead_in[2], atp->desc.lead_in[3]); printf(" ATIP start of lead out: %ld (%02d:%02d/%02d)\n", msf_to_lba(atp->desc.lead_out[1], atp->desc.lead_out[2], atp->desc.lead_out[3]), atp->desc.lead_out[1], atp->desc.lead_out[2], atp->desc.lead_out[3]); if (atp->desc.a1_v) { if (atp->desc.clv_low != 0 || atp->desc.clv_high != 0) printf(" speed low: %d speed high: %d\n", clv_to_speed[atp->desc.clv_low], clv_to_speed[atp->desc.clv_high]); printf(" power mult factor: %d %d\n", atp->desc.power_mult, atp->desc.tgt_y_pow); if (atp->desc.erasable) printf(" recommended erase/write power: %d\n", atp->desc.rerase_pwr_ratio); } if (atp->desc.a2_v) { printf(" A2 values: %02X %02X %02X\n", atp->desc.a2[0], atp->desc.a2[1], atp->desc.a2[2]); } if (atp->desc.a3_v) { printf(" A3 values: %02X %02X %02X\n", atp->desc.a3[0], atp->desc.a3[1], atp->desc.a3[2]); } } #endif /* PRINT_ATIP */ LOCAL int speed_select_mmc(speed, dummy) int speed; int dummy; { u_char mode[0x100]; int len; struct cd_mode_page_05 *mp; curspeed = speed; fillbytes((caddr_t)mode, sizeof(mode), '\0'); if (!get_mode_params(0x05, "CD write parameter", mode, (u_char *)0, (u_char *)0, (u_char *)0, &len)) return (-1); if (len == 0) return (-1); mp = (struct cd_mode_page_05 *) (mode + sizeof(struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); #ifdef DEBUG scsiprbytes("CD write parameter:", (u_char *)mode, len); #endif mp->test_write = dummy != 0; /* * Set default values: * Write type = 01 (track at once) * Track mode = 04 (CD-ROM) * Data block type = 08 (CD-ROM) * Session format = 00 (CD-ROM) */ mp->write_type = WT_TAO; mp->track_mode = TM_DATA; mp->dbtype = DB_ROM_MODE1; mp->session_format = SES_DA_ROM;/* Matsushita has illegal def. value */ #ifdef DEBUG scsiprbytes("CD write parameter:", (u_char *)mode, len); #endif if (!set_mode_params("CD write parameter", mode, len, 0, -1)) return (-1); /*XXX max speed aus page 0x2A lesen !! */ /* if (scsi_set_speed(-1, speed*176) < 0)*/ /* * 44100 * 2 * 2 = 176400 bytes/s * * The right formula would be: * tmp = (((long)speed) * 1764) / 10; * * But the standard is rounding the wrong way. * Furtunately rounding down is guaranteed. */ if (scsi_set_speed(-1, speed*177) < 0) return (-1); return (0); } LOCAL int next_wr_addr_mmc(track, trackp, ap) int track; track_t *trackp; long *ap; { struct track_info track_info; long next_addr; int result = -1; /* * Reading info for current track may require doing the read_track_info * with either the track number (if the track is currently being written) * or with 0xFF (if the track hasn't been started yet and is invisible */ if (track > 0 && is_packet(trackp)) { silent ++; result = read_track_info((caddr_t)&track_info, track, sizeof(track_info)); silent --; } if (result < 0) { if (read_track_info((caddr_t)&track_info, 0xFF, sizeof(track_info)) < 0) return (-1); } if (verbose) scsiprbytes("track info:", (u_char *)&track_info, sizeof(track_info)-scsigetresid()); next_addr = a_to_u_long(track_info.next_writable_addr); if (ap) *ap = next_addr; return (0); } int st2mode[] = { 0, /* 0 */ TM_DATA, /* 1 ST_ROM_MODE1 */ TM_DATA, /* 2 ST_ROM_MODE2 */ 0, /* 3 */ 0, /* 4 ST_AUDIO_NOPRE */ TM_PREEM, /* 5 ST_AUDIO_PRE */ 0, /* 6 */ 0, /* 7 */ }; LOCAL int open_track_mmc(dp, track, trackp) cdr_t *dp; int track; track_t *trackp; { u_char mode[0x100]; int len; struct cd_mode_page_05 *mp; fillbytes((caddr_t)mode, sizeof(mode), '\0'); if (!get_mode_params(0x05, "CD write parameter", mode, (u_char *)0, (u_char *)0, (u_char *)0, &len)) return (-1); if (len == 0) return (-1); mp = (struct cd_mode_page_05 *) (mode + sizeof(struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); /* mp->track_mode = ???;*/ mp->track_mode = st2mode[trackp->sectype & ST_MASK]; /* mp->copy = ???;*/ mp->dbtype = trackp->dbtype; /*i_to_short(mp->audio_pause_len, 300);*/ /*i_to_short(mp->audio_pause_len, 150);*/ /*i_to_short(mp->audio_pause_len, 0);*/ if (is_packet(trackp)) { mp->write_type = WT_PACKET; mp->track_mode |= TM_INCREMENTAL; mp->fp = (trackp->pktsize > 0) ? 1 : 0; i_to_4_byte(mp->packet_size, trackp->pktsize); } else { mp->write_type = WT_TAO; mp->fp = 0; i_to_4_byte(mp->packet_size, 0); } #ifdef DEBUG scsiprbytes("CD write parameter:", (u_char *)mode, len); #endif if (!set_mode_params("CD write parameter", mode, len, 0, trackp->secsize)) return (-1); return (0); } LOCAL int close_track_mmc(track, trackp) int track; track_t *trackp; { int ret; if (scsi_flush_cache() < 0) { printf("Trouble flushing the cache\n"); return -1; } wait_unit_ready(300); /* XXX Wait for ATAPI */ if (is_packet(trackp) && !is_noclose(trackp)) { /* close the incomplete track */ ret = scsi_close_tr_session(1, 0xFF); wait_unit_ready(300); /* XXX Wait for ATAPI */ return (ret); } return (0); } int toc2sess[] = { SES_DA_ROM, /* CD-DA */ SES_DA_ROM, /* CD-ROM */ SES_XA, /* CD-ROM XA mode 1 */ SES_XA, /* CD-ROM XA MODE 2 */ SES_CDI, /* CDI */ SES_DA_ROM, /* Invalid - use default */ SES_DA_ROM, /* Invalid - use default */ }; LOCAL int open_session_mmc(tracks, trackp, toctype, multi) int tracks; track_t *trackp; int toctype; int multi; { u_char mode[0x100]; int len; struct cd_mode_page_05 *mp; fillbytes((caddr_t)mode, sizeof(mode), '\0'); if (!get_mode_params(0x05, "CD write parameter", mode, (u_char *)0, (u_char *)0, (u_char *)0, &len)) return (-1); if (len == 0) return (-1); mp = (struct cd_mode_page_05 *) (mode + sizeof(struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); mp->write_type = WT_TAO; /* fix to allow DAO later */ mp->multi_session = (multi != 0) ? MS_MULTI : MS_NONE; mp->session_format = toc2sess[toctype & TOC_MASK]; #ifdef DEBUG scsiprbytes("CD write parameter:", (u_char *)mode, len); #endif if (!set_mode_params("CD write parameter", mode, len, 0, -1)) return (-1); return (0); } LOCAL int waitfix_mmc(secs) int secs; { char dibuf[16]; int i; int key; #define W_SLEEP 2 silent++; for (i = 0; i < secs/W_SLEEP; i++) { if (read_disk_info(dibuf, sizeof(dibuf)) >= 0) { silent--; return (0); } key = scsi_sense_key(); if (key != SC_UNIT_ATTENTION && key != SC_NOT_READY) break; sleep(W_SLEEP); } silent--; return (-1); #undef W_SLEEP } LOCAL int fixate_mmc(onp, dummy, toctype, tracks, trackp) int onp; int dummy; int toctype; int tracks; track_t *trackp; { int ret; int key; int code; struct timeval starttime; struct timeval stoptime; starttime.tv_sec = 0; starttime.tv_usec = 0; stoptime = starttime; gettimeofday(&starttime, (struct timezone *)0); if (dummy && lverbose) printf("WARNING: Some drives don't like fixation in dummy mode.\n"); silent++; ret = scsi_close_tr_session(2, 0); silent--; key = scsi_sense_key(); code = scsi_sense_code(); if (ret >= 0) { wait_unit_ready(420/curspeed); /* XXX Wait for ATAPI */ waitfix_mmc(420/curspeed); /* XXX Wait for ATAPI */ return (ret); } if ((dummy != 0 && (key != SC_ILLEGAL_REQUEST)) || /* * Try to suppress messages from drives that don't like fixation * in -dummy mode. */ ((dummy == 0) && ((key != SC_UNIT_ATTENTION) || (code != 0x2E) || (strncmp(inq.vendor_info, "MITSUMI", 7) != 0)))) { /* * UNIT ATTENTION/2E seems to be a magic for Mitsumi ATAPI drives * when returning early from fixating. * Try to supress the error message in this case to make * simple minded users less confused. */ scsiprinterr("close track/session"); scsiprintresult(); /* XXX restore key/code in future */ } wait_unit_ready(420); /* XXX Wait for ATAPI */ waitfix_mmc(420/curspeed); /* XXX Wait for ATAPI */ if (!dummy && (ret >= 0 || (key == SC_UNIT_ATTENTION && code == 0x2E))) { /* * Some ATAPI drives (e.g. Mitsumi) imply the * IMMED bit in the SCSI cdb. As there seems to be no * way to properly check for the real end of the * fixating process we wait for the expected time. */ gettimeofday(&stoptime, (struct timezone *)0); timevaldiff(&starttime, &stoptime); if (stoptime.tv_sec < (220 / curspeed)) { unsigned secs; if (lverbose) { printf("Actual fixating time: %ld seconds\n", (long)stoptime.tv_sec); } secs = (280 / curspeed) - stoptime.tv_sec; if (lverbose) { printf("ATAPI early return: sleeping %d seconds.\n", secs); } sleep(secs); } } return (ret); } char *blank_types[] = { "entire disk", "PMA, TOC, pregap", "incomplete track", "reserved track", "tail of track", "closing of last session", "last session", "reserved blanking type", }; LOCAL int blank_mmc(addr, blanktype) long addr; int blanktype; { BOOL cdrr = FALSE; /* Read CD-R */ BOOL cdwr = FALSE; /* Write CD-R */ BOOL cdrrw = FALSE; /* Read CD-RW */ BOOL cdwrw = FALSE; /* Write CD-RW */ mmc_check(&cdrr, &cdwr, &cdrrw, &cdwrw, NULL); if (!cdwrw) return (blank_dummy(addr, blanktype)); if (lverbose) printf("Blanking %s\n", blank_types[blanktype & 0x07]); return (scsi_blank(addr, blanktype)); } LOCAL int scsi_sony_write(bp, sectaddr, size, blocks, islast) caddr_t bp; /* address of buffer */ long sectaddr; /* disk address (sector) to put */ long size; /* number of bytes to transfer */ int blocks; /* sector count */ BOOL islast; /* last write for track */ { return (write_xg5(bp, sectaddr, size, blocks)); }