Date: Mon, 4 Nov 2002 21:03:48 -0700 From: "Kenneth D. Merry" <ken@kdm.org> To: Hidetoshi Shimokawa <simokawa@sat.t.u-tokyo.ac.jp> Cc: David Kleiner <kleiner@panix.com>, Dmitry Mottl <dima@sinp.msu.ru>, freebsd-firewire@FreeBSD.ORG, freebsd-scsi@FreeBSD.ORG Subject: Re: VAIO Firewire dock station with DVD-ROM Message-ID: <20021104210348.A41448@panzer.kdm.org> In-Reply-To: <ybs1y60loxq.wl@ett.sat.t.u-tokyo.ac.jp>; from simokawa@sat.t.u-tokyo.ac.jp on Tue, Nov 05, 2002 at 11:40:01AM %2B0900 References: <ybs4rbasjfn.wl@ett.sat.t.u-tokyo.ac.jp> <20021025184837.C227-100000@localhost> <ybs1y6esb8n.wl@ett.sat.t.u-tokyo.ac.jp> <20021104073302.GA27648@panix.com> <ybs1y60loxq.wl@ett.sat.t.u-tokyo.ac.jp>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
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
[-- Attachment #2 --]
==== //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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20021104210348.A41448>
