11709Smlf /* 21709Smlf * CDDL HEADER START 31709Smlf * 41709Smlf * The contents of this file are subject to the terms of the 51709Smlf * Common Development and Distribution License (the "License"). 61709Smlf * You may not use this file except in compliance with the License. 71709Smlf * 81709Smlf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91709Smlf * or http://www.opensolaris.org/os/licensing. 101709Smlf * See the License for the specific language governing permissions 111709Smlf * and limitations under the License. 121709Smlf * 131709Smlf * When distributing Covered Code, include this CDDL HEADER in each 141709Smlf * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151709Smlf * If applicable, add the following below this CDDL HEADER, with the 161709Smlf * fields enclosed by brackets "[]" replaced with your own identifying 171709Smlf * information: Portions Copyright [yyyy] [name of copyright owner] 181709Smlf * 191709Smlf * CDDL HEADER END 201709Smlf */ 211709Smlf 221709Smlf /* 237239Szk194757 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241709Smlf * Use is subject to license terms. 251709Smlf */ 261709Smlf 271709Smlf /* 281709Smlf * Direct Attached Disk 291709Smlf */ 301709Smlf 311709Smlf #include <sys/file.h> 321709Smlf #include <sys/scsi/scsi.h> 331709Smlf #include <sys/var.h> 341709Smlf #include <sys/proc.h> 351709Smlf #include <sys/dktp/cm.h> 361709Smlf #include <sys/vtoc.h> 371709Smlf #include <sys/dkio.h> 383652Syt160523 #include <sys/policy.h> 393652Syt160523 #include <sys/priv.h> 401709Smlf 411709Smlf #include <sys/dktp/dadev.h> 421709Smlf #include <sys/dktp/fctypes.h> 431709Smlf #include <sys/dktp/flowctrl.h> 441709Smlf #include <sys/dktp/tgcom.h> 451709Smlf #include <sys/dktp/tgdk.h> 461709Smlf #include <sys/dktp/bbh.h> 471709Smlf #include <sys/dktp/dadkio.h> 481709Smlf #include <sys/dktp/dadk.h> 491709Smlf #include <sys/cdio.h> 501709Smlf 511709Smlf /* 521709Smlf * Local Function Prototypes 531709Smlf */ 541709Smlf static void dadk_restart(void *pktp); 551709Smlf static void dadk_pktcb(struct cmpkt *pktp); 561709Smlf static void dadk_iodone(struct buf *bp); 571709Smlf static void dadk_polldone(struct buf *bp); 581709Smlf static void dadk_setcap(struct dadk *dadkp); 592799Smarx static void dadk_create_errstats(struct dadk *dadkp, int instance); 602799Smarx static void dadk_destroy_errstats(struct dadk *dadkp); 611709Smlf 621709Smlf static int dadk_chkerr(struct cmpkt *pktp); 631709Smlf static int dadk_ioprep(struct dadk *dadkp, struct cmpkt *pktp); 641709Smlf static int dadk_iosetup(struct dadk *dadkp, struct cmpkt *pktp); 651709Smlf static int dadk_ioretry(struct cmpkt *pktp, int action); 661709Smlf 671709Smlf static struct cmpkt *dadk_pktprep(struct dadk *dadkp, struct cmpkt *in_pktp, 681709Smlf struct buf *bp, void (*cb_func)(struct buf *), int (*func)(caddr_t), 691709Smlf caddr_t arg); 701709Smlf 711709Smlf static int dadk_pkt(opaque_t com_data, struct buf *bp, int (*func)(caddr_t), 721709Smlf caddr_t arg); 731709Smlf static void dadk_transport(opaque_t com_data, struct buf *bp); 745295Srandyf static int dadk_ctl_ioctl(struct dadk *, uint32_t, uintptr_t, int); 751709Smlf 761709Smlf struct tgcom_objops dadk_com_ops = { 771709Smlf nodev, 781709Smlf nodev, 791709Smlf dadk_pkt, 801709Smlf dadk_transport, 811709Smlf 0, 0 821709Smlf }; 831709Smlf 841709Smlf /* 851709Smlf * architecture dependent allocation restrictions for dadk_iob_alloc(). For 861709Smlf * x86, we'll set dma_attr_addr_hi to dadk_max_phys_addr and dma_attr_sgllen 871709Smlf * to dadk_sgl_size during _init(). 881709Smlf */ 891709Smlf #if defined(__sparc) 901709Smlf static ddi_dma_attr_t dadk_alloc_attr = { 911709Smlf DMA_ATTR_V0, /* version number */ 921709Smlf 0x0, /* lowest usable address */ 931709Smlf 0xFFFFFFFFull, /* high DMA address range */ 941709Smlf 0xFFFFFFFFull, /* DMA counter register */ 951709Smlf 1, /* DMA address alignment */ 961709Smlf 1, /* DMA burstsizes */ 971709Smlf 1, /* min effective DMA size */ 981709Smlf 0xFFFFFFFFull, /* max DMA xfer size */ 991709Smlf 0xFFFFFFFFull, /* segment boundary */ 1001709Smlf 1, /* s/g list length */ 1011709Smlf 512, /* granularity of device */ 1021709Smlf 0, /* DMA transfer flags */ 1031709Smlf }; 1041709Smlf #elif defined(__x86) 1051709Smlf static ddi_dma_attr_t dadk_alloc_attr = { 1061709Smlf DMA_ATTR_V0, /* version number */ 1071709Smlf 0x0, /* lowest usable address */ 1081709Smlf 0x0, /* high DMA address range [set in _init()] */ 1091709Smlf 0xFFFFull, /* DMA counter register */ 1101709Smlf 512, /* DMA address alignment */ 1111709Smlf 1, /* DMA burstsizes */ 1121709Smlf 1, /* min effective DMA size */ 1131709Smlf 0xFFFFFFFFull, /* max DMA xfer size */ 1141709Smlf 0xFFFFFFFFull, /* segment boundary */ 1151709Smlf 0, /* s/g list length [set in _init()] */ 1161709Smlf 512, /* granularity of device */ 1171709Smlf 0, /* DMA transfer flags */ 1181709Smlf }; 1191709Smlf 1201709Smlf uint64_t dadk_max_phys_addr = 0xFFFFFFFFull; 1211709Smlf int dadk_sgl_size = 0xFF; 1221709Smlf #endif 1231709Smlf 1241709Smlf static int dadk_rmb_ioctl(struct dadk *dadkp, int cmd, intptr_t arg, int flags, 1251709Smlf int silent); 1261709Smlf static void dadk_rmb_iodone(struct buf *bp); 1271709Smlf 1281709Smlf static int dadk_dk_buf_setup(struct dadk *dadkp, opaque_t *cmdp, 1291709Smlf dev_t dev, enum uio_seg dataspace, int rw); 1301709Smlf static void dadk_dk(struct dadk *dadkp, struct dadkio_rwcmd *scmdp, 1311709Smlf struct buf *bp); 1321709Smlf static void dadkmin(struct buf *bp); 1331709Smlf static int dadk_dk_strategy(struct buf *bp); 1341709Smlf static void dadk_recorderr(struct cmpkt *pktp, struct dadkio_rwcmd *rwcmdp); 1351709Smlf 1361709Smlf struct tgdk_objops dadk_ops = { 1371709Smlf dadk_init, 1381709Smlf dadk_free, 1391709Smlf dadk_probe, 1401709Smlf dadk_attach, 1411709Smlf dadk_open, 1421709Smlf dadk_close, 1431709Smlf dadk_ioctl, 1441709Smlf dadk_strategy, 1451709Smlf dadk_setgeom, 1461709Smlf dadk_getgeom, 1471709Smlf dadk_iob_alloc, 1481709Smlf dadk_iob_free, 1491709Smlf dadk_iob_htoc, 1501709Smlf dadk_iob_xfer, 1511709Smlf dadk_dump, 1521709Smlf dadk_getphygeom, 1531709Smlf dadk_set_bbhobj, 1541709Smlf dadk_check_media, 1551709Smlf dadk_inquiry, 1561709Smlf dadk_cleanup, 1571709Smlf 0 1581709Smlf }; 1591709Smlf 1601709Smlf /* 1611709Smlf * Local static data 1621709Smlf */ 1631709Smlf 1641709Smlf #ifdef DADK_DEBUG 1651709Smlf #define DENT 0x0001 1661709Smlf #define DERR 0x0002 1671709Smlf #define DIO 0x0004 1681709Smlf #define DGEOM 0x0010 1691709Smlf #define DSTATE 0x0020 1701709Smlf static int dadk_debug = DGEOM; 1711709Smlf 1721709Smlf #endif /* DADK_DEBUG */ 1731709Smlf 1741709Smlf static int dadk_check_media_time = 3000000; /* 3 Second State Check */ 1751709Smlf static int dadk_dk_maxphys = 0x80000; 1761709Smlf 1771709Smlf static char *dadk_cmds[] = { 1781709Smlf "\000Unknown", /* unknown */ 1791709Smlf "\001read sector", /* DCMD_READ 1 */ 1801709Smlf "\002write sector", /* DCMD_WRITE 2 */ 1811709Smlf "\003format track", /* DCMD_FMTTRK 3 */ 1821709Smlf "\004format whole drive", /* DCMD_FMTDRV 4 */ 1831709Smlf "\005recalibrate", /* DCMD_RECAL 5 */ 1841709Smlf "\006seek sector", /* DCMD_SEEK 6 */ 1851709Smlf "\007read verify", /* DCMD_RDVER 7 */ 1861709Smlf "\010read defect list", /* DCMD_GETDEF 8 */ 1871709Smlf "\011lock door", /* DCMD_LOCK 9 */ 1881709Smlf "\012unlock door", /* DCMD_UNLOCK 10 */ 1891709Smlf "\013start motor", /* DCMD_START_MOTOR 11 */ 1901709Smlf "\014stop motor", /* DCMD_STOP_MOTOR 12 */ 1911709Smlf "\015eject", /* DCMD_EJECT 13 */ 1921709Smlf "\016update geometry", /* DCMD_UPDATE_GEOM 14 */ 1931709Smlf "\017get state", /* DCMD_GET_STATE 15 */ 1941709Smlf "\020cdrom pause", /* DCMD_PAUSE 16 */ 1951709Smlf "\021cdrom resume", /* DCMD_RESUME 17 */ 1961709Smlf "\022cdrom play track index", /* DCMD_PLAYTRKIND 18 */ 1971709Smlf "\023cdrom play msf", /* DCMD_PLAYMSF 19 */ 1981709Smlf "\024cdrom sub channel", /* DCMD_SUBCHNL 20 */ 1991709Smlf "\025cdrom read mode 1", /* DCMD_READMODE1 21 */ 2001709Smlf "\026cdrom read toc header", /* DCMD_READTOCHDR 22 */ 2011709Smlf "\027cdrom read toc entry", /* DCMD_READTOCENT 23 */ 2021709Smlf "\030cdrom read offset", /* DCMD_READOFFSET 24 */ 2031709Smlf "\031cdrom read mode 2", /* DCMD_READMODE2 25 */ 2041709Smlf "\032cdrom volume control", /* DCMD_VOLCTRL 26 */ 2051709Smlf "\033flush cache", /* DCMD_FLUSH_CACHE 27 */ 2061709Smlf NULL 2071709Smlf }; 2081709Smlf 2091709Smlf static char *dadk_sense[] = { 2101709Smlf "\000Success", /* DERR_SUCCESS */ 2111709Smlf "\001address mark not found", /* DERR_AMNF */ 2121709Smlf "\002track 0 not found", /* DERR_TKONF */ 2131709Smlf "\003aborted command", /* DERR_ABORT */ 2141709Smlf "\004write fault", /* DERR_DWF */ 2151709Smlf "\005ID not found", /* DERR_IDNF */ 2161709Smlf "\006drive busy", /* DERR_BUSY */ 2171709Smlf "\007uncorrectable data error", /* DERR_UNC */ 2181709Smlf "\010bad block detected", /* DERR_BBK */ 2191709Smlf "\011invalid command", /* DERR_INVCDB */ 2201709Smlf "\012device hard error", /* DERR_HARD */ 2211709Smlf "\013illegal length indicated", /* DERR_ILI */ 2221709Smlf "\014end of media", /* DERR_EOM */ 2231709Smlf "\015media change requested", /* DERR_MCR */ 2241709Smlf "\016recovered from error", /* DERR_RECOVER */ 2251709Smlf "\017device not ready", /* DERR_NOTREADY */ 2261709Smlf "\020medium error", /* DERR_MEDIUM */ 2271709Smlf "\021hardware error", /* DERR_HW */ 2281709Smlf "\022illegal request", /* DERR_ILL */ 2291709Smlf "\023unit attention", /* DERR_UNIT_ATTN */ 2301709Smlf "\024data protection", /* DERR_DATA_PROT */ 2311709Smlf "\025miscompare", /* DERR_MISCOMPARE */ 2321709Smlf "\026ICRC error during UDMA", /* DERR_ICRC */ 2331709Smlf "\027reserved", /* DERR_RESV */ 2341709Smlf NULL 2351709Smlf }; 2361709Smlf 2371709Smlf static char *dadk_name = "Disk"; 2381709Smlf 2391709Smlf /* 2401709Smlf * This is the loadable module wrapper 2411709Smlf */ 2421709Smlf #include <sys/modctl.h> 2431709Smlf 2441709Smlf extern struct mod_ops mod_miscops; 2451709Smlf 2461709Smlf static struct modlmisc modlmisc = { 2471709Smlf &mod_miscops, /* Type of module */ 2487239Szk194757 "Direct Attached Disk" 2491709Smlf }; 2501709Smlf 2511709Smlf static struct modlinkage modlinkage = { 2521709Smlf MODREV_1, (void *)&modlmisc, NULL 2531709Smlf }; 2541709Smlf 2551709Smlf int 2561709Smlf _init(void) 2571709Smlf { 2581709Smlf #ifdef DADK_DEBUG 2591709Smlf if (dadk_debug & DENT) 2601709Smlf PRF("dadk_init: call\n"); 2611709Smlf #endif 2621709Smlf 2631709Smlf #if defined(__x86) 2641709Smlf /* set the max physical address for iob allocs on x86 */ 2651709Smlf dadk_alloc_attr.dma_attr_addr_hi = dadk_max_phys_addr; 2661709Smlf 2671709Smlf /* 2681709Smlf * set the sgllen for iob allocs on x86. If this is set less than 2691709Smlf * the number of pages the buffer will take (taking into account 2701709Smlf * alignment), it would force the allocator to try and allocate 2711709Smlf * contiguous pages. 2721709Smlf */ 2731709Smlf dadk_alloc_attr.dma_attr_sgllen = dadk_sgl_size; 2741709Smlf #endif 2751709Smlf 2761709Smlf return (mod_install(&modlinkage)); 2771709Smlf } 2781709Smlf 2791709Smlf int 2801709Smlf _fini(void) 2811709Smlf { 2821709Smlf #ifdef DADK_DEBUG 2831709Smlf if (dadk_debug & DENT) 2841709Smlf PRF("dadk_fini: call\n"); 2851709Smlf #endif 2861709Smlf 2871709Smlf return (mod_remove(&modlinkage)); 2881709Smlf } 2891709Smlf 2901709Smlf int 2911709Smlf _info(struct modinfo *modinfop) 2921709Smlf { 2931709Smlf return (mod_info(&modlinkage, modinfop)); 2941709Smlf } 2951709Smlf 2961709Smlf struct tgdk_obj * 2971709Smlf dadk_create() 2981709Smlf { 2991709Smlf struct tgdk_obj *dkobjp; 3001709Smlf struct dadk *dadkp; 3011709Smlf 3021709Smlf dkobjp = kmem_zalloc((sizeof (*dkobjp) + sizeof (*dadkp)), KM_NOSLEEP); 3031709Smlf if (!dkobjp) 3041709Smlf return (NULL); 3051709Smlf dadkp = (struct dadk *)(dkobjp+1); 3061709Smlf 3071709Smlf dkobjp->tg_ops = (struct tgdk_objops *)&dadk_ops; 3081709Smlf dkobjp->tg_data = (opaque_t)dadkp; 3091709Smlf dkobjp->tg_ext = &(dkobjp->tg_extblk); 3101709Smlf dadkp->dad_extp = &(dkobjp->tg_extblk); 3111709Smlf 3121709Smlf #ifdef DADK_DEBUG 3131709Smlf if (dadk_debug & DENT) 3141709Smlf PRF("dadk_create: tgdkobjp= 0x%x dadkp= 0x%x\n", dkobjp, dadkp); 3151709Smlf #endif 3161709Smlf return (dkobjp); 3171709Smlf } 3181709Smlf 3191709Smlf int 3201709Smlf dadk_init(opaque_t objp, opaque_t devp, opaque_t flcobjp, opaque_t queobjp, 3211709Smlf opaque_t bbhobjp, void *lkarg) 3221709Smlf { 3231709Smlf struct dadk *dadkp = (struct dadk *)objp; 3241709Smlf struct scsi_device *sdevp = (struct scsi_device *)devp; 3251709Smlf 3261709Smlf dadkp->dad_sd = devp; 3271709Smlf dadkp->dad_ctlobjp = (opaque_t)sdevp->sd_address.a_hba_tran; 3281709Smlf sdevp->sd_private = (caddr_t)dadkp; 3291709Smlf 3301709Smlf /* initialize the communication object */ 3311709Smlf dadkp->dad_com.com_data = (opaque_t)dadkp; 3321709Smlf dadkp->dad_com.com_ops = &dadk_com_ops; 3331709Smlf 3341709Smlf dadkp->dad_bbhobjp = bbhobjp; 3351709Smlf BBH_INIT(bbhobjp); 3361709Smlf 3371709Smlf dadkp->dad_flcobjp = flcobjp; 3385295Srandyf mutex_init(&dadkp->dad_cmd_mutex, NULL, MUTEX_DRIVER, NULL); 3395295Srandyf dadkp->dad_cmd_count = 0; 3401709Smlf return (FLC_INIT(flcobjp, &(dadkp->dad_com), queobjp, lkarg)); 3411709Smlf } 3421709Smlf 3431709Smlf int 3441709Smlf dadk_free(struct tgdk_obj *dkobjp) 3451709Smlf { 3461709Smlf TGDK_CLEANUP(dkobjp); 3471709Smlf kmem_free(dkobjp, (sizeof (*dkobjp) + sizeof (struct dadk))); 3481709Smlf 3491709Smlf return (DDI_SUCCESS); 3501709Smlf } 3511709Smlf 3521709Smlf void 3531709Smlf dadk_cleanup(struct tgdk_obj *dkobjp) 3541709Smlf { 3551709Smlf struct dadk *dadkp; 3561709Smlf 3571709Smlf dadkp = (struct dadk *)(dkobjp->tg_data); 3581709Smlf if (dadkp->dad_sd) 3591709Smlf dadkp->dad_sd->sd_private = NULL; 3601709Smlf if (dadkp->dad_bbhobjp) { 3611709Smlf BBH_FREE(dadkp->dad_bbhobjp); 3621709Smlf dadkp->dad_bbhobjp = NULL; 3631709Smlf } 3641709Smlf if (dadkp->dad_flcobjp) { 3651709Smlf FLC_FREE(dadkp->dad_flcobjp); 3661709Smlf dadkp->dad_flcobjp = NULL; 3671709Smlf } 3685295Srandyf mutex_destroy(&dadkp->dad_cmd_mutex); 3691709Smlf } 3701709Smlf 3711709Smlf /* ARGSUSED */ 3721709Smlf int 3731709Smlf dadk_probe(opaque_t objp, int kmsflg) 3741709Smlf { 3751709Smlf struct dadk *dadkp = (struct dadk *)objp; 3761709Smlf struct scsi_device *devp; 3771709Smlf char name[80]; 3781709Smlf 3791709Smlf devp = dadkp->dad_sd; 3801709Smlf if (!devp->sd_inq || (devp->sd_inq->inq_dtype == DTYPE_NOTPRESENT) || 3815295Srandyf (devp->sd_inq->inq_dtype == DTYPE_UNKNOWN)) { 3821709Smlf return (DDI_PROBE_FAILURE); 3831709Smlf } 3841709Smlf 3851709Smlf switch (devp->sd_inq->inq_dtype) { 3861709Smlf case DTYPE_DIRECT: 3871709Smlf dadkp->dad_ctype = DKC_DIRECT; 3881709Smlf dadkp->dad_extp->tg_nodetype = DDI_NT_BLOCK; 3891709Smlf dadkp->dad_extp->tg_ctype = DKC_DIRECT; 3901709Smlf break; 3911709Smlf case DTYPE_RODIRECT: /* eg cdrom */ 3921709Smlf dadkp->dad_ctype = DKC_CDROM; 3931709Smlf dadkp->dad_extp->tg_rdonly = 1; 3941709Smlf dadkp->dad_rdonly = 1; 3951709Smlf dadkp->dad_cdrom = 1; 3961709Smlf dadkp->dad_extp->tg_nodetype = DDI_NT_CD; 3971709Smlf dadkp->dad_extp->tg_ctype = DKC_CDROM; 3981709Smlf break; 3991709Smlf case DTYPE_WORM: 4001709Smlf case DTYPE_OPTICAL: 4011709Smlf default: 4021709Smlf return (DDI_PROBE_FAILURE); 4031709Smlf } 4041709Smlf 4051709Smlf dadkp->dad_extp->tg_rmb = dadkp->dad_rmb = devp->sd_inq->inq_rmb; 4061709Smlf 4071709Smlf dadkp->dad_secshf = SCTRSHFT; 4081709Smlf dadkp->dad_blkshf = 0; 4091709Smlf 4101709Smlf /* display the device name */ 4111709Smlf (void) strcpy(name, "Vendor '"); 4121709Smlf gda_inqfill((caddr_t)devp->sd_inq->inq_vid, 8, &name[strlen(name)]); 4131709Smlf (void) strcat(name, "' Product '"); 4141709Smlf gda_inqfill((caddr_t)devp->sd_inq->inq_pid, 16, &name[strlen(name)]); 4151709Smlf (void) strcat(name, "'"); 4161709Smlf gda_log(devp->sd_dev, dadk_name, CE_NOTE, "!<%s>\n", name); 4171709Smlf 4181709Smlf return (DDI_PROBE_SUCCESS); 4191709Smlf } 4201709Smlf 4211709Smlf 4221709Smlf /* ARGSUSED */ 4231709Smlf int 4241709Smlf dadk_attach(opaque_t objp) 4251709Smlf { 4261709Smlf return (DDI_SUCCESS); 4271709Smlf } 4281709Smlf 4291709Smlf int 4301709Smlf dadk_set_bbhobj(opaque_t objp, opaque_t bbhobjp) 4311709Smlf { 4321709Smlf struct dadk *dadkp = (struct dadk *)objp; 4331709Smlf /* free the old bbh object */ 4341709Smlf if (dadkp->dad_bbhobjp) 4351709Smlf BBH_FREE(dadkp->dad_bbhobjp); 4361709Smlf 4371709Smlf /* initialize the new bbh object */ 4381709Smlf dadkp->dad_bbhobjp = bbhobjp; 4391709Smlf BBH_INIT(bbhobjp); 4401709Smlf 4411709Smlf return (DDI_SUCCESS); 4421709Smlf } 4431709Smlf 4441709Smlf /* ARGSUSED */ 4451709Smlf int 4461709Smlf dadk_open(opaque_t objp, int flag) 4471709Smlf { 4481709Smlf struct dadk *dadkp = (struct dadk *)objp; 4491709Smlf int error; 4501709Smlf int wce; 4511709Smlf 4521709Smlf if (!dadkp->dad_rmb) { 4531709Smlf if (dadkp->dad_phyg.g_cap) { 4541709Smlf FLC_START_KSTAT(dadkp->dad_flcobjp, "disk", 4551709Smlf ddi_get_instance(CTL_DIP_DEV(dadkp->dad_ctlobjp))); 4561709Smlf return (DDI_SUCCESS); 4571709Smlf } 4581709Smlf } else { 4595295Srandyf mutex_enter(&dadkp->dad_mutex); 4605295Srandyf dadkp->dad_iostate = DKIO_NONE; 4615295Srandyf cv_broadcast(&dadkp->dad_state_cv); 4625295Srandyf mutex_exit(&dadkp->dad_mutex); 4631709Smlf 4645295Srandyf if (dadk_rmb_ioctl(dadkp, DCMD_START_MOTOR, 0, 0, 4655295Srandyf DADK_SILENT) || 4665295Srandyf dadk_rmb_ioctl(dadkp, DCMD_LOCK, 0, 0, DADK_SILENT) || 4675295Srandyf dadk_rmb_ioctl(dadkp, DCMD_UPDATE_GEOM, 0, 0, 4685295Srandyf DADK_SILENT)) { 4695295Srandyf return (DDI_FAILURE); 4705295Srandyf } 4711709Smlf 4725295Srandyf mutex_enter(&dadkp->dad_mutex); 4735295Srandyf dadkp->dad_iostate = DKIO_INSERTED; 4745295Srandyf cv_broadcast(&dadkp->dad_state_cv); 4755295Srandyf mutex_exit(&dadkp->dad_mutex); 4761709Smlf } 4771709Smlf 4781709Smlf /* 4791709Smlf * get write cache enable state 4801709Smlf * If there is an error, must assume that write cache 4811709Smlf * is enabled. 4821709Smlf * NOTE: Since there is currently no Solaris mechanism to 4831709Smlf * change the state of the Write Cache Enable feature, 4841709Smlf * this code just checks the value of the WCE bit 4851709Smlf * obtained at device init time. If a mechanism 4861709Smlf * is added to the driver to change WCE, dad_wce 4871709Smlf * must be updated appropriately. 4881709Smlf */ 4895295Srandyf error = dadk_ctl_ioctl(dadkp, DIOCTL_GETWCE, 4902799Smarx (uintptr_t)&wce, FKIOCTL | FNATIVE); 4911709Smlf mutex_enter(&dadkp->dad_mutex); 4921709Smlf dadkp->dad_wce = (error != 0) || (wce != 0); 4931709Smlf mutex_exit(&dadkp->dad_mutex); 4941709Smlf 4951709Smlf /* logical disk geometry */ 4965295Srandyf (void) dadk_ctl_ioctl(dadkp, DIOCTL_GETGEOM, 4972799Smarx (uintptr_t)&dadkp->dad_logg, FKIOCTL | FNATIVE); 4981709Smlf if (dadkp->dad_logg.g_cap == 0) 4991709Smlf return (DDI_FAILURE); 5001709Smlf 5011709Smlf /* get physical disk geometry */ 5025295Srandyf (void) dadk_ctl_ioctl(dadkp, DIOCTL_GETPHYGEOM, 5032799Smarx (uintptr_t)&dadkp->dad_phyg, FKIOCTL | FNATIVE); 5041709Smlf if (dadkp->dad_phyg.g_cap == 0) 5051709Smlf return (DDI_FAILURE); 5061709Smlf 5071709Smlf dadk_setcap(dadkp); 5081709Smlf 5092799Smarx dadk_create_errstats(dadkp, 5102799Smarx ddi_get_instance(CTL_DIP_DEV(dadkp->dad_ctlobjp))); 5112799Smarx 5121709Smlf /* start profiling */ 5131709Smlf FLC_START_KSTAT(dadkp->dad_flcobjp, "disk", 5145295Srandyf ddi_get_instance(CTL_DIP_DEV(dadkp->dad_ctlobjp))); 5151709Smlf 5161709Smlf return (DDI_SUCCESS); 5171709Smlf } 5181709Smlf 5191709Smlf static void 5201709Smlf dadk_setcap(struct dadk *dadkp) 5211709Smlf { 5221709Smlf int totsize; 5231709Smlf int i; 5241709Smlf 5251709Smlf totsize = dadkp->dad_phyg.g_secsiz; 5261709Smlf 5271709Smlf if (totsize == 0) { 5281709Smlf if (dadkp->dad_cdrom) { 5291709Smlf totsize = 2048; 5301709Smlf } else { 5311709Smlf totsize = NBPSCTR; 5321709Smlf } 5331709Smlf } else { 5341709Smlf /* Round down sector size to multiple of 512B */ 5351709Smlf totsize &= ~(NBPSCTR-1); 5361709Smlf } 5371709Smlf dadkp->dad_phyg.g_secsiz = totsize; 5381709Smlf 5391709Smlf /* set sec,block shift factor - (512->0, 1024->1, 2048->2, etc.) */ 5401709Smlf totsize >>= SCTRSHFT; 5415295Srandyf for (i = 0; totsize != 1; i++, totsize >>= 1) 5425295Srandyf ; 5431709Smlf dadkp->dad_blkshf = i; 5441709Smlf dadkp->dad_secshf = i + SCTRSHFT; 5451709Smlf } 5461709Smlf 5471709Smlf 5482799Smarx static void 5492799Smarx dadk_create_errstats(struct dadk *dadkp, int instance) 5502799Smarx { 5512799Smarx dadk_errstats_t *dep; 5522799Smarx char kstatname[KSTAT_STRLEN]; 5532799Smarx dadk_ioc_string_t dadk_ioc_string; 5542799Smarx 5552799Smarx if (dadkp->dad_errstats) 5562799Smarx return; 5572799Smarx 5582799Smarx (void) sprintf(kstatname, "cmdk%d,error", instance); 5592799Smarx dadkp->dad_errstats = kstat_create("cmdkerror", instance, 5602799Smarx kstatname, "device_error", KSTAT_TYPE_NAMED, 5612799Smarx sizeof (dadk_errstats_t) / sizeof (kstat_named_t), 5622799Smarx KSTAT_FLAG_PERSISTENT); 5632799Smarx 5642799Smarx if (!dadkp->dad_errstats) 5652799Smarx return; 5662799Smarx 5672799Smarx dep = (dadk_errstats_t *)dadkp->dad_errstats->ks_data; 5682799Smarx 5692799Smarx kstat_named_init(&dep->dadk_softerrs, 5702799Smarx "Soft Errors", KSTAT_DATA_UINT32); 5712799Smarx kstat_named_init(&dep->dadk_harderrs, 5722799Smarx "Hard Errors", KSTAT_DATA_UINT32); 5732799Smarx kstat_named_init(&dep->dadk_transerrs, 5742799Smarx "Transport Errors", KSTAT_DATA_UINT32); 5752799Smarx kstat_named_init(&dep->dadk_model, 5762799Smarx "Model", KSTAT_DATA_CHAR); 5772799Smarx kstat_named_init(&dep->dadk_revision, 5782799Smarx "Revision", KSTAT_DATA_CHAR); 5792799Smarx kstat_named_init(&dep->dadk_serial, 5802799Smarx "Serial No", KSTAT_DATA_CHAR); 5812799Smarx kstat_named_init(&dep->dadk_capacity, 5822799Smarx "Size", KSTAT_DATA_ULONGLONG); 5832799Smarx kstat_named_init(&dep->dadk_rq_media_err, 5842799Smarx "Media Error", KSTAT_DATA_UINT32); 5852799Smarx kstat_named_init(&dep->dadk_rq_ntrdy_err, 5862799Smarx "Device Not Ready", KSTAT_DATA_UINT32); 5872799Smarx kstat_named_init(&dep->dadk_rq_nodev_err, 5882799Smarx "No Device", KSTAT_DATA_UINT32); 5892799Smarx kstat_named_init(&dep->dadk_rq_recov_err, 5902799Smarx "Recoverable", KSTAT_DATA_UINT32); 5912799Smarx kstat_named_init(&dep->dadk_rq_illrq_err, 5922799Smarx "Illegal Request", KSTAT_DATA_UINT32); 5932799Smarx 5942799Smarx dadkp->dad_errstats->ks_private = dep; 5952799Smarx dadkp->dad_errstats->ks_update = nulldev; 5962799Smarx kstat_install(dadkp->dad_errstats); 5972799Smarx 5982799Smarx /* get model */ 5992799Smarx dep->dadk_model.value.c[0] = 0; 6002799Smarx dadk_ioc_string.is_buf = &dep->dadk_model.value.c[0]; 6013399Smarx dadk_ioc_string.is_size = sizeof (dep->dadk_model.value.c); 6025295Srandyf (void) dadk_ctl_ioctl(dadkp, DIOCTL_GETMODEL, 6032799Smarx (uintptr_t)&dadk_ioc_string, FKIOCTL | FNATIVE); 6042799Smarx 6052799Smarx /* get serial */ 6062799Smarx dep->dadk_serial.value.c[0] = 0; 6072799Smarx dadk_ioc_string.is_buf = &dep->dadk_serial.value.c[0]; 6083399Smarx dadk_ioc_string.is_size = sizeof (dep->dadk_serial.value.c); 6095295Srandyf (void) dadk_ctl_ioctl(dadkp, DIOCTL_GETSERIAL, 6102799Smarx (uintptr_t)&dadk_ioc_string, FKIOCTL | FNATIVE); 6112799Smarx 6122799Smarx /* Get revision */ 6132799Smarx dep->dadk_revision.value.c[0] = 0; 6142799Smarx 6152799Smarx /* Get capacity */ 6162799Smarx 6172799Smarx dep->dadk_capacity.value.ui64 = 6182799Smarx (uint64_t)dadkp->dad_logg.g_cap * 6192799Smarx (uint64_t)dadkp->dad_logg.g_secsiz; 6202799Smarx } 6212799Smarx 6222799Smarx 6231709Smlf int 6241709Smlf dadk_close(opaque_t objp) 6251709Smlf { 6261709Smlf struct dadk *dadkp = (struct dadk *)objp; 6271709Smlf 6281709Smlf if (dadkp->dad_rmb) { 6291709Smlf (void) dadk_rmb_ioctl(dadkp, DCMD_STOP_MOTOR, 0, 0, 6301709Smlf DADK_SILENT); 6311709Smlf (void) dadk_rmb_ioctl(dadkp, DCMD_UNLOCK, 0, 0, DADK_SILENT); 6321709Smlf } 6331709Smlf FLC_STOP_KSTAT(dadkp->dad_flcobjp); 6342799Smarx 6352799Smarx dadk_destroy_errstats(dadkp); 6362799Smarx 6371709Smlf return (DDI_SUCCESS); 6381709Smlf } 6391709Smlf 6402799Smarx static void 6412799Smarx dadk_destroy_errstats(struct dadk *dadkp) 6422799Smarx { 6432799Smarx if (!dadkp->dad_errstats) 6442799Smarx return; 6452799Smarx 6462799Smarx kstat_delete(dadkp->dad_errstats); 6472799Smarx dadkp->dad_errstats = NULL; 6482799Smarx } 6492799Smarx 6502799Smarx 6511709Smlf int 6521709Smlf dadk_strategy(opaque_t objp, struct buf *bp) 6531709Smlf { 6541709Smlf struct dadk *dadkp = (struct dadk *)objp; 6551709Smlf 6561709Smlf if (dadkp->dad_rdonly && !(bp->b_flags & B_READ)) { 6571709Smlf bioerror(bp, EROFS); 6581709Smlf return (DDI_FAILURE); 6591709Smlf } 6601709Smlf 6611709Smlf if (bp->b_bcount & (dadkp->DAD_SECSIZ-1)) { 6621709Smlf bioerror(bp, ENXIO); 6631709Smlf return (DDI_FAILURE); 6641709Smlf } 6651709Smlf 6661709Smlf SET_BP_SEC(bp, (LBLK2SEC(GET_BP_SEC(bp), dadkp->dad_blkshf))); 6675295Srandyf mutex_enter(&dadkp->dad_cmd_mutex); 6685295Srandyf dadkp->dad_cmd_count++; 6695295Srandyf mutex_exit(&dadkp->dad_cmd_mutex); 6701709Smlf FLC_ENQUE(dadkp->dad_flcobjp, bp); 6711709Smlf 6721709Smlf return (DDI_SUCCESS); 6731709Smlf } 6741709Smlf 6751709Smlf int 6761709Smlf dadk_dump(opaque_t objp, struct buf *bp) 6771709Smlf { 6781709Smlf struct dadk *dadkp = (struct dadk *)objp; 6791709Smlf struct cmpkt *pktp; 6801709Smlf 6811709Smlf if (dadkp->dad_rdonly) { 6821709Smlf bioerror(bp, EROFS); 6831709Smlf return (DDI_FAILURE); 6841709Smlf } 6851709Smlf 6861709Smlf if (bp->b_bcount & (dadkp->DAD_SECSIZ-1)) { 6871709Smlf bioerror(bp, ENXIO); 6881709Smlf return (DDI_FAILURE); 6891709Smlf } 6901709Smlf 6911709Smlf SET_BP_SEC(bp, (LBLK2SEC(GET_BP_SEC(bp), dadkp->dad_blkshf))); 6921709Smlf 6931709Smlf pktp = dadk_pktprep(dadkp, NULL, bp, dadk_polldone, NULL, NULL); 6941709Smlf if (!pktp) { 6951709Smlf cmn_err(CE_WARN, "no resources for dumping"); 6961709Smlf bioerror(bp, EIO); 6971709Smlf return (DDI_FAILURE); 6981709Smlf } 6991709Smlf pktp->cp_flags |= CPF_NOINTR; 7001709Smlf 7011709Smlf (void) dadk_ioprep(dadkp, pktp); 7021709Smlf dadk_transport(dadkp, bp); 7031709Smlf pktp->cp_byteleft -= pktp->cp_bytexfer; 7041709Smlf 7051709Smlf while (geterror(bp) == 0 && pktp->cp_byteleft != 0) { 7061709Smlf (void) dadk_iosetup(dadkp, pktp); 7071709Smlf dadk_transport(dadkp, bp); 7081709Smlf pktp->cp_byteleft -= pktp->cp_bytexfer; 7091709Smlf } 7101709Smlf 7111709Smlf if (pktp->cp_private) 7121709Smlf BBH_FREEHANDLE(dadkp->dad_bbhobjp, pktp->cp_private); 7131709Smlf gda_free(dadkp->dad_ctlobjp, pktp, NULL); 7141709Smlf return (DDI_SUCCESS); 7151709Smlf } 7161709Smlf 7171709Smlf /* ARGSUSED */ 7181709Smlf int 7191709Smlf dadk_ioctl(opaque_t objp, dev_t dev, int cmd, intptr_t arg, int flag, 7201709Smlf cred_t *cred_p, int *rval_p) 7211709Smlf { 7221709Smlf struct dadk *dadkp = (struct dadk *)objp; 7231709Smlf 7241709Smlf switch (cmd) { 7251709Smlf case DKIOCGETDEF: 7265295Srandyf { 7271709Smlf struct buf *bp; 7281709Smlf int err, head; 7291709Smlf unsigned char *secbuf; 7301709Smlf STRUCT_DECL(defect_header, adh); 7311709Smlf 7321709Smlf STRUCT_INIT(adh, flag & FMODELS); 7331709Smlf 7341709Smlf /* 7351709Smlf * copyin header .... 7361709Smlf * yields head number and buffer address 7371709Smlf */ 7381709Smlf if (ddi_copyin((caddr_t)arg, STRUCT_BUF(adh), STRUCT_SIZE(adh), 7391709Smlf flag)) 7401709Smlf return (EFAULT); 7411709Smlf head = STRUCT_FGET(adh, head); 7421709Smlf if (head < 0 || head >= dadkp->dad_phyg.g_head) 7431709Smlf return (ENXIO); 7441709Smlf secbuf = kmem_zalloc(NBPSCTR, KM_SLEEP); 7451709Smlf if (!secbuf) 7461709Smlf return (ENOMEM); 7471709Smlf bp = getrbuf(KM_SLEEP); 7481709Smlf if (!bp) { 7491709Smlf kmem_free(secbuf, NBPSCTR); 7501709Smlf return (ENOMEM); 7511709Smlf } 7521709Smlf 7531709Smlf bp->b_edev = dev; 7541709Smlf bp->b_dev = cmpdev(dev); 7551709Smlf bp->b_flags = B_BUSY; 7561709Smlf bp->b_resid = 0; 7571709Smlf bp->b_bcount = NBPSCTR; 7581709Smlf bp->b_un.b_addr = (caddr_t)secbuf; 7591709Smlf bp->b_blkno = head; /* I had to put it somwhere! */ 7601709Smlf bp->b_forw = (struct buf *)dadkp; 7611709Smlf bp->b_back = (struct buf *)DCMD_GETDEF; 7621709Smlf 7635295Srandyf mutex_enter(&dadkp->dad_cmd_mutex); 7645295Srandyf dadkp->dad_cmd_count++; 7655295Srandyf mutex_exit(&dadkp->dad_cmd_mutex); 7661709Smlf FLC_ENQUE(dadkp->dad_flcobjp, bp); 7671709Smlf err = biowait(bp); 7681709Smlf if (!err) { 7691709Smlf if (ddi_copyout((caddr_t)secbuf, 7701709Smlf STRUCT_FGETP(adh, buffer), NBPSCTR, flag)) 7711709Smlf err = ENXIO; 7721709Smlf } 7731709Smlf kmem_free(secbuf, NBPSCTR); 7741709Smlf freerbuf(bp); 7751709Smlf return (err); 7765295Srandyf } 7771709Smlf case DIOCTL_RWCMD: 7785295Srandyf { 7791709Smlf struct dadkio_rwcmd *rwcmdp; 7801709Smlf int status, rw; 7811709Smlf 7821709Smlf /* 7831709Smlf * copied in by cmdk and, if necessary, converted to the 7841709Smlf * correct datamodel 7851709Smlf */ 7861709Smlf rwcmdp = (struct dadkio_rwcmd *)(intptr_t)arg; 7871709Smlf 7881709Smlf /* 7891709Smlf * handle the complex cases here; we pass these 7901709Smlf * through to the driver, which will queue them and 7911709Smlf * handle the requests asynchronously. The simpler 7921709Smlf * cases ,which can return immediately, fail here, and 7931709Smlf * the request reverts to the dadk_ioctl routine, while 7941709Smlf * will reroute them directly to the ata driver. 7951709Smlf */ 7961709Smlf switch (rwcmdp->cmd) { 7971709Smlf case DADKIO_RWCMD_READ : 7981709Smlf /*FALLTHROUGH*/ 7991709Smlf case DADKIO_RWCMD_WRITE: 8001709Smlf rw = ((rwcmdp->cmd == DADKIO_RWCMD_WRITE) ? 8011709Smlf B_WRITE : B_READ); 8021709Smlf status = dadk_dk_buf_setup(dadkp, 8031709Smlf (opaque_t)rwcmdp, dev, ((flag &FKIOCTL) ? 8041709Smlf UIO_SYSSPACE : UIO_USERSPACE), rw); 8051709Smlf return (status); 8061709Smlf default: 8071709Smlf return (EINVAL); 8085295Srandyf } 8091709Smlf } 8103652Syt160523 case DKIOC_UPDATEFW: 8113652Syt160523 8123652Syt160523 /* 8133652Syt160523 * Require PRIV_ALL privilege to invoke DKIOC_UPDATEFW 8143652Syt160523 * to protect the firmware update from malicious use 8153652Syt160523 */ 8163652Syt160523 if (PRIV_POLICY(cred_p, PRIV_ALL, B_FALSE, EPERM, NULL) != 0) 8173652Syt160523 return (EPERM); 8183652Syt160523 else 8195295Srandyf return (dadk_ctl_ioctl(dadkp, cmd, arg, flag)); 8203652Syt160523 8211709Smlf case DKIOCFLUSHWRITECACHE: 8221709Smlf { 8231709Smlf struct buf *bp; 8241709Smlf int err = 0; 8251709Smlf struct dk_callback *dkc = (struct dk_callback *)arg; 8261709Smlf struct cmpkt *pktp; 8271709Smlf int is_sync = 1; 8281709Smlf 8291709Smlf mutex_enter(&dadkp->dad_mutex); 8301709Smlf if (dadkp->dad_noflush || ! dadkp->dad_wce) { 8311709Smlf err = dadkp->dad_noflush ? ENOTSUP : 0; 8321709Smlf mutex_exit(&dadkp->dad_mutex); 8331709Smlf /* 8341709Smlf * If a callback was requested: a 8351709Smlf * callback will always be done if the 8361709Smlf * caller saw the DKIOCFLUSHWRITECACHE 8371709Smlf * ioctl return 0, and never done if the 8381709Smlf * caller saw the ioctl return an error. 8391709Smlf */ 8401709Smlf if ((flag & FKIOCTL) && dkc != NULL && 8411709Smlf dkc->dkc_callback != NULL) { 8421709Smlf (*dkc->dkc_callback)(dkc->dkc_cookie, 8431709Smlf err); 8441709Smlf /* 8451709Smlf * Did callback and reported error. 8461709Smlf * Since we did a callback, ioctl 8471709Smlf * should return 0. 8481709Smlf */ 8491709Smlf err = 0; 8501709Smlf } 8511709Smlf return (err); 8521709Smlf } 8531709Smlf mutex_exit(&dadkp->dad_mutex); 8541709Smlf 8551709Smlf bp = getrbuf(KM_SLEEP); 8561709Smlf 8571709Smlf bp->b_edev = dev; 8581709Smlf bp->b_dev = cmpdev(dev); 8591709Smlf bp->b_flags = B_BUSY; 8601709Smlf bp->b_resid = 0; 8611709Smlf bp->b_bcount = 0; 8621709Smlf SET_BP_SEC(bp, 0); 8631709Smlf 8641709Smlf if ((flag & FKIOCTL) && dkc != NULL && 8651709Smlf dkc->dkc_callback != NULL) { 8661709Smlf struct dk_callback *dkc2 = 8671709Smlf (struct dk_callback *)kmem_zalloc( 8681709Smlf sizeof (struct dk_callback), KM_SLEEP); 8691709Smlf 8701709Smlf bcopy(dkc, dkc2, sizeof (*dkc2)); 8711709Smlf /* 8721709Smlf * Borrow b_list to carry private data 8731709Smlf * to the b_iodone func. 8741709Smlf */ 8751709Smlf bp->b_list = (struct buf *)dkc2; 8761709Smlf bp->b_iodone = dadk_flushdone; 8771709Smlf is_sync = 0; 8781709Smlf } 8791709Smlf 8801709Smlf /* 8811709Smlf * Setup command pkt 8821709Smlf * dadk_pktprep() can't fail since DDI_DMA_SLEEP set 8831709Smlf */ 8841709Smlf pktp = dadk_pktprep(dadkp, NULL, bp, 8851709Smlf dadk_iodone, DDI_DMA_SLEEP, NULL); 8861709Smlf 8871709Smlf pktp->cp_time = DADK_FLUSH_CACHE_TIME; 8881709Smlf 8891709Smlf *((char *)(pktp->cp_cdbp)) = DCMD_FLUSH_CACHE; 8901709Smlf pktp->cp_byteleft = 0; 8911709Smlf pktp->cp_private = NULL; 8921709Smlf pktp->cp_secleft = 0; 8931709Smlf pktp->cp_srtsec = -1; 8941709Smlf pktp->cp_bytexfer = 0; 8951709Smlf 8961709Smlf CTL_IOSETUP(dadkp->dad_ctlobjp, pktp); 8971709Smlf 8985295Srandyf mutex_enter(&dadkp->dad_cmd_mutex); 8995295Srandyf dadkp->dad_cmd_count++; 9005295Srandyf mutex_exit(&dadkp->dad_cmd_mutex); 9011709Smlf FLC_ENQUE(dadkp->dad_flcobjp, bp); 9021709Smlf 9031709Smlf if (is_sync) { 9041709Smlf err = biowait(bp); 9051709Smlf freerbuf(bp); 9061709Smlf } 9071709Smlf return (err); 9081709Smlf } 9091709Smlf default: 9101709Smlf if (!dadkp->dad_rmb) 9115295Srandyf return (dadk_ctl_ioctl(dadkp, cmd, arg, flag)); 9121709Smlf } 9131709Smlf 9141709Smlf switch (cmd) { 9151709Smlf case CDROMSTOP: 9161709Smlf return (dadk_rmb_ioctl(dadkp, DCMD_STOP_MOTOR, 0, 9175295Srandyf 0, DADK_SILENT)); 9181709Smlf case CDROMSTART: 9191709Smlf return (dadk_rmb_ioctl(dadkp, DCMD_START_MOTOR, 0, 9205295Srandyf 0, DADK_SILENT)); 9211709Smlf case DKIOCLOCK: 9221709Smlf return (dadk_rmb_ioctl(dadkp, DCMD_LOCK, 0, 0, DADK_SILENT)); 9231709Smlf case DKIOCUNLOCK: 9241709Smlf return (dadk_rmb_ioctl(dadkp, DCMD_UNLOCK, 0, 0, DADK_SILENT)); 9251709Smlf case DKIOCEJECT: 9261709Smlf case CDROMEJECT: 9271709Smlf { 9281709Smlf int ret; 9291709Smlf 9301709Smlf if (ret = dadk_rmb_ioctl(dadkp, DCMD_UNLOCK, 0, 0, 9315295Srandyf DADK_SILENT)) { 9321709Smlf return (ret); 9331709Smlf } 9341709Smlf if (ret = dadk_rmb_ioctl(dadkp, DCMD_EJECT, 0, 0, 9355295Srandyf DADK_SILENT)) { 9361709Smlf return (ret); 9371709Smlf } 9381709Smlf mutex_enter(&dadkp->dad_mutex); 9391709Smlf dadkp->dad_iostate = DKIO_EJECTED; 9401709Smlf cv_broadcast(&dadkp->dad_state_cv); 9411709Smlf mutex_exit(&dadkp->dad_mutex); 9421709Smlf 9431709Smlf return (0); 9441709Smlf 9451709Smlf } 9461709Smlf default: 9471709Smlf return (ENOTTY); 9481709Smlf /* 9491709Smlf * cdrom audio commands 9501709Smlf */ 9511709Smlf case CDROMPAUSE: 9521709Smlf cmd = DCMD_PAUSE; 9531709Smlf break; 9541709Smlf case CDROMRESUME: 9551709Smlf cmd = DCMD_RESUME; 9561709Smlf break; 9571709Smlf case CDROMPLAYMSF: 9581709Smlf cmd = DCMD_PLAYMSF; 9591709Smlf break; 9601709Smlf case CDROMPLAYTRKIND: 9611709Smlf cmd = DCMD_PLAYTRKIND; 9621709Smlf break; 9631709Smlf case CDROMREADTOCHDR: 9641709Smlf cmd = DCMD_READTOCHDR; 9651709Smlf break; 9661709Smlf case CDROMREADTOCENTRY: 9671709Smlf cmd = DCMD_READTOCENT; 9681709Smlf break; 9691709Smlf case CDROMVOLCTRL: 9701709Smlf cmd = DCMD_VOLCTRL; 9711709Smlf break; 9721709Smlf case CDROMSUBCHNL: 9731709Smlf cmd = DCMD_SUBCHNL; 9741709Smlf break; 9751709Smlf case CDROMREADMODE2: 9761709Smlf cmd = DCMD_READMODE2; 9771709Smlf break; 9781709Smlf case CDROMREADMODE1: 9791709Smlf cmd = DCMD_READMODE1; 9801709Smlf break; 9811709Smlf case CDROMREADOFFSET: 9821709Smlf cmd = DCMD_READOFFSET; 9831709Smlf break; 9841709Smlf } 9851709Smlf return (dadk_rmb_ioctl(dadkp, cmd, arg, flag, 0)); 9861709Smlf } 9871709Smlf 9881709Smlf int 9891709Smlf dadk_flushdone(struct buf *bp) 9901709Smlf { 9911709Smlf struct dk_callback *dkc = (struct dk_callback *)bp->b_list; 9921709Smlf 9931709Smlf ASSERT(dkc != NULL && dkc->dkc_callback != NULL); 9941709Smlf 9951709Smlf (*dkc->dkc_callback)(dkc->dkc_cookie, geterror(bp)); 9961709Smlf 9971709Smlf kmem_free(dkc, sizeof (*dkc)); 9981709Smlf freerbuf(bp); 9991709Smlf return (0); 10001709Smlf } 10011709Smlf 10021709Smlf int 10031709Smlf dadk_getphygeom(opaque_t objp, struct tgdk_geom *dkgeom_p) 10041709Smlf { 10051709Smlf struct dadk *dadkp = (struct dadk *)objp; 10061709Smlf 10071709Smlf bcopy((caddr_t)&dadkp->dad_phyg, (caddr_t)dkgeom_p, 10081709Smlf sizeof (struct tgdk_geom)); 10091709Smlf return (DDI_SUCCESS); 10101709Smlf } 10111709Smlf 10121709Smlf int 10131709Smlf dadk_getgeom(opaque_t objp, struct tgdk_geom *dkgeom_p) 10141709Smlf { 10151709Smlf struct dadk *dadkp = (struct dadk *)objp; 10161709Smlf bcopy((caddr_t)&dadkp->dad_logg, (caddr_t)dkgeom_p, 10171709Smlf sizeof (struct tgdk_geom)); 10181709Smlf return (DDI_SUCCESS); 10191709Smlf } 10201709Smlf 10211709Smlf int 10221709Smlf dadk_setgeom(opaque_t objp, struct tgdk_geom *dkgeom_p) 10231709Smlf { 10241709Smlf struct dadk *dadkp = (struct dadk *)objp; 10251709Smlf 10261709Smlf dadkp->dad_logg.g_cyl = dkgeom_p->g_cyl; 10271709Smlf dadkp->dad_logg.g_head = dkgeom_p->g_head; 10281709Smlf dadkp->dad_logg.g_sec = dkgeom_p->g_sec; 10291709Smlf dadkp->dad_logg.g_cap = dkgeom_p->g_cap; 10301709Smlf return (DDI_SUCCESS); 10311709Smlf } 10321709Smlf 10331709Smlf 10341709Smlf tgdk_iob_handle 10351709Smlf dadk_iob_alloc(opaque_t objp, daddr_t blkno, ssize_t xfer, int kmsflg) 10361709Smlf { 10371709Smlf struct dadk *dadkp = (struct dadk *)objp; 10381709Smlf struct buf *bp; 10391709Smlf struct tgdk_iob *iobp; 10401709Smlf size_t rlen; 10411709Smlf 10421709Smlf iobp = kmem_zalloc(sizeof (*iobp), kmsflg); 10431709Smlf if (iobp == NULL) 10441709Smlf return (NULL); 10451709Smlf if ((bp = getrbuf(kmsflg)) == NULL) { 10461709Smlf kmem_free(iobp, sizeof (*iobp)); 10471709Smlf return (NULL); 10481709Smlf } 10491709Smlf 10501709Smlf iobp->b_psec = LBLK2SEC(blkno, dadkp->dad_blkshf); 10511709Smlf iobp->b_pbyteoff = (blkno & ((1<<dadkp->dad_blkshf) - 1)) << SCTRSHFT; 10521709Smlf iobp->b_pbytecnt = ((iobp->b_pbyteoff + xfer + dadkp->DAD_SECSIZ - 1) 10535295Srandyf >> dadkp->dad_secshf) << dadkp->dad_secshf; 10541709Smlf 10551709Smlf bp->b_un.b_addr = 0; 10561709Smlf /* 10571709Smlf * use i_ddi_mem_alloc() for now until we have an interface to allocate 10581709Smlf * memory for DMA which doesn't require a DMA handle. ddi_iopb_alloc() 10591709Smlf * is obsolete and we want more flexibility in controlling the DMA 10601709Smlf * address constraints.. 10611709Smlf */ 10621709Smlf if (i_ddi_mem_alloc((dadkp->dad_sd)->sd_dev, &dadk_alloc_attr, 10631709Smlf (size_t)iobp->b_pbytecnt, ((kmsflg == KM_SLEEP) ? 1 : 0), 0, NULL, 10641709Smlf &bp->b_un.b_addr, &rlen, NULL) != DDI_SUCCESS) { 10651709Smlf freerbuf(bp); 10661709Smlf kmem_free(iobp, sizeof (*iobp)); 10671709Smlf return (NULL); 10681709Smlf } 10691709Smlf iobp->b_flag |= IOB_BPALLOC | IOB_BPBUFALLOC; 10701709Smlf iobp->b_bp = bp; 10711709Smlf iobp->b_lblk = blkno; 10721709Smlf iobp->b_xfer = xfer; 10731709Smlf iobp->b_lblk = blkno; 10741709Smlf iobp->b_xfer = xfer; 10751709Smlf return (iobp); 10761709Smlf } 10771709Smlf 10781709Smlf /* ARGSUSED */ 10791709Smlf int 10801709Smlf dadk_iob_free(opaque_t objp, struct tgdk_iob *iobp) 10811709Smlf { 10821709Smlf struct buf *bp; 10831709Smlf 10841709Smlf if (iobp) { 10851709Smlf if (iobp->b_bp && (iobp->b_flag & IOB_BPALLOC)) { 10861709Smlf bp = iobp->b_bp; 10871709Smlf if (bp->b_un.b_addr && (iobp->b_flag & IOB_BPBUFALLOC)) 10881900Seota i_ddi_mem_free((caddr_t)bp->b_un.b_addr, NULL); 10891709Smlf freerbuf(bp); 10901709Smlf } 10911709Smlf kmem_free(iobp, sizeof (*iobp)); 10921709Smlf } 10931709Smlf return (DDI_SUCCESS); 10941709Smlf } 10951709Smlf 10961709Smlf /* ARGSUSED */ 10971709Smlf caddr_t 10981709Smlf dadk_iob_htoc(opaque_t objp, struct tgdk_iob *iobp) 10991709Smlf { 11001709Smlf return (iobp->b_bp->b_un.b_addr+iobp->b_pbyteoff); 11011709Smlf } 11021709Smlf 11031709Smlf 11041709Smlf caddr_t 11051709Smlf dadk_iob_xfer(opaque_t objp, struct tgdk_iob *iobp, int rw) 11061709Smlf { 11071709Smlf struct dadk *dadkp = (struct dadk *)objp; 11081709Smlf struct buf *bp; 11091709Smlf int err; 11101709Smlf 11111709Smlf bp = iobp->b_bp; 11121709Smlf if (dadkp->dad_rdonly && !(rw & B_READ)) { 11131709Smlf bioerror(bp, EROFS); 11141709Smlf return (NULL); 11151709Smlf } 11161709Smlf 11171709Smlf bp->b_flags |= (B_BUSY | rw); 11181709Smlf bp->b_bcount = iobp->b_pbytecnt; 11191709Smlf SET_BP_SEC(bp, iobp->b_psec); 11201709Smlf bp->av_back = (struct buf *)0; 11211709Smlf bp->b_resid = 0; 11221709Smlf 11231709Smlf /* call flow control */ 11245295Srandyf mutex_enter(&dadkp->dad_cmd_mutex); 11255295Srandyf dadkp->dad_cmd_count++; 11265295Srandyf mutex_exit(&dadkp->dad_cmd_mutex); 11271709Smlf FLC_ENQUE(dadkp->dad_flcobjp, bp); 11281709Smlf err = biowait(bp); 11291709Smlf 11301709Smlf bp->b_bcount = iobp->b_xfer; 11311709Smlf bp->b_flags &= ~(B_DONE|B_BUSY); 11321709Smlf 11331709Smlf if (err) 11341709Smlf return (NULL); 11351709Smlf 11361709Smlf return (bp->b_un.b_addr+iobp->b_pbyteoff); 11371709Smlf } 11381709Smlf 11391709Smlf static void 11401709Smlf dadk_transport(opaque_t com_data, struct buf *bp) 11411709Smlf { 11421709Smlf struct dadk *dadkp = (struct dadk *)com_data; 11431709Smlf 11441709Smlf if (CTL_TRANSPORT(dadkp->dad_ctlobjp, GDA_BP_PKT(bp)) == 11451709Smlf CTL_SEND_SUCCESS) 11461709Smlf return; 11471709Smlf dadk_restart((void*)GDA_BP_PKT(bp)); 11481709Smlf } 11491709Smlf 11501709Smlf static int 11511709Smlf dadk_pkt(opaque_t com_data, struct buf *bp, int (*func)(caddr_t), caddr_t arg) 11521709Smlf { 11531709Smlf struct cmpkt *pktp; 11541709Smlf struct dadk *dadkp = (struct dadk *)com_data; 11551709Smlf 11561709Smlf if (GDA_BP_PKT(bp)) 11571709Smlf return (DDI_SUCCESS); 11581709Smlf 11591709Smlf pktp = dadk_pktprep(dadkp, NULL, bp, dadk_iodone, func, arg); 11601709Smlf if (!pktp) 11611709Smlf return (DDI_FAILURE); 11621709Smlf 11631709Smlf return (dadk_ioprep(dadkp, pktp)); 11641709Smlf } 11651709Smlf 11661709Smlf /* 11671709Smlf * Read, Write preparation 11681709Smlf */ 11691709Smlf static int 11701709Smlf dadk_ioprep(struct dadk *dadkp, struct cmpkt *pktp) 11711709Smlf { 11721709Smlf struct buf *bp; 11731709Smlf 11741709Smlf bp = pktp->cp_bp; 11751709Smlf if (bp->b_forw == (struct buf *)dadkp) 11761709Smlf *((char *)(pktp->cp_cdbp)) = (char)(intptr_t)bp->b_back; 11771709Smlf 11781709Smlf else if (bp->b_flags & B_READ) 11791709Smlf *((char *)(pktp->cp_cdbp)) = DCMD_READ; 11801709Smlf else 11811709Smlf *((char *)(pktp->cp_cdbp)) = DCMD_WRITE; 11821709Smlf pktp->cp_byteleft = bp->b_bcount; 11831709Smlf 11841709Smlf /* setup the bad block list handle */ 11851709Smlf pktp->cp_private = BBH_GETHANDLE(dadkp->dad_bbhobjp, bp); 11861709Smlf return (dadk_iosetup(dadkp, pktp)); 11871709Smlf } 11881709Smlf 11891709Smlf static int 11901709Smlf dadk_iosetup(struct dadk *dadkp, struct cmpkt *pktp) 11911709Smlf { 11921709Smlf struct buf *bp; 11931709Smlf bbh_cookie_t bbhckp; 11941709Smlf int seccnt; 11951709Smlf 11961709Smlf seccnt = pktp->cp_bytexfer >> dadkp->dad_secshf; 11971709Smlf pktp->cp_secleft -= seccnt; 11981709Smlf 11991709Smlf if (pktp->cp_secleft) { 12001709Smlf pktp->cp_srtsec += seccnt; 12011709Smlf } else { 12021709Smlf /* get the first cookie from the bad block list */ 12031709Smlf if (!pktp->cp_private) { 12041709Smlf bp = pktp->cp_bp; 12051709Smlf pktp->cp_srtsec = GET_BP_SEC(bp); 12061709Smlf pktp->cp_secleft = (bp->b_bcount >> dadkp->dad_secshf); 12071709Smlf } else { 12081709Smlf bbhckp = BBH_HTOC(dadkp->dad_bbhobjp, 12091709Smlf pktp->cp_private); 12101709Smlf pktp->cp_srtsec = BBH_GETCK_SECTOR(dadkp->dad_bbhobjp, 12111709Smlf bbhckp); 12121709Smlf pktp->cp_secleft = BBH_GETCK_SECLEN(dadkp->dad_bbhobjp, 12131709Smlf bbhckp); 12141709Smlf } 12151709Smlf } 12161709Smlf 12171709Smlf pktp->cp_bytexfer = pktp->cp_secleft << dadkp->dad_secshf; 12181709Smlf 12191709Smlf if (CTL_IOSETUP(dadkp->dad_ctlobjp, pktp)) { 12201709Smlf return (DDI_SUCCESS); 12211709Smlf } else { 12221709Smlf return (DDI_FAILURE); 12231709Smlf } 12241709Smlf 12251709Smlf 12261709Smlf 12271709Smlf 12281709Smlf } 12291709Smlf 12301709Smlf static struct cmpkt * 12311709Smlf dadk_pktprep(struct dadk *dadkp, struct cmpkt *in_pktp, struct buf *bp, 12321709Smlf void (*cb_func)(struct buf *), int (*func)(caddr_t), caddr_t arg) 12331709Smlf { 12341709Smlf struct cmpkt *pktp; 12351709Smlf 12361709Smlf pktp = gda_pktprep(dadkp->dad_ctlobjp, in_pktp, (opaque_t)bp, func, 12371709Smlf arg); 12381709Smlf 12391709Smlf if (pktp) { 12401709Smlf pktp->cp_callback = dadk_pktcb; 12411709Smlf pktp->cp_time = DADK_IO_TIME; 12421709Smlf pktp->cp_flags = 0; 12431709Smlf pktp->cp_iodone = cb_func; 12441709Smlf pktp->cp_dev_private = (opaque_t)dadkp; 12451709Smlf 12461709Smlf } 12471709Smlf 12481709Smlf return (pktp); 12491709Smlf } 12501709Smlf 12511709Smlf 12521709Smlf static void 12531709Smlf dadk_restart(void *vpktp) 12541709Smlf { 12551709Smlf struct cmpkt *pktp = (struct cmpkt *)vpktp; 12561709Smlf 12571709Smlf if (dadk_ioretry(pktp, QUE_COMMAND) == JUST_RETURN) 12581709Smlf return; 12591709Smlf pktp->cp_iodone(pktp->cp_bp); 12601709Smlf } 12611709Smlf 12621709Smlf static int 12631709Smlf dadk_ioretry(struct cmpkt *pktp, int action) 12641709Smlf { 12651709Smlf struct buf *bp; 12661709Smlf struct dadk *dadkp = PKT2DADK(pktp); 12671709Smlf 12681709Smlf switch (action) { 12691709Smlf case QUE_COMMAND: 12701709Smlf if (pktp->cp_retry++ < DADK_RETRY_COUNT) { 12711709Smlf CTL_IOSETUP(dadkp->dad_ctlobjp, pktp); 12721709Smlf if (CTL_TRANSPORT(dadkp->dad_ctlobjp, pktp) == 12735295Srandyf CTL_SEND_SUCCESS) { 12741709Smlf return (JUST_RETURN); 12751709Smlf } 12761709Smlf gda_log(dadkp->dad_sd->sd_dev, dadk_name, 12775295Srandyf CE_WARN, "transport of command fails\n"); 12781709Smlf } else 12791709Smlf gda_log(dadkp->dad_sd->sd_dev, 12805295Srandyf dadk_name, CE_WARN, 12815295Srandyf "exceeds maximum number of retries\n"); 12821709Smlf bioerror(pktp->cp_bp, ENXIO); 12831709Smlf /*FALLTHROUGH*/ 12841709Smlf case COMMAND_DONE_ERROR: 12851709Smlf bp = pktp->cp_bp; 12861709Smlf bp->b_resid += pktp->cp_byteleft - pktp->cp_bytexfer + 12871709Smlf pktp->cp_resid; 12881709Smlf if (geterror(bp) == 0) { 12891709Smlf if ((*((char *)(pktp->cp_cdbp)) == DCMD_FLUSH_CACHE) && 12901709Smlf (pktp->cp_dev_private == (opaque_t)dadkp) && 12911709Smlf ((int)(*(char *)pktp->cp_scbp) == DERR_ABORT)) { 12921709Smlf /* 12931709Smlf * Flag "unimplemented" responses for 12941709Smlf * DCMD_FLUSH_CACHE as ENOTSUP 12951709Smlf */ 12961709Smlf bioerror(bp, ENOTSUP); 12971709Smlf mutex_enter(&dadkp->dad_mutex); 12981709Smlf dadkp->dad_noflush = 1; 12991709Smlf mutex_exit(&dadkp->dad_mutex); 13001709Smlf } else { 13011709Smlf bioerror(bp, EIO); 13021709Smlf } 13031709Smlf } 13041709Smlf /*FALLTHROUGH*/ 13051709Smlf case COMMAND_DONE: 13061709Smlf default: 13071709Smlf return (COMMAND_DONE); 13081709Smlf } 13091709Smlf } 13101709Smlf 13111709Smlf 13121709Smlf static void 13131709Smlf dadk_pktcb(struct cmpkt *pktp) 13141709Smlf { 13151709Smlf int action; 13161709Smlf struct dadkio_rwcmd *rwcmdp; 13171709Smlf 13181709Smlf rwcmdp = (struct dadkio_rwcmd *)pktp->cp_passthru; /* ioctl packet */ 13191709Smlf 13201709Smlf if (pktp->cp_reason == CPS_SUCCESS) { 13211709Smlf if (rwcmdp && (rwcmdp != (opaque_t)DADK_SILENT)) 13221709Smlf rwcmdp->status.status = DADKIO_STAT_NO_ERROR; 13231709Smlf pktp->cp_iodone(pktp->cp_bp); 13241709Smlf return; 13251709Smlf } 13261709Smlf 13271709Smlf if (rwcmdp && (rwcmdp != (opaque_t)DADK_SILENT)) { 13281709Smlf if (pktp->cp_reason == CPS_CHKERR) 13291709Smlf dadk_recorderr(pktp, rwcmdp); 13301709Smlf dadk_iodone(pktp->cp_bp); 13311709Smlf return; 13321709Smlf } 13331709Smlf 13341709Smlf if (pktp->cp_reason == CPS_CHKERR) 13351709Smlf action = dadk_chkerr(pktp); 13361709Smlf else 13371709Smlf action = COMMAND_DONE_ERROR; 13381709Smlf 13391709Smlf if (action == JUST_RETURN) 13401709Smlf return; 13411709Smlf 13427239Szk194757 /* 13437239Szk194757 * If we are panicking don't retry the command 13447239Szk194757 * just fail it so we can go down completing all 13457239Szk194757 * of the buffers. 13467239Szk194757 */ 13477239Szk194757 if (ddi_in_panic() && action == QUE_COMMAND) 13487239Szk194757 action = COMMAND_DONE_ERROR; 13497239Szk194757 13501709Smlf if (action != COMMAND_DONE) { 13511709Smlf if ((dadk_ioretry(pktp, action)) == JUST_RETURN) 13521709Smlf return; 13531709Smlf } 13541709Smlf pktp->cp_iodone(pktp->cp_bp); 13551709Smlf } 13561709Smlf 13571709Smlf 13581709Smlf 13591709Smlf static struct dadkio_derr dadk_errtab[] = { 13601709Smlf {COMMAND_DONE, GDA_INFORMATIONAL}, /* 0 DERR_SUCCESS */ 13611709Smlf {QUE_COMMAND, GDA_FATAL}, /* 1 DERR_AMNF */ 13621709Smlf {QUE_COMMAND, GDA_FATAL}, /* 2 DERR_TKONF */ 13631709Smlf {COMMAND_DONE_ERROR, GDA_INFORMATIONAL}, /* 3 DERR_ABORT */ 13641709Smlf {QUE_COMMAND, GDA_RETRYABLE}, /* 4 DERR_DWF */ 13651709Smlf {QUE_COMMAND, GDA_FATAL}, /* 5 DERR_IDNF */ 13661709Smlf {JUST_RETURN, GDA_INFORMATIONAL}, /* 6 DERR_BUSY */ 13671709Smlf {QUE_COMMAND, GDA_FATAL}, /* 7 DERR_UNC */ 13681709Smlf {QUE_COMMAND, GDA_RETRYABLE}, /* 8 DERR_BBK */ 13691709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 9 DERR_INVCDB */ 13701709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 10 DERR_HARD */ 13711709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 11 DERR_ILI */ 13721709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 12 DERR_EOM */ 13731709Smlf {COMMAND_DONE, GDA_INFORMATIONAL}, /* 13 DERR_MCR */ 13741709Smlf {COMMAND_DONE, GDA_INFORMATIONAL}, /* 14 DERR_RECOVER */ 13751709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 15 DERR_NOTREADY */ 13761709Smlf {QUE_COMMAND, GDA_RETRYABLE}, /* 16 DERR_MEDIUM */ 13771709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 17 DERR_HW */ 13781709Smlf {COMMAND_DONE, GDA_FATAL}, /* 18 DERR_ILL */ 13791709Smlf {COMMAND_DONE, GDA_FATAL}, /* 19 DERR_UNIT_ATTN */ 13801709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 20 DERR_DATA_PROT */ 13811709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 21 DERR_MISCOMPARE */ 13821709Smlf {QUE_COMMAND, GDA_RETRYABLE}, /* 22 DERR_ICRC */ 13831709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 23 DERR_RESV */ 13841709Smlf }; 13851709Smlf 13861709Smlf static int 13871709Smlf dadk_chkerr(struct cmpkt *pktp) 13881709Smlf { 1389*7563SPrasad.Singamsetty@Sun.COM daddr_t err_blkno; 13902799Smarx struct dadk *dadkp = PKT2DADK(pktp); 13912799Smarx dadk_errstats_t *dep; 13922799Smarx int scb = *(char *)pktp->cp_scbp; 13931709Smlf 13942799Smarx if (scb == DERR_SUCCESS) { 13952799Smarx if (pktp->cp_retry != 0 && dadkp->dad_errstats != NULL) { 13962799Smarx dep = (dadk_errstats_t *) 13972799Smarx dadkp->dad_errstats->ks_data; 13982799Smarx dep->dadk_rq_recov_err.value.ui32++; 13992799Smarx } 14001709Smlf return (COMMAND_DONE); 14012799Smarx } 14021709Smlf 14031709Smlf if (pktp->cp_retry) { 14041709Smlf err_blkno = pktp->cp_srtsec + ((pktp->cp_bytexfer - 14055295Srandyf pktp->cp_resid) >> dadkp->dad_secshf); 14061709Smlf } else 14071709Smlf err_blkno = -1; 14081709Smlf 14092799Smarx if (dadkp->dad_errstats != NULL) { 14102799Smarx dep = (dadk_errstats_t *)dadkp->dad_errstats->ks_data; 14112799Smarx 14123399Smarx switch (dadk_errtab[scb].d_severity) { 14133399Smarx case GDA_RETRYABLE: 14143399Smarx dep->dadk_softerrs.value.ui32++; 14153399Smarx break; 14163399Smarx 14173399Smarx case GDA_FATAL: 14183399Smarx dep->dadk_harderrs.value.ui32++; 14193399Smarx break; 14203399Smarx 14213399Smarx default: 14223399Smarx break; 14233399Smarx } 14242799Smarx 14252799Smarx switch (scb) { 14262799Smarx case DERR_INVCDB: 14272799Smarx case DERR_ILI: 14282799Smarx case DERR_EOM: 14292799Smarx case DERR_HW: 14302799Smarx case DERR_ICRC: 14312799Smarx dep->dadk_transerrs.value.ui32++; 14322799Smarx break; 14332799Smarx 14342799Smarx case DERR_AMNF: 14352799Smarx case DERR_TKONF: 14362799Smarx case DERR_DWF: 14372799Smarx case DERR_BBK: 14382799Smarx case DERR_UNC: 14392799Smarx case DERR_HARD: 14402799Smarx case DERR_MEDIUM: 14412799Smarx case DERR_DATA_PROT: 14422799Smarx case DERR_MISCOMP: 14432799Smarx dep->dadk_rq_media_err.value.ui32++; 14442799Smarx break; 14452799Smarx 14462799Smarx case DERR_NOTREADY: 14472799Smarx dep->dadk_rq_ntrdy_err.value.ui32++; 14482799Smarx break; 14492799Smarx 14502799Smarx case DERR_IDNF: 14512799Smarx case DERR_UNIT_ATTN: 14522799Smarx dep->dadk_rq_nodev_err.value.ui32++; 14532799Smarx break; 14542799Smarx 14552799Smarx case DERR_ILL: 14562799Smarx case DERR_RESV: 14572799Smarx dep->dadk_rq_illrq_err.value.ui32++; 14582799Smarx break; 14592799Smarx 14602799Smarx default: 14612799Smarx break; 14622799Smarx } 14632799Smarx } 14642799Smarx 14651709Smlf /* if attempting to read a sector from a cdrom audio disk */ 14661709Smlf if ((dadkp->dad_cdrom) && 14671709Smlf (*((char *)(pktp->cp_cdbp)) == DCMD_READ) && 14681709Smlf (scb == DERR_ILL)) { 14691709Smlf return (COMMAND_DONE); 14701709Smlf } 14711709Smlf if (pktp->cp_passthru == NULL) { 14721709Smlf gda_errmsg(dadkp->dad_sd, pktp, dadk_name, 14731709Smlf dadk_errtab[scb].d_severity, pktp->cp_srtsec, 14741709Smlf err_blkno, dadk_cmds, dadk_sense); 14751709Smlf } 14761709Smlf 14771709Smlf if (scb == DERR_BUSY) { 14781709Smlf (void) timeout(dadk_restart, (void *)pktp, DADK_BSY_TIMEOUT); 14791709Smlf } 14801709Smlf 14813399Smarx return (dadk_errtab[scb].d_action); 14821709Smlf } 14831709Smlf 14841709Smlf static void 14851709Smlf dadk_recorderr(struct cmpkt *pktp, struct dadkio_rwcmd *rwcmdp) 14861709Smlf { 14871709Smlf struct dadk *dadkp; 14881709Smlf int scb; 14891709Smlf 14901709Smlf dadkp = PKT2DADK(pktp); 14911709Smlf scb = (int)(*(char *)pktp->cp_scbp); 14921709Smlf 14931709Smlf 14941709Smlf rwcmdp->status.failed_blk = rwcmdp->blkaddr + 14955295Srandyf ((pktp->cp_bytexfer - pktp->cp_resid) >> dadkp->dad_secshf); 14961709Smlf 14971709Smlf rwcmdp->status.resid = pktp->cp_bp->b_resid + 14985295Srandyf pktp->cp_byteleft - pktp->cp_bytexfer + pktp->cp_resid; 14991709Smlf switch ((int)(* (char *)pktp->cp_scbp)) { 15001709Smlf case DERR_AMNF: 15011709Smlf case DERR_ABORT: 15021709Smlf rwcmdp->status.status = DADKIO_STAT_ILLEGAL_REQUEST; 15031709Smlf break; 15041709Smlf case DERR_DWF: 15051709Smlf case DERR_IDNF: 15061709Smlf rwcmdp->status.status = DADKIO_STAT_ILLEGAL_ADDRESS; 15071709Smlf break; 15081709Smlf case DERR_TKONF: 15091709Smlf case DERR_UNC: 15101709Smlf case DERR_BBK: 15111709Smlf rwcmdp->status.status = DADKIO_STAT_MEDIUM_ERROR; 15121709Smlf rwcmdp->status.failed_blk_is_valid = 1; 15131709Smlf rwcmdp->status.resid = 0; 15141709Smlf break; 15151709Smlf case DERR_BUSY: 15161709Smlf rwcmdp->status.status = DADKIO_STAT_NOT_READY; 15171709Smlf break; 15181709Smlf case DERR_INVCDB: 15191709Smlf case DERR_HARD: 15201709Smlf rwcmdp->status.status = DADKIO_STAT_HARDWARE_ERROR; 15211709Smlf break; 15221709Smlf case DERR_ICRC: 15231709Smlf default: 15241709Smlf rwcmdp->status.status = DADKIO_STAT_NOT_SUPPORTED; 15251709Smlf } 15261709Smlf 15271709Smlf if (rwcmdp->flags & DADKIO_FLAG_SILENT) 15281709Smlf return; 15291709Smlf gda_errmsg(dadkp->dad_sd, pktp, dadk_name, dadk_errtab[scb].d_severity, 15305295Srandyf rwcmdp->blkaddr, rwcmdp->status.failed_blk, 15315295Srandyf dadk_cmds, dadk_sense); 15321709Smlf } 15331709Smlf 15341709Smlf /*ARGSUSED*/ 15351709Smlf static void 15361709Smlf dadk_polldone(struct buf *bp) 15371709Smlf { 15385295Srandyf struct cmpkt *pktp; 15395295Srandyf struct dadk *dadkp; 15405295Srandyf 15415295Srandyf pktp = GDA_BP_PKT(bp); 15425295Srandyf dadkp = PKT2DADK(pktp); 15435295Srandyf mutex_enter(&dadkp->dad_cmd_mutex); 15445295Srandyf dadkp->dad_cmd_count--; 15455295Srandyf mutex_exit(&dadkp->dad_cmd_mutex); 15461709Smlf } 15471709Smlf 15481709Smlf static void 15491709Smlf dadk_iodone(struct buf *bp) 15501709Smlf { 15511709Smlf struct cmpkt *pktp; 15521709Smlf struct dadk *dadkp; 15531709Smlf 15541709Smlf pktp = GDA_BP_PKT(bp); 15551709Smlf dadkp = PKT2DADK(pktp); 15561709Smlf 15571709Smlf /* check for all iodone */ 15581709Smlf pktp->cp_byteleft -= pktp->cp_bytexfer; 15591709Smlf if (geterror(bp) == 0 && pktp->cp_byteleft != 0) { 15601709Smlf pktp->cp_retry = 0; 15611709Smlf (void) dadk_iosetup(dadkp, pktp); 15621709Smlf 15631709Smlf 15641709Smlf /* transport the next one */ 15651709Smlf if (CTL_TRANSPORT(dadkp->dad_ctlobjp, pktp) == CTL_SEND_SUCCESS) 15661709Smlf return; 15671709Smlf if ((dadk_ioretry(pktp, QUE_COMMAND)) == JUST_RETURN) 15681709Smlf return; 15691709Smlf } 15701709Smlf 15711709Smlf /* start next one */ 15721709Smlf FLC_DEQUE(dadkp->dad_flcobjp, bp); 15731709Smlf 15741709Smlf /* free pkt */ 15751709Smlf if (pktp->cp_private) 15761709Smlf BBH_FREEHANDLE(dadkp->dad_bbhobjp, pktp->cp_private); 15771709Smlf gda_free(dadkp->dad_ctlobjp, pktp, NULL); 15785295Srandyf mutex_enter(&dadkp->dad_cmd_mutex); 15795295Srandyf dadkp->dad_cmd_count--; 15805295Srandyf mutex_exit(&dadkp->dad_cmd_mutex); 15811709Smlf biodone(bp); 15821709Smlf } 15831709Smlf 15841709Smlf int 15851709Smlf dadk_check_media(opaque_t objp, int *state) 15861709Smlf { 15871709Smlf struct dadk *dadkp = (struct dadk *)objp; 15881709Smlf 15891709Smlf if (!dadkp->dad_rmb) { 15901709Smlf return (ENXIO); 15911709Smlf } 15921709Smlf #ifdef DADK_DEBUG 15931709Smlf if (dadk_debug & DSTATE) 15941709Smlf PRF("dadk_check_media: user state %x disk state %x\n", 15955295Srandyf *state, dadkp->dad_iostate); 15961709Smlf #endif 15971709Smlf /* 15981709Smlf * If state already changed just return 15991709Smlf */ 16001709Smlf if (*state != dadkp->dad_iostate) { 16011709Smlf *state = dadkp->dad_iostate; 16021709Smlf return (0); 16031709Smlf } 16041709Smlf 16051709Smlf /* 16061709Smlf * Startup polling on thread state 16071709Smlf */ 16081709Smlf mutex_enter(&dadkp->dad_mutex); 16091709Smlf if (dadkp->dad_thread_cnt == 0) { 16101709Smlf /* 16111709Smlf * One thread per removable dadk device 16121709Smlf */ 16131709Smlf (void) thread_create(NULL, 0, dadk_watch_thread, dadkp, 0, &p0, 16141709Smlf TS_RUN, v.v_maxsyspri - 2); 16151709Smlf } 16161709Smlf dadkp->dad_thread_cnt++; 16171709Smlf 16181709Smlf /* 16191709Smlf * Wait for state to change 16201709Smlf */ 16211709Smlf do { 16221709Smlf if (cv_wait_sig(&dadkp->dad_state_cv, &dadkp->dad_mutex) == 0) { 16231709Smlf dadkp->dad_thread_cnt--; 16241709Smlf mutex_exit(&dadkp->dad_mutex); 16251709Smlf return (EINTR); 16261709Smlf } 16271709Smlf } while (*state == dadkp->dad_iostate); 16281709Smlf *state = dadkp->dad_iostate; 16291709Smlf dadkp->dad_thread_cnt--; 16301709Smlf mutex_exit(&dadkp->dad_mutex); 16311709Smlf return (0); 16321709Smlf } 16331709Smlf 16341709Smlf 16351709Smlf #define MEDIA_ACCESS_DELAY 2000000 16361709Smlf 16371709Smlf static void 16381709Smlf dadk_watch_thread(struct dadk *dadkp) 16391709Smlf { 16401709Smlf enum dkio_state state; 16411709Smlf int interval; 16421709Smlf 16431709Smlf interval = drv_usectohz(dadk_check_media_time); 16441709Smlf 16451709Smlf do { 16461709Smlf if (dadk_rmb_ioctl(dadkp, DCMD_GET_STATE, (intptr_t)&state, 0, 16471709Smlf DADK_SILENT)) { 16481709Smlf /* 16491709Smlf * Assume state remained the same 16501709Smlf */ 16511709Smlf state = dadkp->dad_iostate; 16521709Smlf } 16531709Smlf 16541709Smlf /* 16551709Smlf * now signal the waiting thread if this is *not* the 16561709Smlf * specified state; 16571709Smlf * delay the signal if the state is DKIO_INSERTED 16581709Smlf * to allow the target to recover 16591709Smlf */ 16601709Smlf if (state != dadkp->dad_iostate) { 16611709Smlf 16621709Smlf dadkp->dad_iostate = state; 16631709Smlf if (state == DKIO_INSERTED) { 16641709Smlf /* 16651709Smlf * delay the signal to give the drive a chance 16661709Smlf * to do what it apparently needs to do 16671709Smlf */ 16681709Smlf (void) timeout((void(*)(void *))cv_broadcast, 16691709Smlf (void *)&dadkp->dad_state_cv, 16701709Smlf drv_usectohz((clock_t)MEDIA_ACCESS_DELAY)); 16711709Smlf } else { 16721709Smlf cv_broadcast(&dadkp->dad_state_cv); 16731709Smlf } 16741709Smlf } 16751709Smlf delay(interval); 16761709Smlf } while (dadkp->dad_thread_cnt); 16771709Smlf } 16781709Smlf 16791709Smlf int 16801709Smlf dadk_inquiry(opaque_t objp, opaque_t *inqpp) 16811709Smlf { 16821709Smlf struct dadk *dadkp = (struct dadk *)objp; 16831709Smlf struct scsi_inquiry **sinqpp = (struct scsi_inquiry **)inqpp; 16841709Smlf 16851709Smlf if (dadkp && dadkp->dad_sd && dadkp->dad_sd->sd_inq) { 16861709Smlf *sinqpp = dadkp->dad_sd->sd_inq; 16871709Smlf return (DDI_SUCCESS); 16881709Smlf } 16891709Smlf 16901709Smlf return (DDI_FAILURE); 16911709Smlf } 16921709Smlf 16931709Smlf static int 16941709Smlf dadk_rmb_ioctl(struct dadk *dadkp, int cmd, intptr_t arg, int flags, int silent) 16951709Smlf 16961709Smlf { 16971709Smlf struct buf *bp; 16981709Smlf int err; 16991709Smlf struct cmpkt *pktp; 17001709Smlf 17011709Smlf if ((bp = getrbuf(KM_SLEEP)) == NULL) { 17021709Smlf return (ENOMEM); 17031709Smlf } 17041709Smlf pktp = dadk_pktprep(dadkp, NULL, bp, dadk_rmb_iodone, NULL, NULL); 17051709Smlf if (!pktp) { 17061709Smlf freerbuf(bp); 17071709Smlf return (ENOMEM); 17081709Smlf } 17091709Smlf bp->b_back = (struct buf *)arg; 17101709Smlf bp->b_forw = (struct buf *)dadkp->dad_flcobjp; 17111709Smlf pktp->cp_passthru = (opaque_t)(intptr_t)silent; 17121709Smlf 17135295Srandyf err = dadk_ctl_ioctl(dadkp, cmd, (uintptr_t)pktp, flags); 17141709Smlf freerbuf(bp); 17151709Smlf gda_free(dadkp->dad_ctlobjp, pktp, NULL); 17161709Smlf return (err); 17171709Smlf 17181709Smlf 17191709Smlf } 17201709Smlf 17211709Smlf static void 17221709Smlf dadk_rmb_iodone(struct buf *bp) 17231709Smlf { 17241709Smlf struct cmpkt *pktp; 17251709Smlf struct dadk *dadkp; 17261709Smlf 17271709Smlf pktp = GDA_BP_PKT(bp); 17281709Smlf dadkp = PKT2DADK(pktp); 17291709Smlf 17301709Smlf bp->b_flags &= ~(B_DONE|B_BUSY); 17311709Smlf 17321709Smlf /* Start next one */ 17331709Smlf FLC_DEQUE(dadkp->dad_flcobjp, bp); 17341709Smlf 17355295Srandyf mutex_enter(&dadkp->dad_cmd_mutex); 17365295Srandyf dadkp->dad_cmd_count--; 17375295Srandyf mutex_exit(&dadkp->dad_cmd_mutex); 17381709Smlf biodone(bp); 17391709Smlf } 17401709Smlf 17411709Smlf static int 17421709Smlf dadk_dk_buf_setup(struct dadk *dadkp, opaque_t *cmdp, dev_t dev, 17431709Smlf enum uio_seg dataspace, int rw) 17441709Smlf { 17451709Smlf struct dadkio_rwcmd *rwcmdp = (struct dadkio_rwcmd *)cmdp; 17461709Smlf struct buf *bp; 17471709Smlf struct iovec aiov; 17481709Smlf struct uio auio; 17491709Smlf struct uio *uio = &auio; 17501709Smlf int status; 17511709Smlf 17521709Smlf bp = getrbuf(KM_SLEEP); 17531709Smlf 17541709Smlf bp->av_forw = bp->b_forw = (struct buf *)dadkp; 17551709Smlf bp->b_back = (struct buf *)rwcmdp; /* ioctl packet */ 17561709Smlf 17571709Smlf bzero((caddr_t)&auio, sizeof (struct uio)); 17581709Smlf bzero((caddr_t)&aiov, sizeof (struct iovec)); 17591709Smlf aiov.iov_base = rwcmdp->bufaddr; 17601709Smlf aiov.iov_len = rwcmdp->buflen; 17611709Smlf uio->uio_iov = &aiov; 17621709Smlf 17631709Smlf uio->uio_iovcnt = 1; 17641709Smlf uio->uio_resid = rwcmdp->buflen; 17651709Smlf uio->uio_segflg = dataspace; 17661709Smlf 17671709Smlf /* Let physio do the rest... */ 17681709Smlf status = physio(dadk_dk_strategy, bp, dev, rw, dadkmin, uio); 17691709Smlf 17701709Smlf freerbuf(bp); 17711709Smlf return (status); 17721709Smlf 17731709Smlf } 17741709Smlf 17751709Smlf /* Do not let a user gendisk request get too big or */ 17761709Smlf /* else we could use to many resources. */ 17771709Smlf 17781709Smlf static void 17791709Smlf dadkmin(struct buf *bp) 17801709Smlf { 17811709Smlf if (bp->b_bcount > dadk_dk_maxphys) 17821709Smlf bp->b_bcount = dadk_dk_maxphys; 17831709Smlf } 17841709Smlf 17851709Smlf static int 17861709Smlf dadk_dk_strategy(struct buf *bp) 17871709Smlf { 17881709Smlf dadk_dk((struct dadk *)bp->av_forw, (struct dadkio_rwcmd *)bp->b_back, 17891709Smlf bp); 17901709Smlf return (0); 17911709Smlf } 17921709Smlf 17931709Smlf static void 17941709Smlf dadk_dk(struct dadk *dadkp, struct dadkio_rwcmd *rwcmdp, struct buf *bp) 17951709Smlf { 17961709Smlf struct cmpkt *pktp; 17971709Smlf 17981709Smlf pktp = dadk_pktprep(dadkp, NULL, bp, dadk_iodone, NULL, NULL); 17991709Smlf if (!pktp) { 18001709Smlf bioerror(bp, ENOMEM); 18011709Smlf biodone(bp); 18021709Smlf return; 18031709Smlf } 18041709Smlf 18051709Smlf pktp->cp_passthru = rwcmdp; 18061709Smlf 18071709Smlf (void) dadk_ioprep(dadkp, pktp); 18081709Smlf 18095295Srandyf mutex_enter(&dadkp->dad_cmd_mutex); 18105295Srandyf dadkp->dad_cmd_count++; 18115295Srandyf mutex_exit(&dadkp->dad_cmd_mutex); 18121709Smlf FLC_ENQUE(dadkp->dad_flcobjp, bp); 18131709Smlf } 18145295Srandyf 18155295Srandyf /* 18165295Srandyf * There is no existing way to notify cmdk module 18175295Srandyf * when the command completed, so add this function 18185295Srandyf * to calculate how many on-going commands. 18195295Srandyf */ 18205295Srandyf int 18215295Srandyf dadk_getcmds(opaque_t objp) 18225295Srandyf { 18235295Srandyf struct dadk *dadkp = (struct dadk *)objp; 18245295Srandyf int count; 18255295Srandyf 18265295Srandyf mutex_enter(&dadkp->dad_cmd_mutex); 18275295Srandyf count = dadkp->dad_cmd_count; 18285295Srandyf mutex_exit(&dadkp->dad_cmd_mutex); 18295295Srandyf return (count); 18305295Srandyf } 18315295Srandyf 18325295Srandyf /* 18335295Srandyf * this function was used to calc the cmd for CTL_IOCTL 18345295Srandyf */ 18355295Srandyf static int 18365295Srandyf dadk_ctl_ioctl(struct dadk *dadkp, uint32_t cmd, uintptr_t arg, int flag) 18375295Srandyf { 18385295Srandyf int error; 18395295Srandyf mutex_enter(&dadkp->dad_cmd_mutex); 18405295Srandyf dadkp->dad_cmd_count++; 18415295Srandyf mutex_exit(&dadkp->dad_cmd_mutex); 18425295Srandyf error = CTL_IOCTL(dadkp->dad_ctlobjp, cmd, arg, flag); 18435295Srandyf mutex_enter(&dadkp->dad_cmd_mutex); 18445295Srandyf dadkp->dad_cmd_count--; 18455295Srandyf mutex_exit(&dadkp->dad_cmd_mutex); 18465295Srandyf return (error); 18475295Srandyf } 1848