Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Nov 2002 23:18:25 -0700
From:      "Kenneth D. Merry" <ken@kdm.org>
To:        David Kleiner <kleiner@panix.com>
Cc:        Hidetoshi Shimokawa <simokawa@sat.t.u-tokyo.ac.jp>, 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:  <20021104231825.A42046@panzer.kdm.org>
In-Reply-To: <20021105060143.GA24764@panix.com>; from kleiner@panix.com on Tue, Nov 05, 2002 at 01:01:43AM -0500
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> <20021104210348.A41448@panzer.kdm.org> <20021105060143.GA24764@panix.com>

next in thread | previous in thread | raw e-mail | index | archive | help

--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Tue, Nov 05, 2002 at 01:01:43 -0500, David Kleiner wrote:
> On Mon, Nov 04, 2002 at 09:03:48PM -0700, Kenneth D. Merry wrote:
> > 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
> 
> Ken,
> 
> I had applied your patch and rebuilt kernel - when I tried
> cdcontrol/cdplay, I got this streaming messages below (very 
> chatty).  CD didn't play, system eventually crashed, unfortunately,
> I don't have the dump.

It looks like that's the result of a brain-o.  I forgot to change the
opcode.

I've attached a new patch.  It still has extra debugging output, in case
something doesn't work right.

Ken
-- 
Kenneth Merry
ken@kdm.org

--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="scsi_cd.cmdsize.stable.20021104"

==== //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.2056.0	Mon Nov  4 23:16:22 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.2056.1	Mon Nov  4 23:16:22 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.2056.2	Mon Nov  4 23:16:22 2002
--- /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.c	Mon Nov  4 23:14:34 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,2834 ----
  }
  
  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));
+ 		ms10.opcode = MODE_SENSE_10;
+ 		ms10.byte2 = ms6->byte2;
+ 		ms10.page = ms6->page;
+ 
+ 		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 = MODE_SELECT_10;
+ 		ms10.byte2 = ms6->byte2;
+ 
+ 		mode_data_10 = &params->mode_data.mode_data_10;
+ 		mode_data_6 = &params->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);
--- 2938,2987 ----
  }
  
  
+ /*
+  * 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);
--- 2991,3071 ----
  	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.2056.3	Mon Nov  4 23:16:22 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

--X1bOJ3K7DJ5YkBrT--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-scsi" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20021104231825.A42046>