From owner-freebsd-firewire Mon Nov 4 20: 4:21 2002 Delivered-To: freebsd-firewire@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id BB58237B401; Mon, 4 Nov 2002 20:03:53 -0800 (PST) Received: from panzer.kdm.org (panzer.kdm.org [216.160.178.169]) by mx1.FreeBSD.org (Postfix) with ESMTP id BC3CD43E75; Mon, 4 Nov 2002 20:03:50 -0800 (PST) (envelope-from ken@panzer.kdm.org) Received: from panzer.kdm.org (localhost [127.0.0.1]) by panzer.kdm.org (8.12.5/8.12.5) with ESMTP id gA543nKD041474; Mon, 4 Nov 2002 21:03:49 -0700 (MST) (envelope-from ken@panzer.kdm.org) Received: (from ken@localhost) by panzer.kdm.org (8.12.5/8.12.5/Submit) id gA543m5w041473; Mon, 4 Nov 2002 21:03:48 -0700 (MST) (envelope-from ken) Date: Mon, 4 Nov 2002 21:03:48 -0700 From: "Kenneth D. Merry" To: Hidetoshi Shimokawa Cc: David Kleiner , Dmitry Mottl , freebsd-firewire@FreeBSD.ORG, freebsd-scsi@FreeBSD.ORG Subject: Re: VAIO Firewire dock station with DVD-ROM Message-ID: <20021104210348.A41448@panzer.kdm.org> References: <20021025184837.C227-100000@localhost> <20021104073302.GA27648@panix.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="h31gzZEtNLTqOjlF" Content-Disposition: inline User-Agent: Mutt/1.2.5.1i In-Reply-To: ; from simokawa@sat.t.u-tokyo.ac.jp on Tue, Nov 05, 2002 at 11:40:01AM +0900 Sender: owner-freebsd-firewire@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG --h31gzZEtNLTqOjlF Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Tue, Nov 05, 2002 at 11:40:01 +0900, Hidetoshi Shimokawa wrote: > At Mon, 4 Nov 2002 02:33:02 -0500, > David Kleiner wrote: > > > > Hidetoshi-san, > > > > I have just rebuilt my RELENG_4 world with just imported > > firewire support. > > > > Here is what I am getting when trying to run cdcontrol: > .. > > (cd0:sbp0:0:0:0): MODE SENSE(06). CDB: 1a 0 e 0 1c 0 > > (cd0:sbp0:0:0:0): ILLEGAL REQUEST asc:20,0 > > (cd0:sbp0:0:0:0): Invalid command operation code > > Could you try the CAM patch which Ken posted to the list? I've attached a -stable version of the patch. Keep in mind that this version has a bit of extra debugging output, so don't be alarmed if it is a bit more chatty than you expect. Ken -- Kenneth Merry ken@kdm.org --h31gzZEtNLTqOjlF Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="scsi_cd.cmdsize.stable.200211102" ==== //depot/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_all.c#7 - /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_all.c ==== *** /tmp/tmp.6985.0 Sat Nov 2 18:52:39 2002 --- /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_all.c Sat Nov 2 18:35:15 2002 *************** *** 2568,2579 **** u_int8_t page, u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, u_int32_t timeout) { u_int8_t cdb_len; /* * Use the smallest possible command to perform the operation. */ ! if (param_len < 256) { /* * We can fit in a 6 byte cdb. */ --- 2568,2591 ---- u_int8_t page, u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, u_int32_t timeout) { + return(scsi_mode_sense_len(csio, retries, cbfcnp, tag_action, dbd, + page_code, page, param_buf, param_len, 0, + sense_len, timeout)); + } + void + scsi_mode_sense_len(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int dbd, u_int8_t page_code, + u_int8_t page, u_int8_t *param_buf, u_int32_t param_len, + int minimum_cmd_size, u_int8_t sense_len, u_int32_t timeout) + { u_int8_t cdb_len; /* * Use the smallest possible command to perform the operation. */ ! if ((param_len < 256) ! && (minimum_cmd_size < 10)) { /* * We can fit in a 6 byte cdb. */ *************** *** 2621,2632 **** u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, u_int32_t timeout) { u_int8_t cdb_len; /* * Use the smallest possible command to perform the operation. */ ! if (param_len < 256) { /* * We can fit in a 6 byte cdb. */ --- 2633,2658 ---- u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, u_int32_t timeout) { + return(scsi_mode_select_len(csio, retries, cbfcnp, tag_action, + scsi_page_fmt, save_pages, param_buf, + param_len, 0, sense_len, timeout)); + } + + void + scsi_mode_select_len(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int scsi_page_fmt, int save_pages, + u_int8_t *param_buf, u_int32_t param_len, + int minimum_cmd_size, u_int8_t sense_len, + u_int32_t timeout) + { u_int8_t cdb_len; /* * Use the smallest possible command to perform the operation. */ ! if ((param_len < 256) ! && (minimum_cmd_size < 10)) { /* * We can fit in a 6 byte cdb. */ ==== //depot/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_all.h#2 - /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_all.h ==== *** /tmp/tmp.6985.1 Sat Nov 2 18:52:39 2002 --- /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_all.h Sat Nov 2 18:35:25 2002 *************** *** 833,838 **** --- 833,847 ---- u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, u_int32_t timeout); + void scsi_mode_sense_len(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), + u_int8_t tag_action, int dbd, + u_int8_t page_code, u_int8_t page, + u_int8_t *param_buf, u_int32_t param_len, + int minimum_cmd_size, u_int8_t sense_len, + u_int32_t timeout); + void scsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *), *************** *** 840,845 **** --- 849,862 ---- int save_pages, u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, u_int32_t timeout); + + void scsi_mode_select_len(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), + u_int8_t tag_action, int scsi_page_fmt, + int save_pages, u_int8_t *param_buf, + u_int32_t param_len, int minimum_cmd_size, + u_int8_t sense_len, u_int32_t timeout); void scsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, ==== //depot/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.c#6 - /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.c ==== *** /tmp/tmp.6985.2 Sat Nov 2 18:52:40 2002 --- /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.c Sat Nov 2 18:50:33 2002 *************** *** 1,6 **** /* * Copyright (c) 1997 Justin T. Gibbs. ! * Copyright (c) 1997, 1998, 1999, 2000, 2001 Kenneth D. Merry. * All rights reserved. * * Redistribution and use in source and binary forms, with or without --- 1,6 ---- /* * Copyright (c) 1997 Justin T. Gibbs. ! * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002 Kenneth D. Merry. * All rights reserved. * * Redistribution and use in source and binary forms, with or without *************** *** 136,141 **** --- 136,142 ---- struct cdchanger *changer; int bufs_left; struct cam_periph *periph; + int minimum_command_size; }; struct cd_quirk_entry { *************** *** 203,208 **** --- 204,210 ---- u_int32_t priority); static void cddone(struct cam_periph *periph, union ccb *start_ccb); + static int cd6byteworkaround(union ccb *ccb); static int cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags); static void cdprevent(struct cam_periph *periph, int action); *************** *** 212,220 **** u_int32_t start, struct cd_toc_entry *data, u_int32_t len); static int cdgetmode(struct cam_periph *periph, ! struct cd_mode_data *data, u_int32_t page); static int cdsetmode(struct cam_periph *periph, ! struct cd_mode_data *data); static int cdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len); static int cdreadsubchannel(struct cam_periph *periph, --- 214,222 ---- u_int32_t start, struct cd_toc_entry *data, u_int32_t len); static int cdgetmode(struct cam_periph *periph, ! struct cd_mode_params *data, u_int32_t page); static int cdsetmode(struct cam_periph *periph, ! struct cd_mode_params *data); static int cdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len); static int cdreadsubchannel(struct cam_periph *periph, *************** *** 614,619 **** --- 616,623 ---- else softc->quirks = CD_Q_NONE; + softc->minimum_command_size = 6; + /* * We need to register the statistics structure for this device, * but we don't have the blocksize yet for it. So, we register *************** *** 1846,1854 **** { struct ioc_play_track *args = (struct ioc_play_track *) addr; ! struct cd_mode_data *data; ! data = malloc(sizeof(struct cd_mode_data), M_TEMP, M_WAITOK); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, --- 1850,1859 ---- { struct ioc_play_track *args = (struct ioc_play_track *) addr; ! struct cd_mode_params *data; ! union cd_pages *page; ! data = malloc(sizeof(struct cd_mode_params), M_TEMP, M_WAITOK); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, *************** *** 1859,1866 **** free(data, M_TEMP); break; } ! data->page.audio.flags &= ~CD_PA_SOTC; ! data->page.audio.flags |= CD_PA_IMMED; error = cdsetmode(periph, data); free(data, M_TEMP); if (error) --- 1864,1875 ---- free(data, M_TEMP); break; } ! page = (data->cdb_size == 10) ? ! &data->mode_data.mode_data_10.page : ! &data->mode_data.mode_data_6.page; ! ! page->audio.flags &= ~CD_PA_SOTC; ! page->audio.flags |= CD_PA_IMMED; error = cdsetmode(periph, data); free(data, M_TEMP); if (error) *************** *** 1880,1888 **** { struct ioc_play_msf *args = (struct ioc_play_msf *) addr; ! struct cd_mode_data *data; ! data = malloc(sizeof(struct cd_mode_data), M_TEMP, M_WAITOK); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, --- 1889,1898 ---- { struct ioc_play_msf *args = (struct ioc_play_msf *) addr; ! struct cd_mode_params *data; ! union cd_pages *page; ! data = malloc(sizeof(struct cd_mode_params), M_TEMP, M_WAITOK); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, *************** *** 1893,1900 **** free(data, M_TEMP); break; } ! data->page.audio.flags &= ~CD_PA_SOTC; ! data->page.audio.flags |= CD_PA_IMMED; error = cdsetmode(periph, data); free(data, M_TEMP); if (error) --- 1903,1914 ---- free(data, M_TEMP); break; } ! page = (data->cdb_size == 10) ? ! &data->mode_data.mode_data_10.page : ! &data->mode_data.mode_data_6.page; ! ! page->audio.flags &= ~CD_PA_SOTC; ! page->audio.flags |= CD_PA_IMMED; error = cdsetmode(periph, data); free(data, M_TEMP); if (error) *************** *** 1912,1923 **** { struct ioc_play_blocks *args = (struct ioc_play_blocks *) addr; ! struct cd_mode_data *data; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCPLAYBLOCKS\n")); ! data = malloc(sizeof(struct cd_mode_data), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); --- 1926,1938 ---- { struct ioc_play_blocks *args = (struct ioc_play_blocks *) addr; ! struct cd_mode_params *data; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCPLAYBLOCKS\n")); ! data = malloc(sizeof(struct cd_mode_params), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); *************** *** 1925,1932 **** free(data, M_TEMP); break; } ! data->page.audio.flags &= ~CD_PA_SOTC; ! data->page.audio.flags |= CD_PA_IMMED; error = cdsetmode(periph, data); free(data, M_TEMP); if (error) --- 1940,1951 ---- free(data, M_TEMP); break; } ! page = (data->cdb_size == 10) ? ! &data->mode_data.mode_data_10.page : ! &data->mode_data.mode_data_6.page; ! ! page->audio.flags &= ~CD_PA_SOTC; ! page->audio.flags |= CD_PA_IMMED; error = cdsetmode(periph, data); free(data, M_TEMP); if (error) *************** *** 2219,2242 **** case CDIOCSETPATCH: { struct ioc_patch *arg = (struct ioc_patch *) addr; ! struct cd_mode_data *data; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETPATCH\n")); ! data = malloc(sizeof(struct cd_mode_data), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! data->page.audio.port[LEFT_PORT].channels = arg->patch[0]; ! data->page.audio.port[RIGHT_PORT].channels = arg->patch[1]; ! data->page.audio.port[2].channels = arg->patch[2]; ! data->page.audio.port[3].channels = arg->patch[3]; error = cdsetmode(periph, data); free(data, M_TEMP); } --- 2238,2266 ---- case CDIOCSETPATCH: { struct ioc_patch *arg = (struct ioc_patch *) addr; ! struct cd_mode_params *data; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETPATCH\n")); ! data = malloc(sizeof(struct cd_mode_params), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! page = (data->cdb_size == 10) ? ! &data->mode_data.mode_data_10.page : ! &data->mode_data.mode_data_6.page; ! ! page->audio.port[LEFT_PORT].channels = arg->patch[0]; ! page->audio.port[RIGHT_PORT].channels = arg->patch[1]; ! page->audio.port[2].channels = arg->patch[2]; ! page->audio.port[3].channels = arg->patch[3]; error = cdsetmode(periph, data); free(data, M_TEMP); } *************** *** 2244,2411 **** case CDIOCGETVOL: { struct ioc_vol *arg = (struct ioc_vol *) addr; ! struct cd_mode_data *data; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCGETVOL\n")); ! data = malloc(sizeof(struct cd_mode_data), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } arg->vol[LEFT_PORT] = ! data->page.audio.port[LEFT_PORT].volume; arg->vol[RIGHT_PORT] = ! data->page.audio.port[RIGHT_PORT].volume; ! arg->vol[2] = data->page.audio.port[2].volume; ! arg->vol[3] = data->page.audio.port[3].volume; free(data, M_TEMP); } break; case CDIOCSETVOL: { struct ioc_vol *arg = (struct ioc_vol *) addr; ! struct cd_mode_data *data; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETVOL\n")); ! data = malloc(sizeof(struct cd_mode_data), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! data->page.audio.port[LEFT_PORT].channels = CHANNEL_0; ! data->page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT]; ! data->page.audio.port[RIGHT_PORT].channels = CHANNEL_1; ! data->page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT]; ! data->page.audio.port[2].volume = arg->vol[2]; ! data->page.audio.port[3].volume = arg->vol[3]; error = cdsetmode(periph, data); free(data, M_TEMP); } break; case CDIOCSETMONO: { ! struct cd_mode_data *data; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETMONO\n")); ! data = malloc(sizeof(struct cd_mode_data), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! data->page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL; ! data->page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL; ! data->page.audio.port[2].channels = 0; ! data->page.audio.port[3].channels = 0; error = cdsetmode(periph, data); free(data, M_TEMP); } break; case CDIOCSETSTEREO: { ! struct cd_mode_data *data; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETSTEREO\n")); ! data = malloc(sizeof(struct cd_mode_data), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! data->page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL; ! data->page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; ! data->page.audio.port[2].channels = 0; ! data->page.audio.port[3].channels = 0; error = cdsetmode(periph, data); free(data, M_TEMP); } break; case CDIOCSETMUTE: { ! struct cd_mode_data *data; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETMUTE\n")); ! data = malloc(sizeof(struct cd_mode_data), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! data->page.audio.port[LEFT_PORT].channels = 0; ! data->page.audio.port[RIGHT_PORT].channels = 0; ! data->page.audio.port[2].channels = 0; ! data->page.audio.port[3].channels = 0; error = cdsetmode(periph, data); free(data, M_TEMP); } break; case CDIOCSETLEFT: { ! struct cd_mode_data *data; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETLEFT\n")); ! data = malloc(sizeof(struct cd_mode_data), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! data->page.audio.port[LEFT_PORT].channels = ! LEFT_CHANNEL; ! data->page.audio.port[RIGHT_PORT].channels = ! LEFT_CHANNEL; ! data->page.audio.port[2].channels = 0; ! data->page.audio.port[3].channels = 0; error = cdsetmode(periph, data); free(data, M_TEMP); } break; case CDIOCSETRIGHT: { ! struct cd_mode_data *data; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETRIGHT\n")); ! data = malloc(sizeof(struct cd_mode_data), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! data->page.audio.port[LEFT_PORT].channels = ! RIGHT_CHANNEL; ! data->page.audio.port[RIGHT_PORT].channels = ! RIGHT_CHANNEL; ! data->page.audio.port[2].channels = 0; ! data->page.audio.port[3].channels = 0; error = cdsetmode(periph, data); free(data, M_TEMP); } --- 2268,2466 ---- case CDIOCGETVOL: { struct ioc_vol *arg = (struct ioc_vol *) addr; ! struct cd_mode_params *data; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCGETVOL\n")); ! data = malloc(sizeof(struct cd_mode_params), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } + page = (data->cdb_size == 10) ? + &data->mode_data.mode_data_10.page : + &data->mode_data.mode_data_6.page; + arg->vol[LEFT_PORT] = ! page->audio.port[LEFT_PORT].volume; arg->vol[RIGHT_PORT] = ! page->audio.port[RIGHT_PORT].volume; ! arg->vol[2] = page->audio.port[2].volume; ! arg->vol[3] = page->audio.port[3].volume; free(data, M_TEMP); } break; case CDIOCSETVOL: { struct ioc_vol *arg = (struct ioc_vol *) addr; ! struct cd_mode_params *data; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETVOL\n")); ! data = malloc(sizeof(struct cd_mode_params), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! page = (data->cdb_size == 10) ? ! &data->mode_data.mode_data_10.page : ! &data->mode_data.mode_data_6.page; ! ! page->audio.port[LEFT_PORT].channels = CHANNEL_0; ! page->audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT]; ! page->audio.port[RIGHT_PORT].channels = CHANNEL_1; ! page->audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT]; ! page->audio.port[2].volume = arg->vol[2]; ! page->audio.port[3].volume = arg->vol[3]; error = cdsetmode(periph, data); free(data, M_TEMP); } break; case CDIOCSETMONO: { ! struct cd_mode_params *data; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETMONO\n")); ! data = malloc(sizeof(struct cd_mode_params), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! page = (data->cdb_size == 10) ? ! &data->mode_data.mode_data_10.page : ! &data->mode_data.mode_data_6.page; ! ! page->audio.port[LEFT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL; ! page->audio.port[RIGHT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL; ! page->audio.port[2].channels = 0; ! page->audio.port[3].channels = 0; error = cdsetmode(periph, data); free(data, M_TEMP); } break; case CDIOCSETSTEREO: { ! struct cd_mode_params *data; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETSTEREO\n")); ! data = malloc(sizeof(struct cd_mode_params), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! page = (data->cdb_size == 10) ? ! &data->mode_data.mode_data_10.page : ! &data->mode_data.mode_data_6.page; ! ! page->audio.port[LEFT_PORT].channels = LEFT_CHANNEL; ! page->audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; ! page->audio.port[2].channels = 0; ! page->audio.port[3].channels = 0; error = cdsetmode(periph, data); free(data, M_TEMP); } break; case CDIOCSETMUTE: { ! struct cd_mode_params *data; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETMUTE\n")); ! data = malloc(sizeof(struct cd_mode_params), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! page = (data->cdb_size == 10) ? ! &data->mode_data.mode_data_10.page : ! &data->mode_data.mode_data_6.page; ! ! page->audio.port[LEFT_PORT].channels = 0; ! page->audio.port[RIGHT_PORT].channels = 0; ! page->audio.port[2].channels = 0; ! page->audio.port[3].channels = 0; error = cdsetmode(periph, data); free(data, M_TEMP); } break; case CDIOCSETLEFT: { ! struct cd_mode_params *data; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETLEFT\n")); ! data = malloc(sizeof(struct cd_mode_params), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! page = (data->cdb_size == 10) ? ! &data->mode_data.mode_data_10.page : ! &data->mode_data.mode_data_6.page; ! ! page->audio.port[LEFT_PORT].channels = LEFT_CHANNEL; ! page->audio.port[RIGHT_PORT].channels = LEFT_CHANNEL; ! page->audio.port[2].channels = 0; ! page->audio.port[3].channels = 0; error = cdsetmode(periph, data); free(data, M_TEMP); } break; case CDIOCSETRIGHT: { ! struct cd_mode_params *data; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETRIGHT\n")); ! data = malloc(sizeof(struct cd_mode_params), M_TEMP, M_WAITOK); error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { free(data, M_TEMP); break; } ! page = (data->cdb_size == 10) ? ! &data->mode_data.mode_data_10.page : ! &data->mode_data.mode_data_6.page; ! ! page->audio.port[LEFT_PORT].channels = RIGHT_CHANNEL; ! page->audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; ! page->audio.port[2].channels = 0; ! page->audio.port[3].channels = 0; error = cdsetmode(periph, data); free(data, M_TEMP); } *************** *** 2648,2661 **** --- 2703,2833 ---- } static int + cd6byteworkaround(union ccb *ccb) + { + u_int8_t *cdb; + struct cam_periph *periph; + struct cd_softc *softc; + struct cd_mode_params *params; + int frozen, len; + + periph = xpt_path_periph(ccb->ccb_h.path); + softc = (struct cd_softc *)periph->softc; + + cdb = ccb->csio.cdb_io.cdb_bytes; + + if ((ccb->ccb_h.flags & CAM_CDB_POINTER) + || ((cdb[0] != MODE_SENSE_6) + && (cdb[0] != MODE_SELECT_6))) + return (0); + + /* + * Because there is no other convenient place to stash the overall + * cd_mode_params structure pointer, we have to grab it like this. + * This means that ALL MODE_SENSE and MODE_SELECT requests in the + * cd(4) driver MUST go through cdgetmode() and cdsetmode()! + */ + params = (struct cd_mode_params *)(ccb->csio.data_ptr - + __offsetof(struct cd_mode_params, mode_data)); + + params->cdb_size = 10; + len = sizeof(params->mode_data.mode_data_10); + ccb->csio.dxfer_len = len; + softc->minimum_command_size = 10; + xpt_print_path(ccb->ccb_h.path); + printf("MODE_SENSE(6)/MODE_SELECT(6) failed, increasing " + "minimum CDB size to 10 bytes\n"); + /* XXX KDM remove this */ + printf("CAM Status %#x\n", ccb->ccb_h.status); + printf("SCSI Status %#x\n", ccb->csio.scsi_status); + scsi_sense_print(&ccb->csio); + + if (cdb[0] == MODE_SENSE_6) { + struct scsi_mode_sense_10 ms10; + struct scsi_mode_sense_6 *ms6; + + ms6 = (struct scsi_mode_sense_6 *)cdb; + + bzero(&ms10, sizeof(ms10)); + /* first 3 bytes are the same */ + bcopy(ms6, &ms10, 3); + + scsi_ulto2b(len, ms10.length); + ms10.control = ms6->control; + } else { + struct scsi_mode_select_10 ms10; + struct scsi_mode_select_6 *ms6; + struct cd_mode_data_10 *mode_data_10; + struct cd_mode_data *mode_data_6; + + ms6 = (struct scsi_mode_select_6 *)cdb; + + bzero(&ms10, sizeof(ms10)); + ms10.opcode = ms6->opcode; + ms10.byte2 = ms6->byte2; + + mode_data_10 = ¶ms->mode_data.mode_data_10; + mode_data_6 = ¶ms->mode_data.mode_data_6; + + /* + * Since the 6 byte parameter header is shorter than the 10 + * byte parameter header, we need to copy the actual mode + * page data, so it winds up in the right place. The + * regions will overlap, but bcopy() does the right thing. + */ + bcopy(&mode_data_6->page, &mode_data_10->page, + sizeof(mode_data_10->page)); + + /* Make sure these fields are set correctly. */ + scsi_ulto2b(0, mode_data_10->header.data_length); + mode_data_10->header.medium_type = 0; + + scsi_ulto2b(len, ms10.length); + ms10.control = ms6->control; + } + + frozen = (ccb->ccb_h.status & CAM_DEV_QFRZN) != 0; + ccb->ccb_h.status = CAM_REQUEUE_REQ; + xpt_action(ccb); + if (frozen) { + cam_release_devq(ccb->ccb_h.path, + /*relsim_flags*/0, + /*openings*/0, + /*timeout*/0, + /*getcount_only*/0); + } + + return (ERESTART); + } + + static int cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) { struct cd_softc *softc; struct cam_periph *periph; + int error; periph = xpt_path_periph(ccb->ccb_h.path); softc = (struct cd_softc *)periph->softc; + error = 0; + + if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) + && (ccb->ccb_h.status & CAM_AUTOSNS_VALID) + && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) + && ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0) + && ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) { + int sense_key, error_code, asc, ascq; + + scsi_extract_sense(&ccb->csio.sense_data, + &error_code, &sense_key, &asc, &ascq); + if (sense_key == SSD_KEY_ILLEGAL_REQUEST) + error = cd6byteworkaround(ccb); + } + + if (error == ERESTART) + return (error); + /* * XXX * Until we have a better way of doing pack validation, *************** *** 2765,2800 **** } static int ! cdgetmode(struct cam_periph *periph, struct cd_mode_data *data, u_int32_t page) { ! struct scsi_mode_sense_6 *scsi_cmd; ! struct ccb_scsiio *csio; union ccb *ccb; int error; ccb = cdgetccb(periph, /* priority */ 1); csio = &ccb->csio; bzero(data, sizeof(*data)); ! cam_fill_csio(csio, ! /* retries */ 1, ! /* cbfcnp */ cddone, ! /* flags */ CAM_DIR_IN, ! /* tag_action */ MSG_SIMPLE_Q_TAG, ! /* data_ptr */ (u_int8_t *)data, ! /* dxfer_len */ sizeof(*data), ! /* sense_len */ SSD_FULL_SIZE, ! sizeof(struct scsi_mode_sense_6), ! /* timeout */ 50000); ! scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes; ! bzero (scsi_cmd, sizeof(*scsi_cmd)); ! scsi_cmd->page = page; ! scsi_cmd->length = sizeof(*data) & 0xff; ! scsi_cmd->opcode = MODE_SENSE; error = cdrunccb(ccb, cderror, /*cam_flags*/0, /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); --- 2937,2986 ---- } + /* + * All MODE_SENSE requests in the cd(4) driver MUST go through this + * routine. See comments in cd6byteworkaround() for details. + */ static int ! cdgetmode(struct cam_periph *periph, struct cd_mode_params *data, ! u_int32_t page) { ! struct ccb_scsiio *csio; ! struct cd_softc *softc; union ccb *ccb; + int param_len; int error; + softc = (struct cd_softc *)periph->softc; + ccb = cdgetccb(periph, /* priority */ 1); csio = &ccb->csio; bzero(data, sizeof(*data)); ! data->cdb_size = softc->minimum_command_size; ! if (data->cdb_size < 10) ! param_len = sizeof(data->mode_data.mode_data_6); ! else ! param_len = sizeof(data->mode_data.mode_data_10); ! scsi_mode_sense_len(csio, ! /* retries */ 1, ! /* cbfcnp */ cddone, ! /* tag_action */ MSG_SIMPLE_Q_TAG, ! /* dbd */ 0, ! /* page_code */ SMS_PAGE_CTRL_CURRENT, ! /* page */ page, ! /* param_buf */ (u_int8_t *)&data->mode_data, ! /* param_len */ param_len, ! /* minimum_cmd_size */ softc->minimum_command_size, ! /* sense_len */ SSD_FULL_SIZE, ! /* timeout */ 50000); ! /* ! * Save this so we can pull it out and reformat if necessary. ! */ ! /* csio->ccb_h.periph_priv.entries[0].ptr = data; */ error = cdrunccb(ccb, cderror, /*cam_flags*/0, /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); *************** *** 2804,2847 **** return(error); } static int ! cdsetmode(struct cam_periph *periph, struct cd_mode_data *data) { ! struct scsi_mode_select_6 *scsi_cmd; ! struct ccb_scsiio *csio; union ccb *ccb; int error; ccb = cdgetccb(periph, /* priority */ 1); csio = &ccb->csio; error = 0; ! cam_fill_csio(csio, ! /* retries */ 1, ! /* cbfcnp */ cddone, ! /* flags */ CAM_DIR_OUT, ! /* tag_action */ MSG_SIMPLE_Q_TAG, ! /* data_ptr */ (u_int8_t *)data, ! /* dxfer_len */ sizeof(*data), ! /* sense_len */ SSD_FULL_SIZE, ! sizeof(struct scsi_mode_select_6), ! /* timeout */ 50000); ! scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes; ! bzero(scsi_cmd, sizeof(*scsi_cmd)); ! scsi_cmd->opcode = MODE_SELECT; ! scsi_cmd->byte2 |= SMS_PF; ! scsi_cmd->length = sizeof(*data) & 0xff; ! data->header.data_length = 0; ! /* ! * SONY drives do not allow a mode select with a medium_type ! * value that has just been returned by a mode sense; use a ! * medium_type of 0 (Default) instead. */ ! data->header.medium_type = 0; error = cdrunccb(ccb, cderror, /*cam_flags*/0, /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); --- 2990,3070 ---- return(error); } + /* + * All MODE_SELECT requests in the cd(4) driver MUST go through this + * routine. See comments in cd6byteworkaround() for details. + */ static int ! cdsetmode(struct cam_periph *periph, struct cd_mode_params *data) { ! struct ccb_scsiio *csio; ! struct cd_softc *softc; union ccb *ccb; + int cdb_size, param_len; int error; + softc = (struct cd_softc *)periph->softc; + ccb = cdgetccb(periph, /* priority */ 1); csio = &ccb->csio; error = 0; ! /* ! * If the data is formatted for the 10 byte version of the mode ! * select parameter list, we need to use the 10 byte CDB. ! * Otherwise, we use whatever the stored minimum command size. ! */ ! if (data->cdb_size == 10) ! cdb_size = data->cdb_size; ! else ! cdb_size = softc->minimum_command_size; ! if (cdb_size >= 10) { ! struct cd_mode_data_10 *mode_data; ! mode_data = &data->mode_data.mode_data_10; ! ! scsi_ulto2b(0, mode_data->header.data_length); ! /* ! * SONY drives do not allow a mode select with a medium_type ! * value that has just been returned by a mode sense; use a ! * medium_type of 0 (Default) instead. ! */ ! mode_data->header.medium_type = 0; ! param_len = sizeof(*mode_data); ! } else { ! struct cd_mode_data *mode_data; ! ! mode_data = &data->mode_data.mode_data_6; ! ! mode_data->header.data_length = 0; ! /* ! * SONY drives do not allow a mode select with a medium_type ! * value that has just been returned by a mode sense; use a ! * medium_type of 0 (Default) instead. ! */ ! mode_data->header.medium_type = 0; ! param_len = sizeof(*mode_data); ! } ! ! scsi_mode_select_len(csio, ! /* retries */ 1, ! /* cbfcnp */ cddone, ! /* tag_action */ MSG_SIMPLE_Q_TAG, ! /* scsi_page_fmt */ 1, ! /* save_pages */ 0, ! /* param_buf */ (u_int8_t *)&data->mode_data, ! /* param_len */ param_len, ! /* minimum_cmd_size */ cdb_size, ! /* sense_len */ SSD_FULL_SIZE, ! /* timeout */ 50000); ! ! /* ! * Save this so we can pull it out and reformat if necessary. */ ! /* csio->ccb_h.periph_priv.entries[0].ptr = data; */ error = cdrunccb(ccb, cderror, /*cam_flags*/0, /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); ==== //depot/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.h#1 - /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.h ==== *** /tmp/tmp.6985.3 Sat Nov 2 18:52:40 2002 --- /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.h Sat Oct 26 23:45:50 2002 *************** *** 679,689 **** --- 679,708 ---- }audio; }; + struct cd_mode_data_10 + { + struct scsi_mode_header_10 header; + struct scsi_mode_blk_desc blk_desc; + union cd_pages page; + }; + struct cd_mode_data { struct scsi_mode_header_6 header; struct scsi_mode_blk_desc blk_desc; union cd_pages page; + }; + + union cd_mode_data_6_10 + { + struct cd_mode_data mode_data_6; + struct cd_mode_data_10 mode_data_10; + }; + + struct cd_mode_params + { + int cdb_size; + union cd_mode_data_6_10 mode_data; }; __BEGIN_DECLS --h31gzZEtNLTqOjlF-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-firewire" in the body of the message