==== //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.17105.0 Fri Nov 22 22:38:19 2002 --- /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_all.c Fri Nov 22 22:07:52 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.17105.1 Fri Nov 22 22:38:19 2002 --- /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_all.h Fri Nov 22 22:07:52 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#7 - /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.c ==== *** /tmp/tmp.17105.2 Fri Nov 22 22:38:19 2002 --- /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.c Fri Nov 22 22:19:40 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,156 ---- struct cdchanger *changer; int bufs_left; struct cam_periph *periph; + int minimum_command_size; + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; + STAILQ_HEAD(, cd_mode_params) mode_queue; + }; + + struct cd_page_sizes { + int page; + int page_size; + }; + + static struct cd_page_sizes cd_page_size_table[] = + { + { AUDIO_PAGE, sizeof(struct cd_audio_page)} }; struct cd_quirk_entry { *************** *** 191,196 **** --- 205,211 ---- static periph_oninv_t cdoninvalidate; static void cdasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg); + static int cdcmdsizesysctl(SYSCTL_HANDLER_ARGS); static void cdshorttimeout(void *arg); static void cdschedule(struct cam_periph *periph, int priority); static void cdrunchangerqueue(void *arg); *************** *** 200,221 **** u_int32_t cam_flags, u_int32_t sense_flags), u_int32_t cam_flags, u_int32_t sense_flags); ! static union ccb *cdgetccb(struct cam_periph *periph, u_int32_t priority); static void cddone(struct cam_periph *periph, union ccb *start_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); static int cdsize(dev_t dev, u_int32_t *size); static int cdfirsttrackisdata(struct cam_periph *periph); static int cdreadtoc(struct cam_periph *periph, u_int32_t mode, 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, --- 215,239 ---- u_int32_t cam_flags, u_int32_t sense_flags), u_int32_t cam_flags, u_int32_t sense_flags); ! static union ccb *cdgetccb(struct cam_periph *periph, u_int32_t priority); static void cddone(struct cam_periph *periph, union ccb *start_ccb); ! static union cd_pages *cdgetpage(struct cd_mode_params *mode_params); ! static int cdgetpagesize(int page_num); static void cdprevent(struct cam_periph *periph, int action); static int cdsize(dev_t dev, u_int32_t *size); + static int cd6byteworkaround(union ccb *ccb); + static int cderror(union ccb *ccb, u_int32_t cam_flags, + u_int32_t sense_flags); static int cdfirsttrackisdata(struct cam_periph *periph); static int cdreadtoc(struct cam_periph *periph, u_int32_t mode, 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, *************** *** 294,301 **** --- 312,321 ---- SYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0, "CD Changer"); SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW, &changer_min_busy_seconds, 0, "Minimum changer scheduling quantum"); + TUNABLE_INT("kern.cam.cd.changer.min_busy_seconds", &changer_min_busy_seconds); SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, max_busy_seconds, CTLFLAG_RW, &changer_max_busy_seconds, 0, "Maximum changer scheduling quantum"); + TUNABLE_INT("kern.cam.cd.changer.max_busy_seconds", &changer_max_busy_seconds); struct cdchanger { path_id_t path_id; *************** *** 564,575 **** --- 584,633 ---- } } + /* + * We have a handler function for this so we can check the values when the + * user sets them, instead of every time we look at them. + */ + static int + cdcmdsizesysctl(SYSCTL_HANDLER_ARGS) + { + int error, value; + + value = *(int *)arg1; + + error = sysctl_handle_int(oidp, &value, 0, req); + + if ((error != 0) + || (req->newptr == NULL)) + return (error); + + /* + * The only real values we can have here are 6 or 10. I don't + * really forsee having 12 be an option at any time in the future. + * So if the user sets something less than or equal to 6, we'll set + * it to 6. If he sets something greater than 6, we'll set it to 10. + * + * I suppose we could just return an error here for the wrong values, + * but I don't think it's necessary to do so, as long as we can + * determine the user's intent without too much trouble. + */ + if (value < 6) + value = 6; + else if (value > 6) + value = 10; + + *(int *)arg1 = value; + + return (0); + } + static cam_status cdregister(struct cam_periph *periph, void *arg) { struct cd_softc *softc; struct ccb_setasync csa; struct ccb_getdev *cgd; + char tmpstr[80], tmpstr2[80]; caddr_t match; cgd = (struct ccb_getdev *)arg; *************** *** 592,597 **** --- 650,656 ---- bzero(softc, sizeof(*softc)); LIST_INIT(&softc->pending_ccbs); + STAILQ_INIT(&softc->mode_queue); softc->state = CD_STATE_PROBE; bufq_init(&softc->buf_queue); if (SID_IS_REMOVABLE(&cgd->inq_data)) *************** *** 617,622 **** --- 676,717 ---- else softc->quirks = CD_Q_NONE; + snprintf(tmpstr, sizeof(tmpstr), "CAM CD unit %d", periph->unit_number); + snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); + softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_kern_cam_cd), OID_AUTO, + tmpstr2, CTLFLAG_RD, 0, tmpstr); + if (softc->sysctl_tree == NULL) { + printf("cdregister: unable to allocate sysctl tree\n"); + free(softc, M_DEVBUF); + return (CAM_REQ_CMP_ERR); + } + + /* The default is 6 byte commands */ + softc->minimum_command_size = 6; + + /* + * Load the user's default, if any. + */ + snprintf(tmpstr, sizeof(tmpstr), "kern.cam.cd.%d.minimum_cmd_size", + periph->unit_number); + TUNABLE_INT_FETCH(tmpstr, &softc->minimum_command_size); + + /* 6 and 10 are the only permissible values here. */ + if (softc->minimum_command_size < 6) + softc->minimum_command_size = 6; + else if (softc->minimum_command_size > 6) + softc->minimum_command_size = 10; + + /* + * Now register the sysctl handler, so the user can the value on + * the fly. + */ + SYSCTL_ADD_PROC(&softc->sysctl_ctx,SYSCTL_CHILDREN(softc->sysctl_tree), + OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW, + &softc->minimum_command_size, 0, cdcmdsizesysctl, "I", + "Minimum CDB size"); + /* * We need to register the statistics structure for this device, * but we don't have the blocksize yet for it. So, we register *************** *** 1817,1822 **** --- 1912,1946 ---- xpt_release_ccb(done_ccb); } + static union cd_pages * + cdgetpage(struct cd_mode_params *mode_params) + { + union cd_pages *page; + + if (mode_params->cdb_size == 10) + page = (union cd_pages *)find_mode_page_10( + (struct scsi_mode_header_10 *)mode_params->mode_buf); + else + page = (union cd_pages *)find_mode_page_6( + (struct scsi_mode_header_6 *)mode_params->mode_buf); + + return (page); + } + + static int + cdgetpagesize(int page_num) + { + int i; + + for (i = 0; i < (sizeof(cd_page_size_table)/ + sizeof(cd_page_size_table[0])); i++) { + if (cd_page_size_table[i].page == page_num) + return (cd_page_size_table[i].page_size); + } + + return (-1); + } + static int cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { *************** *** 1849,1871 **** { 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, ("trying to do CDIOCPLAYTRACKS\n")); ! error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { ! 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) break; if (softc->quirks & CD_Q_BCD_TRACKS) { --- 1973,1999 ---- { struct ioc_play_track *args = (struct ioc_play_track *) addr; ! struct cd_mode_params params; ! union cd_pages *page; ! params.alloc_len = sizeof(union cd_mode_data_6_10); ! params.mode_buf = malloc(params.alloc_len, M_TEMP, ! M_WAITOK | M_ZERO); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCPLAYTRACKS\n")); ! error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { ! free(params.mode_buf, M_TEMP); break; } ! page = cdgetpage(¶ms); ! ! page->audio.flags &= ~CD_PA_SOTC; ! page->audio.flags |= CD_PA_IMMED; ! error = cdsetmode(periph, ¶ms); ! free(params.mode_buf, M_TEMP); if (error) break; if (softc->quirks & CD_Q_BCD_TRACKS) { *************** *** 1883,1905 **** { 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, ("trying to do CDIOCPLAYMSF\n")); ! error = cdgetmode(periph, data, AUDIO_PAGE); if (error) { ! 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) break; error = cdplaymsf(periph, --- 2011,2037 ---- { struct ioc_play_msf *args = (struct ioc_play_msf *) addr; ! struct cd_mode_params params; ! union cd_pages *page; ! params.alloc_len = sizeof(union cd_mode_data_6_10); ! params.mode_buf = malloc(params.alloc_len, M_TEMP, ! M_WAITOK | M_ZERO); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCPLAYMSF\n")); ! error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { ! free(params.mode_buf, M_TEMP); break; } ! page = cdgetpage(¶ms); ! ! page->audio.flags &= ~CD_PA_SOTC; ! page->audio.flags |= CD_PA_IMMED; ! error = cdsetmode(periph, ¶ms); ! free(params.mode_buf, M_TEMP); if (error) break; error = cdplaymsf(periph, *************** *** 1915,1937 **** { 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); if (error) { ! 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) break; error = cdplay(periph, args->blk, args->len); --- 2047,2073 ---- { struct ioc_play_blocks *args = (struct ioc_play_blocks *) addr; ! struct cd_mode_params params; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCPLAYBLOCKS\n")); ! params.alloc_len = sizeof(union cd_mode_data_6_10); ! params.mode_buf = malloc(params.alloc_len, M_TEMP, ! M_WAITOK | M_ZERO); ! error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { ! free(params.mode_buf, M_TEMP); break; } ! page = cdgetpage(¶ms); ! ! page->audio.flags &= ~CD_PA_SOTC; ! page->audio.flags |= CD_PA_IMMED; ! error = cdsetmode(periph, ¶ms); ! free(params.mode_buf, M_TEMP); if (error) break; error = cdplay(periph, args->blk, args->len); *************** *** 2221,2416 **** break; 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); } break; 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); } break; case CDIOCRESUME: --- 2357,2582 ---- break; case CDIOCSETPATCH: { ! struct ioc_patch *arg = (struct ioc_patch *)addr; ! struct cd_mode_params params; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETPATCH\n")); ! params.alloc_len = sizeof(union cd_mode_data_6_10); ! params.mode_buf = malloc(params.alloc_len, M_TEMP, ! M_WAITOK | M_ZERO); ! error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { ! free(params.mode_buf, M_TEMP); break; } ! page = cdgetpage(¶ms); ! ! 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, ¶ms); ! free(params.mode_buf, M_TEMP); } break; case CDIOCGETVOL: { struct ioc_vol *arg = (struct ioc_vol *) addr; ! struct cd_mode_params params; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCGETVOL\n")); ! params.alloc_len = sizeof(union cd_mode_data_6_10); ! params.mode_buf = malloc(params.alloc_len, M_TEMP, ! M_WAITOK | M_ZERO); ! error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { ! free(params.mode_buf, M_TEMP); break; } + page = cdgetpage(¶ms); + 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(params.mode_buf, M_TEMP); } break; case CDIOCSETVOL: { struct ioc_vol *arg = (struct ioc_vol *) addr; ! struct cd_mode_params params; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETVOL\n")); ! params.alloc_len = sizeof(union cd_mode_data_6_10); ! params.mode_buf = malloc(params.alloc_len, M_TEMP, ! M_WAITOK | M_ZERO); ! error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { ! free(params.mode_buf, M_TEMP); break; } ! page = cdgetpage(¶ms); ! ! 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, ¶ms); ! free(params.mode_buf, M_TEMP); } break; case CDIOCSETMONO: { ! struct cd_mode_params params; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETMONO\n")); ! params.alloc_len = sizeof(union cd_mode_data_6_10); ! params.mode_buf = malloc(params.alloc_len, M_TEMP, ! M_WAITOK | M_ZERO); ! error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { ! free(params.mode_buf, M_TEMP); break; } ! page = cdgetpage(¶ms); ! ! 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, ¶ms); ! free(params.mode_buf, M_TEMP); } break; case CDIOCSETSTEREO: { ! struct cd_mode_params params; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETSTEREO\n")); ! params.alloc_len = sizeof(union cd_mode_data_6_10); ! params.mode_buf = malloc(params.alloc_len, M_TEMP, ! M_WAITOK | M_ZERO); ! error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { ! free(params.mode_buf, M_TEMP); break; } ! page = cdgetpage(¶ms); ! ! 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, ¶ms); ! free(params.mode_buf, M_TEMP); } break; case CDIOCSETMUTE: { ! struct cd_mode_params params; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETMUTE\n")); ! params.alloc_len = sizeof(union cd_mode_data_6_10); ! params.mode_buf = malloc(params.alloc_len, M_TEMP, ! M_WAITOK | M_ZERO); ! error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { ! free(¶ms, M_TEMP); break; } ! page = cdgetpage(¶ms); ! ! 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, ¶ms); ! free(params.mode_buf, M_TEMP); } break; case CDIOCSETLEFT: { ! struct cd_mode_params params; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETLEFT\n")); ! params.alloc_len = sizeof(union cd_mode_data_6_10); ! params.mode_buf = malloc(params.alloc_len, M_TEMP, ! M_WAITOK | M_ZERO); ! ! error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { ! free(params.mode_buf, M_TEMP); break; } ! page = cdgetpage(¶ms); ! ! 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, ¶ms); ! free(params.mode_buf, M_TEMP); } break; case CDIOCSETRIGHT: { ! struct cd_mode_params params; ! union cd_pages *page; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETRIGHT\n")); ! params.alloc_len = sizeof(union cd_mode_data_6_10); ! params.mode_buf = malloc(params.alloc_len, M_TEMP, ! M_WAITOK | M_ZERO); ! ! error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { ! free(params.mode_buf, M_TEMP); break; } ! page = cdgetpage(¶ms); ! ! 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, ¶ms); ! free(params.mode_buf, M_TEMP); } break; case CDIOCRESUME: *************** *** 2657,2670 **** --- 2823,3012 ---- } 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, found; + + 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 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()! + * + * XXX It would be nice if, at some point, we could increase the + * number of available peripheral private pointers. Both pointers + * are currently used in most every peripheral driver. + */ + found = 0; + + STAILQ_FOREACH(params, &softc->mode_queue, links) { + if (params->mode_buf == ccb->csio.data_ptr) { + found = 1; + break; + } + } + + /* + * This shouldn't happen. All mode sense and mode select + * operations in the cd(4) driver MUST go through cdgetmode() and + * cdsetmode()! + */ + if (found == 0) { + xpt_print_path(periph->path); + printf("mode buffer not found in mode queue!\n"); + return (0); + } + + params->cdb_size = 10; + softc->minimum_command_size = 10; + xpt_print_path(ccb->ccb_h.path); + printf("%s(6) failed, increasing minimum CDB size to 10 bytes\n", + (cdb[0] == MODE_SENSE_6) ? "MODE_SENSE" : "MODE_SELECT"); + + if (cdb[0] == MODE_SENSE_6) { + struct scsi_mode_sense_10 ms10; + struct scsi_mode_sense_6 *ms6; + int len; + + ms6 = (struct scsi_mode_sense_6 *)cdb; + + bzero(&ms10, sizeof(ms10)); + ms10.opcode = MODE_SENSE_10; + ms10.byte2 = ms6->byte2; + ms10.page = ms6->page; + + /* + * 10 byte mode header, block descriptor, + * sizeof(union cd_pages) + */ + len = sizeof(struct cd_mode_data_10); + ccb->csio.dxfer_len = len; + + scsi_ulto2b(len, ms10.length); + ms10.control = ms6->control; + bcopy(&ms10, cdb, 10); + ccb->csio.cdb_len = 10; + } else { + struct scsi_mode_select_10 ms10; + struct scsi_mode_select_6 *ms6; + struct scsi_mode_header_6 *header6; + struct scsi_mode_header_10 *header10; + struct scsi_mode_page_header *page_header; + int blk_desc_len, page_num, page_size, len; + + ms6 = (struct scsi_mode_select_6 *)cdb; + + bzero(&ms10, sizeof(ms10)); + ms10.opcode = MODE_SELECT_10; + ms10.byte2 = ms6->byte2; + + header6 = (struct scsi_mode_header_6 *)params->mode_buf; + header10 = (struct scsi_mode_header_10 *)params->mode_buf; + + page_header = find_mode_page_6(header6); + page_num = page_header->page_code; + + blk_desc_len = header6->blk_desc_len; + + page_size = cdgetpagesize(page_num); + + if (page_size != (page_header->page_length + + sizeof(*page_header))) + page_size = page_header->page_length + + sizeof(*page_header); + + len = sizeof(*header10) + blk_desc_len + page_size; + + len = min(params->alloc_len, len); + + /* + * Since the 6 byte parameter header is shorter than the 10 + * byte parameter header, we need to copy the actual mode + * page data, and the block descriptor, if any, so things wind + * up in the right place. The regions will overlap, but + * bcopy() does the right thing. + */ + bcopy(params->mode_buf + sizeof(*header6), + params->mode_buf + sizeof(*header10), + len - sizeof(*header10)); + + /* Make sure these fields are set correctly. */ + scsi_ulto2b(0, header10->data_length); + header10->medium_type = 0; + scsi_ulto2b(blk_desc_len, header10->blk_desc_len); + + ccb->csio.dxfer_len = len; + + scsi_ulto2b(len, ms10.length); + ms10.control = ms6->control; + bcopy(&ms10, cdb, 10); + ccb->csio.cdb_len = 10; + } + + 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; + + /* + * We use a status of CAM_REQ_INVALID as shorthand -- if a 6 byte + * CDB comes back with this particular error, try transforming it + * into the 10 byte version. + */ + if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) { + error = cd6byteworkaround(ccb); + } else 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, *************** *** 2774,2863 **** } 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); xpt_release_ccb(ccb); ! 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); xpt_release_ccb(ccb); ! return(error); } --- 3116,3317 ---- } + /* + * 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; ! data->cdb_size = softc->minimum_command_size; ! if (data->cdb_size < 10) ! param_len = sizeof(struct cd_mode_data); ! else ! param_len = sizeof(struct cd_mode_data_10); ! /* Don't say we've got more room than we actually allocated */ ! param_len = min(param_len, data->alloc_len); ! 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 */ data->mode_buf, ! /* param_len */ param_len, ! /* minimum_cmd_size */ softc->minimum_command_size, ! /* sense_len */ SSD_FULL_SIZE, ! /* timeout */ 50000); ! ! /* ! * It would be nice not to have to do this, but there's no ! * available pointer in the CCB that would allow us to stuff the ! * mode params structure in there and retrieve it in ! * cd6byteworkaround(), so we can set the cdb size. The cdb size ! * lets the caller know what CDB size we ended up using, so they ! * can find the actual mode page offset. ! */ ! STAILQ_INSERT_TAIL(&softc->mode_queue, data, links); error = cdrunccb(ccb, cderror, /*cam_flags*/0, /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); xpt_release_ccb(ccb); ! STAILQ_REMOVE(&softc->mode_queue, data, cd_mode_params, links); ! ! /* ! * This is a bit of belt-and-suspenders checking, but if we run ! * into a situation where the target sends back multiple block ! * descriptors, we might not have enough space in the buffer to ! * see the whole mode page. Better to return an error than ! * potentially access memory beyond our malloced region. ! */ ! if (error == 0) { ! u_int32_t data_len; ! ! if (data->cdb_size == 10) { ! struct scsi_mode_header_10 *hdr10; ! ! hdr10 = (struct scsi_mode_header_10 *)data->mode_buf; ! data_len = scsi_2btoul(hdr10->data_length); ! data_len += sizeof(hdr10->data_length); ! } else { ! struct scsi_mode_header_6 *hdr6; ! ! hdr6 = (struct scsi_mode_header_6 *)data->mode_buf; ! data_len = hdr6->data_length; ! data_len += sizeof(hdr6->data_length); ! } ! ! /* ! * Complain if there is more mode data available than we ! * allocated space for. This could potentially happen if ! * we miscalculated the page length for some reason, if the ! * drive returns multiple block descriptors, or if it sets ! * the data length incorrectly. ! */ ! if (data_len > data->alloc_len) { ! xpt_print_path(periph->path); ! printf("allocated modepage %d length %d < returned " ! "length %d\n", page, data->alloc_len, data_len); ! ! error = ENOSPC; ! } ! } ! 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 scsi_mode_header_10 *mode_header; ! u_int32_t data_len; ! mode_header = (struct scsi_mode_header_10 *)data->mode_buf; ! ! data_len = scsi_2btoul(mode_header->data_length); ! ! scsi_ulto2b(0, mode_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_header->medium_type = 0; ! ! /* ! * Pass back whatever the drive passed to us, plus the size ! * of the data length field. ! */ ! param_len = data_len + sizeof(mode_header->data_length); ! ! } else { ! struct scsi_mode_header_6 *mode_header; ! ! mode_header = (struct scsi_mode_header_6 *)data->mode_buf; ! ! param_len = mode_header->data_length + 1; ! ! mode_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_header->medium_type = 0; ! } ! ! /* Don't say we've got more room than we actually allocated */ ! param_len = min(param_len, data->alloc_len); ! ! scsi_mode_select_len(csio, ! /* retries */ 1, ! /* cbfcnp */ cddone, ! /* tag_action */ MSG_SIMPLE_Q_TAG, ! /* scsi_page_fmt */ 1, ! /* save_pages */ 0, ! /* param_buf */ data->mode_buf, ! /* param_len */ param_len, ! /* minimum_cmd_size */ cdb_size, ! /* sense_len */ SSD_FULL_SIZE, ! /* timeout */ 50000); ! ! /* See comments in cdgetmode() and cd6byteworkaround(). */ ! STAILQ_INSERT_TAIL(&softc->mode_queue, data, links); error = cdrunccb(ccb, cderror, /*cam_flags*/0, /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); xpt_release_ccb(ccb); ! STAILQ_REMOVE(&softc->mode_queue, data, cd_mode_params, links); ! ! return (error); } ==== //depot/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.h#2 - /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.h ==== *** /tmp/tmp.17105.3 Fri Nov 22 22:38:19 2002 --- /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_cd.h Fri Nov 22 22:07:52 2002 *************** *** 656,693 **** u_int8_t length_0; /* Least significant */ }; ! union cd_pages { ! struct audio_page { ! u_int8_t page_code; ! #define CD_PAGE_CODE 0x3F ! #define AUDIO_PAGE 0x0e ! #define CD_PAGE_PS 0x80 ! u_int8_t param_len; ! u_int8_t flags; ! #define CD_PA_SOTC 0x02 ! #define CD_PA_IMMED 0x04 ! u_int8_t unused[2]; ! u_int8_t format_lba; ! #define CD_PA_FORMAT_LBA 0x0F ! #define CD_PA_APR_VALID 0x80 ! u_int8_t lb_per_sec[2]; ! struct port_control ! { ! u_int8_t channels; ! #define CHANNEL 0x0F ! #define CHANNEL_0 1 ! #define CHANNEL_1 2 ! #define CHANNEL_2 4 ! #define CHANNEL_3 8 ! #define LEFT_CHANNEL CHANNEL_0 ! #define RIGHT_CHANNEL CHANNEL_1 ! u_int8_t volume; ! } port[4]; ! #define LEFT_PORT 0 ! #define RIGHT_PORT 1 ! }audio; }; struct cd_mode_data --- 656,702 ---- u_int8_t length_0; /* Least significant */ }; ! struct cd_audio_page { ! u_int8_t page_code; ! #define CD_PAGE_CODE 0x3F ! #define AUDIO_PAGE 0x0e ! #define CD_PAGE_PS 0x80 ! u_int8_t param_len; ! u_int8_t flags; ! #define CD_PA_SOTC 0x02 ! #define CD_PA_IMMED 0x04 ! u_int8_t unused[2]; ! u_int8_t format_lba; ! #define CD_PA_FORMAT_LBA 0x0F ! #define CD_PA_APR_VALID 0x80 ! u_int8_t lb_per_sec[2]; ! struct port_control { ! u_int8_t channels; ! #define CHANNEL 0x0F ! #define CHANNEL_0 1 ! #define CHANNEL_1 2 ! #define CHANNEL_2 4 ! #define CHANNEL_3 8 ! #define LEFT_CHANNEL CHANNEL_0 ! #define RIGHT_CHANNEL CHANNEL_1 ! u_int8_t volume; ! } port[4]; ! #define LEFT_PORT 0 ! #define RIGHT_PORT 1 ! }; ! ! union cd_pages ! { ! struct cd_audio_page 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 *************** *** 695,700 **** --- 704,723 ---- 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 + { + STAILQ_ENTRY(cd_mode_params) links; + int cdb_size; + int alloc_len; + u_int8_t *mode_buf; }; __BEGIN_DECLS ==== //depot/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_da.c#12 - /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_da.c ==== *** /tmp/tmp.17105.4 Fri Nov 22 22:38:19 2002 --- /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/cam/scsi/scsi_da.c Fri Nov 22 22:24:13 2002 *************** *** 128,133 **** --- 128,135 ---- struct disk_params params; struct disk disk; union ccb saved_ccb; + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; }; struct da_quirk_entry { *************** *** 434,450 **** static int da_retry_count = DA_DEFAULT_RETRY; static int da_default_timeout = DA_DEFAULT_TIMEOUT; - static int da_no_6_byte = 0; SYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); SYSCTL_NODE(_kern_cam, OID_AUTO, da, CTLFLAG_RD, 0, "CAM Direct Access Disk driver"); SYSCTL_INT(_kern_cam_da, OID_AUTO, retry_count, CTLFLAG_RW, &da_retry_count, 0, "Normal I/O retry count"); SYSCTL_INT(_kern_cam_da, OID_AUTO, default_timeout, CTLFLAG_RW, &da_default_timeout, 0, "Normal I/O timeout (in seconds)"); ! SYSCTL_INT(_kern_cam_da, OID_AUTO, no_6_byte, CTLFLAG_RW, ! &da_no_6_byte, 0, "No 6 bytes commands"); /* * DA_ORDEREDTAG_INTERVAL determines how often, relative --- 436,451 ---- static int da_retry_count = DA_DEFAULT_RETRY; static int da_default_timeout = DA_DEFAULT_TIMEOUT; SYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); SYSCTL_NODE(_kern_cam, OID_AUTO, da, CTLFLAG_RD, 0, "CAM Direct Access Disk driver"); SYSCTL_INT(_kern_cam_da, OID_AUTO, retry_count, CTLFLAG_RW, &da_retry_count, 0, "Normal I/O retry count"); + TUNABLE_INT("kern.cam.da.retry_count", &da_retry_count); SYSCTL_INT(_kern_cam_da, OID_AUTO, default_timeout, CTLFLAG_RW, &da_default_timeout, 0, "Normal I/O timeout (in seconds)"); ! TUNABLE_INT("kern.cam.da.default_timeout", &da_default_timeout); /* * DA_ORDEREDTAG_INTERVAL determines how often, relative *************** *** 1127,1132 **** --- 1128,1165 ---- } } + static int + dacmdsizesysctl(SYSCTL_HANDLER_ARGS) + { + int error, value; + + value = *(int *)arg1; + + error = sysctl_handle_int(oidp, &value, 0, req); + + if ((error != 0) + || (req->newptr == NULL)) + return (error); + + /* + * Acceptable values here are 6, 10 or 12. It's possible we may + * support a 16 byte minimum command size in the future, since + * there are now READ(16) and WRITE(16) commands defined in the + * SBC-2 spec. + */ + if (value < 6) + value = 6; + else if ((value > 6) + && (value <= 10)) + value = 10; + else if (value > 10) + value = 12; + + *(int *)arg1 = value; + + return (0); + } + static cam_status daregister(struct cam_periph *periph, void *arg) { *************** *** 1134,1139 **** --- 1167,1173 ---- struct da_softc *softc; struct ccb_setasync csa; struct ccb_getdev *cgd; + char tmpstr[80], tmpstr2[80]; caddr_t match; cgd = (struct ccb_getdev *)arg; *************** *** 1181,1192 **** --- 1215,1267 ---- else softc->quirks = DA_Q_NONE; + snprintf(tmpstr, sizeof(tmpstr), "CAM DA unit %d", periph->unit_number); + snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); + softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_kern_cam_da), OID_AUTO, tmpstr2, + CTLFLAG_RD, 0, tmpstr); + if (softc->sysctl_tree == NULL) { + printf("daregister: unable to allocate sysctl tree\n"); + free(softc, M_DEVBUF); + return (CAM_REQ_CMP_ERR); + } + + /* + * RBC devices don't have to support READ(6), only READ(10). + */ if (softc->quirks & DA_Q_NO_6_BYTE || SID_TYPE(&cgd->inq_data) == T_RBC) softc->minimum_cmd_size = 10; else softc->minimum_cmd_size = 6; /* + * Load the user's default, if any. + */ + snprintf(tmpstr, sizeof(tmpstr), "kern.cam.da.%d.minimum_cmd_size", + periph->unit_number); + TUNABLE_INT_FETCH(tmpstr, &softc->minimum_cmd_size); + + /* + * 6, 10 and 12 are the currently permissible values. + */ + if (softc->minimum_cmd_size < 6) + softc->minimum_cmd_size = 6; + else if ((softc->minimum_cmd_size > 6) + && (softc->minimum_cmd_size <= 10)) + softc->minimum_cmd_size = 10; + else if (softc->minimum_cmd_size > 12) + softc->minimum_cmd_size = 12; + + /* + * Now register the sysctl handler, so the user can the value on + * the fly. + */ + SYSCTL_ADD_PROC(&softc->sysctl_ctx,SYSCTL_CHILDREN(softc->sysctl_tree), + OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW, + &softc->minimum_cmd_size, 0, dacmdsizesysctl, "I", + "Minimum CDB size"); + + /* * Block our timeout handler while we * add this softc to the dev list. */ *************** *** 1286,1293 **** } else { tag_code = MSG_SIMPLE_Q_TAG; } - if (da_no_6_byte && softc->minimum_cmd_size == 6) - softc->minimum_cmd_size = 10; scsi_read_write(&start_ccb->csio, /*retries*/da_retry_count, dadone, --- 1361,1366 ---- *************** *** 1665,1671 **** { struct da_softc *softc; struct cam_periph *periph; ! int error, sense_key, error_code, asc, ascq; periph = xpt_path_periph(ccb->ccb_h.path); softc = (struct da_softc *)periph->softc; --- 1738,1744 ---- { struct da_softc *softc; struct cam_periph *periph; ! int error; periph = xpt_path_periph(ccb->ccb_h.path); softc = (struct da_softc *)periph->softc; *************** *** 1675,1682 **** * READ(6)/WRITE(6) and upgrade to using 10 byte cdbs. */ error = 0; ! if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR ! && ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) { scsi_extract_sense(&ccb->csio.sense_data, &error_code, &sense_key, &asc, &ascq); if (sense_key == SSD_KEY_ILLEGAL_REQUEST) --- 1748,1763 ---- * READ(6)/WRITE(6) and upgrade to using 10 byte cdbs. */ error = 0; ! if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) { ! error = cmd6workaround(ccb); ! } else 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) ==== //depot/FreeBSD-ken-RELENG_4/src/sys/dev/ata/atapi-cam.c#1 - /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/dev/ata/atapi-cam.c ==== *** /tmp/tmp.17105.5 Fri Nov 22 22:38:19 2002 --- /usr/home/ken/perforce2/FreeBSD-ken-RELENG_4/src/sys/dev/ata/atapi-cam.c Fri Nov 22 22:07:52 2002 *************** *** 419,454 **** } break; } - case MODE_SELECT_6: - /* FALLTHROUGH */ - - case MODE_SENSE_6: - /* - * not supported by ATAPI/MMC devices (per SCSI MMC spec) - * translate to _10 equivalent. - * (actually we should do this only if we have tried - * MODE_foo_6 and received ILLEGAL_REQUEST or - * INVALID COMMAND OPERATION CODE) - * alternative fix: behave like a honest CAM transport, - * do not muck with CDB contents, and change scsi_cd to - * always use MODE_SENSE_10 in cdgetmode(), or let scsi_cd - * know that this specific unit is an ATAPI/MMC one, - * and in /that case/ use MODE_SENSE_10 - */ - - CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE, - ("Translating %s into _10 equivalent\n", - (hcb->cmd[0] == MODE_SELECT_6) ? - "MODE_SELECT_6" : "MODE_SENSE_6")); - hcb->cmd[0] |= 0x40; - hcb->cmd[6] = 0; - hcb->cmd[7] = 0; - hcb->cmd[8] = hcb->cmd[4]; - hcb->cmd[9] = hcb->cmd[5]; - hcb->cmd[4] = 0; - hcb->cmd[5] = 0; - break; - case READ_6: /* FALLTHROUGH */ --- 419,424 ----