Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 27 Oct 2002 00:12:38 -0600
From:      "Kenneth D. Merry" <ken@kdm.org>
To:        Hidetoshi Shimokawa <simokawa@sat.t.u-tokyo.ac.jp>
Cc:        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:  <20021027001238.A76092@panzer.kdm.org>
In-Reply-To: <ybs1y6esb8n.wl@ett.sat.t.u-tokyo.ac.jp>; from simokawa@sat.t.u-tokyo.ac.jp on Sat, Oct 26, 2002 at 02:02:16AM %2B0900
References:  <ybs4rbasjfn.wl@ett.sat.t.u-tokyo.ac.jp> <20021025184837.C227-100000@localhost> <ybs1y6esb8n.wl@ett.sat.t.u-tokyo.ac.jp>

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

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

On Sat, Oct 26, 2002 at 02:02:16 +0900, Hidetoshi Shimokawa wrote:
> At Fri, 25 Oct 2002 18:50:20 +0400 (MSD),
> Dmitry Mottl wrote:
> > 
> > On Fri, 25 Oct 2002, Hidetoshi Shimokawa wrote:
> > 
> > > Did you really do `make install'?
> > Certainly
> > >
> > > I put the latest version at
> > > http://people.freebsd.org/~simokawa/firewire-20021025.tar.gz
> > The same result.  :(
> 
> O.K. I understand the problem.
> 
> Please note that the patch worked somehow. Without the patch,
> the MODE_SENSE(6) failed with "Invalid command operation code", on
> the other hand, with the patch, MODE_SELECT(6) (which is actually
> transformed to MODE_SELECT(10)) failed with 'Invalid field in
> parameter list'.
> 
> This is because MODE_SENSE/SELECT(6) and MODE_SENSE/SELECT(10) use
> different scsi_mode_header6/10(see scsi_all.h) and their parameter
> list aren't compatible. This is out of the scope of the patch.
> I think umass has same problem.

Oops, you're right.  It'll cause weird problems with mode sense and mode
select, definitely.  We should probably just take out the mode sense and
mode select translation code in umass, since I don't think there's a good
way to do translation at the SIM layer for either command.

> I don't have any quick solution.
> Maybe, we have to wait for CAM_NEW_TRAN_CODE.
> 
> (If your dvd drive is the only cd drive connected to your machine,
> you can hack the scsi_cd.c to use 10 bytes command.)

I've attached a patch that should work.  I've tested this with a SCSI
CDROM, but obviously it doesn't exhibit the same behavior.

Can you shed some light on what sort of drive this is?  Is this a
SCSI-over-firewire device, or is it on an ATAPI converter, or what?  i.e.
any clues on why it is rejecting 6 byte commands?

This patch isn't in its final form, and definitely needs to be
reviewed/tested.  Unfortunately, due to the problems that Shimokawa-san
pointed out with mode sense/select, doing translation down in the SIM layer
isn't going to work -- it has to be done in the peripheral driver, at least
for mode sense and mode select.  (The reason is that the peripheral driver
can know whether or not it can increase the length of the parameter list,
which is needed to switch from a 6 byte to a 10 byte command.  The SIM
driver won't know, and so it can't really do anything.)

This patch is also a little more hackish than I would like.  Doing things
via the CAM_NEW_TRAN_CODE approach is definitely the right thing to do.

Make sure you aren't using the patch Shimokawa-san gave you to translate
commands when you try this patch.

Ken
-- 
Kenneth Merry
ken@kdm.org

--/04w6evG8XlLl3ft
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="scsi_cd.cmdsize.20021026"

==== //depot/FreeBSD-ken/src/sys/cam/scsi/scsi_all.c#22 - /usr/home/ken/perforce/FreeBSD-ken/src/sys/cam/scsi/scsi_all.c ====
*** /tmp/tmp.331.0	Sat Oct 26 23:35:11 2002
--- /usr/home/ken/perforce/FreeBSD-ken/src/sys/cam/scsi/scsi_all.c	Thu Oct 17 23:19:51 2002
***************
*** 2447,2458 ****
  		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.
  		 */
--- 2447,2470 ----
  		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.
  		 */
***************
*** 2500,2511 ****
  		 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.
  		 */
--- 2512,2537 ----
  		 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/src/sys/cam/scsi/scsi_all.h#11 - /usr/home/ken/perforce/FreeBSD-ken/src/sys/cam/scsi/scsi_all.h ====
*** /tmp/tmp.331.1	Sat Oct 26 23:35:11 2002
--- /usr/home/ken/perforce/FreeBSD-ken/src/sys/cam/scsi/scsi_all.h	Thu Oct 17 23:19:51 2002
***************
*** 926,931 ****
--- 926,940 ----
  				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 *),
***************
*** 933,938 ****
--- 942,955 ----
  				 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_log_sense(struct ccb_scsiio *csio, u_int32_t retries,
  			       void (*cbfcnp)(struct cam_periph *, union ccb *),
==== //depot/FreeBSD-ken/src/sys/cam/scsi/scsi_cd.c#28 - /usr/home/ken/perforce/FreeBSD-ken/src/sys/cam/scsi/scsi_cd.c ====
*** /tmp/tmp.331.2	Sat Oct 26 23:35:11 2002
--- /usr/home/ken/perforce/FreeBSD-ken/src/sys/cam/scsi/scsi_cd.c	Sat Oct 26 23:27:15 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
***************
*** 137,142 ****
--- 137,143 ----
  	struct cam_periph	*periph;
  	dev_t			dev;
  	eventhandler_tag	clonetag;
+ 	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);
***************
*** 211,219 ****
  				  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, 
--- 213,221 ----
  				  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, 
***************
*** 609,614 ****
--- 611,618 ----
  	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
***************
*** 1785,1793 ****
  		{
  			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, 
--- 1789,1798 ----
  		{
  			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, 
***************
*** 1798,1805 ****
  				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)
--- 1803,1814 ----
  				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)
***************
*** 1819,1827 ****
  		{
  			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, 
--- 1828,1837 ----
  		{
  			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, 
***************
*** 1832,1839 ****
  				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)
--- 1842,1853 ----
  				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)
***************
*** 1851,1862 ****
  		{
  			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);
--- 1865,1877 ----
  		{
  			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);
***************
*** 1864,1871 ****
  				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)
--- 1879,1890 ----
  				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)
***************
*** 2158,2181 ****
  	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);
  		}
--- 2177,2205 ----
  	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);
  		}
***************
*** 2183,2350 ****
  	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);
  		}
--- 2207,2405 ----
  	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);
  		}
***************
*** 2521,2534 ****
--- 2576,2702 ----
  }
  
  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");
+ 
+ 	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 = &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,
***************
*** 2638,2673 ****
  }
  
  
  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*/CAM_RETRY_SELTO,
  			 /*sense_flags*/SF_RETRY_UA);
--- 2806,2855 ----
  }
  
  
+ /*
+  * 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*/CAM_RETRY_SELTO,
  			 /*sense_flags*/SF_RETRY_UA);
***************
*** 2677,2720 ****
  	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*/CAM_RETRY_SELTO,
  			 /*sense_flags*/SF_RETRY_UA);
--- 2859,2939 ----
  	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*/CAM_RETRY_SELTO,
  			 /*sense_flags*/SF_RETRY_UA);
==== //depot/FreeBSD-ken/src/sys/cam/scsi/scsi_cd.h#5 - /usr/home/ken/perforce/FreeBSD-ken/src/sys/cam/scsi/scsi_cd.h ====
*** /tmp/tmp.331.3	Sat Oct 26 23:35:11 2002
--- /usr/home/ken/perforce/FreeBSD-ken/src/sys/cam/scsi/scsi_cd.h	Sat Oct 26 21:20:13 2002
***************
*** 689,699 ****
--- 689,718 ----
  	}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

--/04w6evG8XlLl3ft--

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




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