Example #1
0
int
cd_setchan(struct cd_softc *cd, int p0, int p1, int p2, int p3, int flags)
{
	union scsi_mode_sense_buf *data;
	struct cd_audio_page *audio = NULL;
	int error, big;

	data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
	if (data == NULL)
		return (ENOMEM);

	error = scsi_do_mode_sense(cd->sc_link, AUDIO_PAGE, data,
	    (void **)&audio, NULL, NULL, NULL, sizeof(*audio), flags, &big);
	if (error == 0 && audio == NULL)
		error = EIO;

	if (error == 0) {
		audio->port[LEFT_PORT].channels = p0;
		audio->port[RIGHT_PORT].channels = p1;
		audio->port[2].channels = p2;
		audio->port[3].channels = p3;
		if (big)
			error = scsi_mode_select_big(cd->sc_link, SMS_PF,
			    &data->hdr_big, flags, 20000);
		else
			error = scsi_mode_select(cd->sc_link, SMS_PF,
			    &data->hdr, flags, 20000);
	}

	free(data, M_TEMP);
	return (error);
}
Example #2
0
int
cd_setvol(struct cd_softc *cd, const struct ioc_vol *arg, int flags)
{
	union scsi_mode_sense_buf *data;
	struct cd_audio_page *audio = NULL;
	u_int8_t mask_volume[4];
	int error, big;

	data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
	if (data == NULL)
		return (ENOMEM);

	error = scsi_do_mode_sense(cd->sc_link,
	    AUDIO_PAGE | SMS_PAGE_CTRL_CHANGEABLE, data, (void **)&audio, NULL,
	    NULL, NULL, sizeof(*audio), flags, NULL);
	if (error == 0 && audio == NULL)
		error = EIO;
	if (error != 0) {
		free(data, M_TEMP);
		return (error);
	}

	mask_volume[0] = audio->port[0].volume;
	mask_volume[1] = audio->port[1].volume;
	mask_volume[2] = audio->port[2].volume;
	mask_volume[3] = audio->port[3].volume;

	error = scsi_do_mode_sense(cd->sc_link, AUDIO_PAGE, data,
	    (void **)&audio, NULL, NULL, NULL, sizeof(*audio), flags, &big);
	if (error == 0 && audio == NULL)
		error = EIO;
	if (error != 0) {
		free(data, M_TEMP);
		return (error);
	}

	audio->port[0].volume = arg->vol[0] & mask_volume[0];
	audio->port[1].volume = arg->vol[1] & mask_volume[1];
	audio->port[2].volume = arg->vol[2] & mask_volume[2];
	audio->port[3].volume = arg->vol[3] & mask_volume[3];

	if (big)
		error = scsi_mode_select_big(cd->sc_link, SMS_PF,
		    &data->hdr_big, flags, 20000);
	else
		error = scsi_mode_select(cd->sc_link, SMS_PF,
		    &data->hdr, flags, 20000);

	free(data, M_TEMP);
	return (error);
}
Example #3
0
static ssize_t
sd_store_cache_type(struct device *dev, struct device_attribute *attr,
		    const char *buf, size_t count)
{
	int i, ct = -1, rcd, wce, sp;
	struct scsi_disk *sdkp = to_scsi_disk(dev);
	struct scsi_device *sdp = sdkp->device;
	char buffer[64];
	char *buffer_data;
	struct scsi_mode_data data;
	struct scsi_sense_hdr sshdr;
	int len;

	if (sdp->type != TYPE_DISK)
		/* no cache control on RBC devices; theoretically they
		 * can do it, but there's probably so many exceptions
		 * it's not worth the risk */
		return -EINVAL;

	for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) {
		len = strlen(sd_cache_types[i]);
		if (strncmp(sd_cache_types[i], buf, len) == 0 &&
		    buf[len] == '\n') {
			ct = i;
			break;
		}
	}
	if (ct < 0)
		return -EINVAL;
	rcd = ct & 0x01 ? 1 : 0;
	wce = ct & 0x02 ? 1 : 0;
	if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT,
			    SD_MAX_RETRIES, &data, NULL))
		return -EINVAL;
	len = min_t(size_t, sizeof(buffer), data.length - data.header_length -
		  data.block_descriptor_length);
	buffer_data = buffer + data.header_length +
		data.block_descriptor_length;
	buffer_data[2] &= ~0x05;
	buffer_data[2] |= wce << 2 | rcd;
	sp = buffer_data[0] & 0x80 ? 1 : 0;

	if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
			     SD_MAX_RETRIES, &data, &sshdr)) {
		if (scsi_sense_valid(&sshdr))
			sd_print_sense_hdr(sdkp, &sshdr);
		return -EINVAL;
	}
	revalidate_disk(sdkp->disk);
	return count;
}
Example #4
0
/*
 * Clear the GLTSD bit, indicating log pages should be saved to non-volatile
 * storage.
 */
static int
clear_gltsd(ds_scsi_info_t *sip)
{
	scsi_ms_hdrs_t hdrs, junk_hdrs;
	struct mode_control_scsi3 control_pg_cur, control_pg_chg;
	int result;
	uint_t skey, asc, ascq;

	bzero(&hdrs, sizeof (hdrs));
	bzero(&control_pg_cur, sizeof (control_pg_cur));
	bzero(&control_pg_chg, sizeof (control_pg_chg));

	result = scsi_mode_sense(sip,
	    MODEPAGE_CTRL_MODE, PC_CURRENT, &control_pg_cur,
	    MODEPAGE_CTRL_MODE_LEN, &hdrs, &skey, &asc, &ascq);

	if (result != 0) {
		printf("failed to read Control mode page (KEY=0x%x "
		    "ASC=0x%x ASCQ=0x%x)\n", skey, asc, ascq);
	} else if (control_pg_cur.mode_page.length !=
	    PAGELENGTH_MODE_CONTROL_SCSI3) {
		printf("SCSI-3 control mode page not supported\n");
	} else if ((result = scsi_mode_sense(sip,
	    MODEPAGE_CTRL_MODE, PC_CHANGEABLE, &control_pg_chg,
	    MODEPAGE_CTRL_MODE_LEN, &junk_hdrs, &skey, &asc, &ascq))
	    != 0) {
		printf("failed to read changeable Control mode page (KEY=0x%x "
		    "ASC=0x%x ASCQ=0x%x)\n", skey, asc, ascq);
	} else if (control_pg_cur.gltsd && !GLTSD_CHANGEABLE(control_pg_chg)) {
		printf("gltsd is set and not changeable\n");
		if (nvlist_add_boolean_value(sip->si_dsp->ds_state,
		    "gltsd", control_pg_cur.gltsd) != 0)
			return (scsi_set_errno(sip, EDS_NOMEM));
	} else if (control_pg_cur.gltsd) {
		control_pg_cur.gltsd = 0;
		result = scsi_mode_select(sip,
		    MODEPAGE_CTRL_MODE, MODE_SELECT_PF, &control_pg_cur,
		    MODEPAGE_CTRL_MODE_LEN, &hdrs, &skey, &asc, &ascq);
		if (result != 0)
			printf("failed to enable GLTSD (KEY=0x%x "
			    "ASC=0x%x ASCQ=0x%x\n", skey, asc, ascq);
		if (nvlist_add_boolean_value(sip->si_dsp->ds_state,
		    "gltsd", control_pg_cur.gltsd) != 0)
			return (scsi_set_errno(sip, EDS_NOMEM));
	}

	return (0);
}
Example #5
0
int
cd_set_pa_immed(struct cd_softc *cd, int flags)
{
	union scsi_mode_sense_buf *data;
	struct cd_audio_page *audio = NULL;
	int error, oflags, big;

	if (cd->sc_link->flags & SDEV_ATAPI)
		/* XXX Noop? */
		return (0);

	data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
	if (data == NULL)
		return (ENOMEM);

	error = scsi_do_mode_sense(cd->sc_link, AUDIO_PAGE, data,
	    (void **)&audio, NULL, NULL, NULL, sizeof(*audio), flags, &big);
	if (error == 0 && audio == NULL)
		error = EIO;

	if (error == 0) {
		oflags = audio->flags;
		audio->flags &= ~CD_PA_SOTC;
		audio->flags |= CD_PA_IMMED;
		if (audio->flags != oflags) {
			if (big)
				error = scsi_mode_select_big(cd->sc_link,
				    SMS_PF, &data->hdr_big, flags,
				    20000);
			else
				error = scsi_mode_select(cd->sc_link, SMS_PF,
				    &data->hdr, flags, 20000);
		}
	}

	free(data, M_TEMP);
	return (error);
}
Example #6
0
int
sd_ioctl_cache(struct sd_softc *sc, long cmd, struct dk_cache *dkc)
{
	union scsi_mode_sense_buf *buf;
	struct page_caching_mode *mode = NULL;
	u_int wrcache, rdcache;
	int big;
	int rv;

	if (ISSET(sc->sc_link->flags, SDEV_UMASS))
		return (EOPNOTSUPP);

	/* see if the adapter has special handling */
	rv = scsi_do_ioctl(sc->sc_link, cmd, (caddr_t)dkc, 0);
	if (rv != ENOTTY)
		return (rv);

	buf = dma_alloc(sizeof(*buf), PR_WAITOK);
	if (buf == NULL)
		return (ENOMEM);

	rv = scsi_do_mode_sense(sc->sc_link, PAGE_CACHING_MODE,
	    buf, (void **)&mode, NULL, NULL, NULL,
	    sizeof(*mode) - 4, scsi_autoconf | SCSI_SILENT, &big);
	if (rv != 0)
		goto done;

	if ((mode == NULL) || (!DISK_PGCODE(mode, PAGE_CACHING_MODE))) {
		rv = EIO;
		goto done;
	}

	wrcache = (ISSET(mode->flags, PG_CACHE_FL_WCE) ? 1 : 0);
	rdcache = (ISSET(mode->flags, PG_CACHE_FL_RCD) ? 0 : 1);

	switch (cmd) {
	case DIOCGCACHE:
		dkc->wrcache = wrcache;
		dkc->rdcache = rdcache;
		break;

	case DIOCSCACHE:
		if (dkc->wrcache == wrcache && dkc->rdcache == rdcache)
			break;

		if (dkc->wrcache)
			SET(mode->flags, PG_CACHE_FL_WCE);
		else
			CLR(mode->flags, PG_CACHE_FL_WCE);

		if (dkc->rdcache)
			CLR(mode->flags, PG_CACHE_FL_RCD);
		else
			SET(mode->flags, PG_CACHE_FL_RCD);

		if (big) {
			rv = scsi_mode_select_big(sc->sc_link, SMS_PF,
			    &buf->hdr_big, scsi_autoconf | SCSI_SILENT, 20000);
		} else {
			rv = scsi_mode_select(sc->sc_link, SMS_PF,
			    &buf->hdr, scsi_autoconf | SCSI_SILENT, 20000);
		}
		break;
	}

done:
	dma_free(buf, sizeof(*buf));
	return (rv);
}
Example #7
0
/*
 * Enable IE reporting.  We prefer the following settings:
 *
 * (1) DEXCPT = 0
 * (3) MRIE = 6 (IE_REPORT_ON_REQUEST)
 * (4) EWASC = 1
 * (6) REPORT COUNT = 0x00000001
 * (7) LOGERR = 1
 *
 * However, not all drives support changing these values, and the current state
 * may be useful enough as-is.  For example, some drives support IE logging, but
 * don't support changing the MRIE.  In this case, we can still use the
 * information provided by the log page.
 */
static int
scsi_enable_ie(ds_scsi_info_t *sip, boolean_t *changed)
{
	scsi_ie_page_t new_iec_page;
	scsi_ms_hdrs_t hdrs;
	uint_t skey, asc, ascq;

	if (!(sip->si_supp_mode & MODEPAGE_SUPP_IEC))
		return (0);

	bzero(&new_iec_page, sizeof (new_iec_page));
	bzero(&hdrs, sizeof (hdrs));

	(void) memcpy(&new_iec_page, &sip->si_iec_current,
	    sizeof (new_iec_page));

	if (IEC_IE_CHANGEABLE(sip->si_iec_changeable))
		new_iec_page.ie_dexcpt = 0;

	if (IEC_MRIE_CHANGEABLE(sip->si_iec_changeable))
		new_iec_page.ie_mrie = IE_REPORT_ON_REQUEST;

	/*
	 * We only want to enable warning reporting if we are able to change the
	 * mrie to report on request.  Otherwise, we risk unnecessarily
	 * interrupting normal SCSI commands with a CHECK CONDITION code.
	 */
	if (IEC_EWASC_CHANGEABLE(sip->si_iec_changeable)) {
		if (new_iec_page.ie_mrie == IE_REPORT_ON_REQUEST)
			new_iec_page.ie_ewasc = 1;
		else
			new_iec_page.ie_ewasc = 0;
	}

	if (IEC_RPTCNT_CHANGEABLE(sip->si_iec_changeable))
		new_iec_page.ie_report_count = BE_32(1);

	if (IEC_LOGERR_CHANGEABLE(sip->si_iec_changeable))
		new_iec_page.ie_logerr = 1;

	/*
	 * Now compare the new mode page with the existing one.
	 * if there's no difference, there's no need for a mode select
	 */
	if (memcmp(&new_iec_page, &sip->si_iec_current,
	    MODEPAGE_INFO_EXCPT_LEN) == 0) {
		*changed = B_FALSE;
	} else {
		(void) memcpy(&hdrs, &sip->si_hdrs, sizeof (sip->si_hdrs));

		if (scsi_mode_select(sip,
		    MODEPAGE_INFO_EXCPT, MODE_SELECT_PF, &new_iec_page,
		    MODEPAGE_INFO_EXCPT_LEN, &hdrs, &skey, &asc, &ascq) == 0) {
			*changed = B_TRUE;
		} else {
			printf("failed to enable IE (KEY=0x%x "
			    "ASC=0x%x ASCQ=0x%x)\n", skey, asc, ascq);
			*changed = B_FALSE;
		}
	}

	if (nvlist_add_boolean_value(sip->si_state_iec, "changed",
	    *changed) != 0)
		return (scsi_set_errno(sip, EDS_NOMEM));

	return (0);
}
Example #8
0
void DevOperate(DiscDCB *dcb, DiscReq *req)
{
	BYTE	  capacity_data[CAPACITY_LENGTH];
	WORD	  command_status,second_status;
	WORD	  block_addr, block_len;
	WORD	  done = 0;
	WORD	  size;
	BYTE	  *buf = req->Buf;
	INT	  res;
	BYTE sense_data[SENSE_LENGTH];

	FormatReq *freq;

	Wait(&dcb->Lock);

	/* Select the appropriate command */
	switch( req->DevReq.Request & FG_Mask)
	{
		case FG_Read:
#ifdef DEBUG
		IOdebug("read pos = %d size = %d",req->Pos / dcb->SectorSize,req->Size / dcb->SectorSize);
#endif
			size = req->Size;
			while( done < size )
			{
				WORD tfr = size - done;
				WORD position = (req->Pos / dcb->SectorSize) + (done/dcb->SectorSize);
				command_status = 8;/* make loop happen once*/
				if ( tfr > MAX_TFR )
				{
					tfr = MAX_TFR;
				}
				while (command_status == 8)
				  {
				  res = scsi_read(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
				  }

				if ( ( res < 0 ) || ( command_status ne 0 ))
					{
					 command_status = 8;
					 while (command_status == 8)
					   {
					   res = scsi_read(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
					   }
				}

				done += tfr;
				buf  += tfr;
			}

			req->DevReq.Result = command_status;
			if ( req->DevReq.Result eq 0 )
				req->Actual = req->Size;
			else
				req->Actual = 0;
			break;

		case FG_Write:
#ifdef DEBUG
			IOdebug("write pos = %d size = %d",req->Pos / dcb->SectorSize,req->Size / dcb->SectorSize);
#endif
			size = req->Size;
			while( done < size )
			{
				WORD tfr = size - done;
				WORD position = (req->Pos / dcb->SectorSize) + (done/dcb->SectorSize);
				command_status = 8; /* make loop happen once*/
				if ( tfr > MAX_TFR )
				{
					tfr = MAX_TFR;
				}
				while (command_status == 8)
				{
				  res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
				}
				if ( ( res < 0 ) || ( command_status ne 0 ))
				{
					command_status = 8;
					while (command_status == 8)
					{
					 res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
					}
				}
				done += tfr;
				buf  += tfr;
			}


			req->DevReq.Result = command_status;
			if ( req->DevReq.Result eq 0 )
				req->Actual = req->Size;
			else
				req->Actual = 0;
			break;

		case FG_GetSize:
#ifdef DEBUG
			IOdebug("read capacity request");
#endif
			command_status = 8;
			while (command_status == 8)
			{
			scsi_read_capacity(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,		/* lun		   */
				8,		/* capacity length */
				capacity_data,
				&command_status);
			}

			if ( command_status eq 0 )
			{
				block_addr = capacity_data[0] * 0x1000000 +
					     capacity_data[1] * 0x10000   +
					     capacity_data[2] * 0x100	  +
					     capacity_data[3];
				block_len  = capacity_data[4] * 0x1000000 +
					     capacity_data[5] * 0x10000   +
					     capacity_data[6] * 0x100	  +
					     capacity_data[7];
				req->DevReq.Result = block_addr * block_len;
			}
			break;
		case FG_Format:
			IOdebug("\rFormatting disk please wait ....");
			freq = (FormatReq *)req;


			command_status = 8;/* so the loop happens once*/
			while (command_status == 8)
			{
			scsi_mode_select(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				0,			/* format whole disk */
				dcb->SectorSize,
				&command_status);
			}
			command_status = 8;/* so the loop happens once*/
			while (command_status == 8)
			{
			scsi_format(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				freq->Interleave,
				&command_status);
			}
/* If the disk supports the busy status we need to wait until busy goes away
	before giving the message that we are verifying */

			command_status = 8;
			while (command_status == 8)
			{
			  scsi_test_unit_ready(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				&command_status);
			}
/* some disks will queue one command so we need to wait twice to cope with this
	*/
			command_status = 8;
			while (command_status != 0)
			{
			  IOdebug("status = %d",command_status);
			  scsi_test_unit_ready(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				&command_status);

			scsi_request_sense(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				SENSE_LENGTH,
				sense_data,
				&command_status);
			IOdebug("sense =%x",sense_data[2]);
			}


			{
			WORD	total_blocks;
			WORD	i,j;
			WORD	ten_cent,done = 0;
			BYTE	*data;

			IOdebug("\rVerifying disk please wait ....");
			data = Malloc(dcb->SectorSize);
			command_status = 8; /* do at least once*/
			while (command_status == 8 )
			{
				res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,1,dcb->SectorSize,dcb->SectorSize,data,&command_status);
			}
			total_blocks = (dcb->SectorsPerTrack * dcb->TracksPerCyl * dcb->Cylinders);
/*			IOdebug("\rdisk size is %d blocks",total_blocks);*/
			ten_cent =  total_blocks  / 10;
			for ( i = 1; i < total_blocks; i++)
			{
			 command_status = 8; /* you know by now*/
			 while (command_status == 8)
			 {
				 res = scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
			}
			second_status = 8;
			while (second_status == 8)
			{
			 res = scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status);
			}
					 if (( i % ten_cent )  eq 0)
				{
					done += 10;
					IOdebug("\rVerified %d percent of disk\v",done);
				}
				if ((command_status ne 0) || (second_status ne 0))
				{
					command_status = 8;
					while (command_status == 8 )
					{
					scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
					}
					second_status = 8;
					while (second_status == 8)
					{
					scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status);
					}
					if (( command_status  ne 0 ) || (second_status ne 0))
					{
						IOdebug("Verifier found bad block at %d",i);
						for( j = 0; j  < 10; j++)
						{
							command_status = 8;
							while (command_status == 8)
							{
							scsi_reassign_block(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
							}
							command_status = 8;
							while (command_status == 8)
							{
							scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
							}
							second_status = 8;
							while (second_status == 8)
							{
							scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status);
							}
							if ((command_status eq 0) && (second_status eq 0))break;
						}
						if  (( command_status eq 0 ) && (second_status eq 0))
							IOdebug("Block %d reassigned OK",i);
						else
							IOdebug("Failed to reassign block %d",i);
					}
				}
			}

			}
			IOdebug("Verification complete                         ");
			req->DevReq.Result = 0;
			break;
		default:
			break;
		}
		/* Unlock the driver */
		Signal(&dcb->Lock);
		/* Client action */
		(*req->DevReq.Action)(req);
		return;
}