dadk.c revision 43369e138469651f508b1edd3512f007d1545665
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Direct Attached Disk
*/
/*
* Local Function Prototypes
*/
static void dadk_restart(void *pktp);
struct tgcom_objops dadk_com_ops = {
0, 0
};
int silent);
struct tgdk_objops dadk_ops = {
0
};
/*
* Local static data
*/
#ifdef DADK_DEBUG
#define DENT 0x0001
#define DERR 0x0002
#define DIO 0x0004
#define DGEOM 0x0010
#define DSTATE 0x0020
static int dadk_debug = DGEOM;
#endif /* DADK_DEBUG */
static int dadk_dk_maxphys = 0x80000;
static char *dadk_cmds[] = {
"\000Unknown", /* unknown */
"\001read sector", /* DCMD_READ 1 */
"\002write sector", /* DCMD_WRITE 2 */
"\003format track", /* DCMD_FMTTRK 3 */
"\004format whole drive", /* DCMD_FMTDRV 4 */
"\005recalibrate", /* DCMD_RECAL 5 */
"\006seek sector", /* DCMD_SEEK 6 */
"\007read verify", /* DCMD_RDVER 7 */
"\010read defect list", /* DCMD_GETDEF 8 */
"\011lock door", /* DCMD_LOCK 9 */
"\012unlock door", /* DCMD_UNLOCK 10 */
"\013start motor", /* DCMD_START_MOTOR 11 */
"\014stop motor", /* DCMD_STOP_MOTOR 12 */
"\015eject", /* DCMD_EJECT 13 */
"\016update geometry", /* DCMD_UPDATE_GEOM 14 */
"\017get state", /* DCMD_GET_STATE 15 */
"\020cdrom pause", /* DCMD_PAUSE 16 */
"\021cdrom resume", /* DCMD_RESUME 17 */
"\022cdrom play track index", /* DCMD_PLAYTRKIND 18 */
"\023cdrom play msf", /* DCMD_PLAYMSF 19 */
"\024cdrom sub channel", /* DCMD_SUBCHNL 20 */
"\025cdrom read mode 1", /* DCMD_READMODE1 21 */
"\026cdrom read toc header", /* DCMD_READTOCHDR 22 */
"\027cdrom read toc entry", /* DCMD_READTOCENT 23 */
"\030cdrom read offset", /* DCMD_READOFFSET 24 */
"\031cdrom read mode 2", /* DCMD_READMODE2 25 */
"\032cdrom volume control", /* DCMD_VOLCTRL 26 */
};
static char *dadk_sense[] = {
"\000Success", /* DERR_SUCCESS */
"\001address mark not found", /* DERR_AMNF */
"\002track 0 not found", /* DERR_TKONF */
"\003aborted command", /* DERR_ABORT */
"\004write fault", /* DERR_DWF */
"\005ID not found", /* DERR_IDNF */
"\006drive busy", /* DERR_BUSY */
"\007uncorrectable data error", /* DERR_UNC */
"\010bad block detected", /* DERR_BBK */
"\011invalid command", /* DERR_INVCDB */
"\012device hard error", /* DERR_HARD */
"\013illegal length indicated", /* DERR_ILI */
"\014end of media", /* DERR_EOM */
"\015media change requested", /* DERR_MCR */
"\016recovered from error", /* DERR_RECOVER */
"\017device not ready", /* DERR_NOTREADY */
"\020medium error", /* DERR_MEDIUM */
"\021hardware error", /* DERR_HW */
"\022illegal request", /* DERR_ILL */
"\023unit attention", /* DERR_UNIT_ATTN */
"\024data protection", /* DERR_DATA_PROT */
"\025miscompare", /* DERR_MISCOMPARE */
"\026reserved", /* DERR_RESV */
};
static char *dadk_name = "Disk";
/*
* This is the loadable module wrapper
*/
extern struct mod_ops mod_miscops;
&mod_miscops, /* Type of module */
"Direct Attached Disk %I%"
};
static struct modlinkage modlinkage = {
};
int
_init(void)
{
#ifdef DADK_DEBUG
if (dadk_debug & DENT)
PRF("dadk_init: call\n");
#endif
return (mod_install(&modlinkage));
}
int
_fini(void)
{
#ifdef DADK_DEBUG
if (dadk_debug & DENT)
PRF("dadk_fini: call\n");
#endif
return (mod_remove(&modlinkage));
}
int
{
}
struct tgdk_obj *
{
if (!dkobjp)
return (NULL);
#ifdef DADK_DEBUG
if (dadk_debug & DENT)
#endif
return (dkobjp);
}
int
{
/* initialize the communication object */
}
int
{
return (DDI_SUCCESS);
}
void
{
if (dadkp->dad_bbhobjp) {
}
if (dadkp->dad_flcobjp) {
}
}
/* ARGSUSED */
int
{
struct scsi_device *devp;
char name[80];
return (DDI_PROBE_FAILURE);
}
case DTYPE_DIRECT:
break;
case DTYPE_RODIRECT: /* eg cdrom */
break;
case DTYPE_WORM:
case DTYPE_OPTICAL:
default:
return (DDI_PROBE_FAILURE);
}
dadkp->dad_blkshf = 0;
/* display the device name */
return (DDI_PROBE_SUCCESS);
}
/* ARGSUSED */
int
{
return (DDI_SUCCESS);
}
int
{
/* free the old bbh object */
if (dadkp->dad_bbhobjp)
/* initialize the new bbh object */
return (DDI_SUCCESS);
}
/* ARGSUSED */
int
{
return (DDI_SUCCESS);
}
} else {
return (DDI_FAILURE);
}
}
/* logical disk geometry */
return (DDI_FAILURE);
/* get physical disk geometry */
return (DDI_FAILURE);
/* start profiling */
return (DDI_SUCCESS);
}
static void
{
int totsize;
int i;
if (totsize == 0) {
totsize = 2048;
} else {
}
} else {
/* Round down sector size to multiple of 512B */
}
/* set sec,block shift factor - (512->0, 1024->1, 2048->2, etc.) */
dadkp->dad_blkshf = i;
}
int
{
}
return (DDI_SUCCESS);
}
int
{
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
{
if (dadkp->dad_rdonly) {
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
if (!pktp) {
return (DDI_FAILURE);
}
}
if (pktp->cp_private)
return (DDI_SUCCESS);
}
/* ARGSUSED */
int
{
switch (cmd) {
case DKIOCGETDEF:
{
unsigned char *secbuf;
/*
* copyin header ....
* yields head number and buffer address
*/
flag))
return (EFAULT);
return (ENXIO);
if (!secbuf)
return (ENOMEM);
if (!bp) {
return (ENOMEM);
}
if (!err) {
}
return (err);
}
case DIOCTL_RWCMD:
{
struct dadkio_rwcmd *rwcmdp;
/*
* copied in by cmdk and, if necessary, converted to the
* correct datamodel
*/
/*
* handle the complex cases here; we pass these
* through to the driver, which will queue them and
* handle the requests asynchronously. The simpler
* cases ,which can return immediately, fail here, and
* the request reverts to the dadk_ioctl routine, while
* will reroute them directly to the ata driver.
*/
case DADKIO_RWCMD_READ :
/*FALLTHROUGH*/
case DADKIO_RWCMD_WRITE:
return (status);
default:
return (EINVAL);
}
}
default:
}
switch (cmd) {
case CDROMSTOP:
0, DADK_SILENT));
case CDROMSTART:
0, DADK_SILENT));
case DKIOCLOCK:
case DKIOCUNLOCK:
case DKIOCEJECT:
case CDROMEJECT:
{
int ret;
DADK_SILENT)) {
return (ret);
}
DADK_SILENT)) {
return (ret);
}
return (0);
}
default:
return (ENOTTY);
/*
* cdrom audio commands
*/
case CDROMPAUSE:
cmd = DCMD_PAUSE;
break;
case CDROMRESUME:
cmd = DCMD_RESUME;
break;
case CDROMPLAYMSF:
cmd = DCMD_PLAYMSF;
break;
case CDROMPLAYTRKIND:
break;
case CDROMREADTOCHDR:
break;
case CDROMREADTOCENTRY:
break;
case CDROMVOLCTRL:
cmd = DCMD_VOLCTRL;
break;
case CDROMSUBCHNL:
cmd = DCMD_SUBCHNL;
break;
case CDROMREADMODE2:
break;
case CDROMREADMODE1:
break;
case CDROMREADOFFSET:
break;
}
}
int
{
sizeof (struct tgdk_geom));
return (DDI_SUCCESS);
}
int
{
sizeof (struct tgdk_geom));
return (DDI_SUCCESS);
}
int
{
return (DDI_SUCCESS);
}
{
return (NULL);
return (NULL);
}
return (NULL);
}
return (iobp);
}
/* ARGSUSED */
int
{
if (iobp) {
}
}
return (DDI_SUCCESS);
}
/* ARGSUSED */
{
}
{
int err;
return (NULL);
}
/* call flow control */
if (err)
return (NULL);
}
static void
{
return;
}
static int
{
if (GDA_BP_PKT(bp))
return (DDI_SUCCESS);
if (!pktp)
return (DDI_FAILURE);
}
/*
* Read, Write preparation
*/
static int
{
else
/* setup the bad block list handle */
}
static int
{
int seccnt;
if (pktp->cp_secleft) {
} else {
/* get the first cookie from the bad block list */
if (!pktp->cp_private) {
} else {
pktp->cp_private);
bbhckp);
bbhckp);
}
}
return (DDI_SUCCESS);
} else {
return (DDI_FAILURE);
}
}
static struct cmpkt *
{
arg);
if (pktp) {
}
return (pktp);
}
static void
dadk_restart(void *vpktp)
{
return;
}
static int
{
switch (action) {
case QUE_COMMAND:
return (JUST_RETURN);
}
"transport of command fails\n");
} else
"exceeds maximum number of retries\n");
/*FALLTHROUGH*/
case COMMAND_DONE_ERROR:
/*FALLTHROUGH*/
case COMMAND_DONE:
default:
return (COMMAND_DONE);
}
}
static void
{
int action;
struct dadkio_rwcmd *rwcmdp;
return;
}
return;
}
else
if (action == JUST_RETURN)
return;
if (action != COMMAND_DONE) {
return;
}
}
static struct dadkio_derr dadk_errtab[] = {
};
static int
{
int err_blkno;
int scb;
return (COMMAND_DONE);
/* check error code table */
} else
err_blkno = -1;
/* if attempting to read a sector from a cdrom audio disk */
return (COMMAND_DONE);
}
}
}
}
static void
{
int scb;
((pktp->cp_bytexfer -
case DERR_AMNF:
case DERR_ABORT:
break;
case DERR_DWF:
case DERR_IDNF:
break;
case DERR_TKONF:
case DERR_UNC:
case DERR_BBK:
break;
case DERR_BUSY:
break;
case DERR_INVCDB:
case DERR_HARD:
break;
default:
}
return;
}
/*ARGSUSED*/
static void
{
}
static void
{
/* check for all iodone */
/* transport the next one */
return;
return;
}
/* start next one */
/* free pkt */
if (pktp->cp_private)
}
int
{
return (ENXIO);
}
#ifdef DADK_DEBUG
if (dadk_debug & DSTATE)
PRF("dadk_check_media: user state %x disk state %x\n",
#endif
/*
* If state already changed just return
*/
return (0);
}
/*
* Startup polling on thread state
*/
if (dadkp->dad_thread_cnt == 0) {
/*
* One thread per removable dadk device
*/
}
dadkp->dad_thread_cnt++;
/*
* Wait for state to change
*/
do {
dadkp->dad_thread_cnt--;
return (EINTR);
}
dadkp->dad_thread_cnt--;
return (0);
}
#define MEDIA_ACCESS_DELAY 2000000
static void
{
enum dkio_state state;
int interval;
do {
DADK_SILENT)) {
/*
* Assume state remained the same
*/
}
/*
* now signal the waiting thread if this is *not* the
* specified state;
* delay the signal if the state is DKIO_INSERTED
* to allow the target to recover
*/
if (state == DKIO_INSERTED) {
/*
* delay the signal to give the drive a chance
* to do what it apparently needs to do
*/
(void) timeout((void(*)(void *))cv_broadcast,
(void *)&dadkp->dad_state_cv,
} else {
}
}
} while (dadkp->dad_thread_cnt);
}
int
{
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
static int
{
int err;
return (ENOMEM);
}
if (!pktp) {
return (ENOMEM);
}
return (err);
}
static void
{
/* Start next one */
}
static int
{
int status;
/* Let physio do the rest... */
return (status);
}
/* Do not let a user gendisk request get too big or */
/* else we could use to many resources. */
static void
{
}
static int
{
bp);
return (0);
}
static void
{
if (!pktp) {
return;
}
}