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 /* 23*3399Smarx * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 241709Smlf * Use is subject to license terms. 251709Smlf */ 261709Smlf 271709Smlf #pragma ident "%Z%%M% %I% %E% SMI" 281709Smlf 291709Smlf /* 301709Smlf * Direct Attached Disk 311709Smlf */ 321709Smlf 331709Smlf #include <sys/file.h> 341709Smlf #include <sys/scsi/scsi.h> 351709Smlf #include <sys/var.h> 361709Smlf #include <sys/proc.h> 371709Smlf #include <sys/dktp/cm.h> 381709Smlf #include <sys/vtoc.h> 391709Smlf #include <sys/dkio.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); 741709Smlf 751709Smlf struct tgcom_objops dadk_com_ops = { 761709Smlf nodev, 771709Smlf nodev, 781709Smlf dadk_pkt, 791709Smlf dadk_transport, 801709Smlf 0, 0 811709Smlf }; 821709Smlf 831709Smlf /* 841709Smlf * architecture dependent allocation restrictions for dadk_iob_alloc(). For 851709Smlf * x86, we'll set dma_attr_addr_hi to dadk_max_phys_addr and dma_attr_sgllen 861709Smlf * to dadk_sgl_size during _init(). 871709Smlf */ 881709Smlf #if defined(__sparc) 891709Smlf static ddi_dma_attr_t dadk_alloc_attr = { 901709Smlf DMA_ATTR_V0, /* version number */ 911709Smlf 0x0, /* lowest usable address */ 921709Smlf 0xFFFFFFFFull, /* high DMA address range */ 931709Smlf 0xFFFFFFFFull, /* DMA counter register */ 941709Smlf 1, /* DMA address alignment */ 951709Smlf 1, /* DMA burstsizes */ 961709Smlf 1, /* min effective DMA size */ 971709Smlf 0xFFFFFFFFull, /* max DMA xfer size */ 981709Smlf 0xFFFFFFFFull, /* segment boundary */ 991709Smlf 1, /* s/g list length */ 1001709Smlf 512, /* granularity of device */ 1011709Smlf 0, /* DMA transfer flags */ 1021709Smlf }; 1031709Smlf #elif defined(__x86) 1041709Smlf static ddi_dma_attr_t dadk_alloc_attr = { 1051709Smlf DMA_ATTR_V0, /* version number */ 1061709Smlf 0x0, /* lowest usable address */ 1071709Smlf 0x0, /* high DMA address range [set in _init()] */ 1081709Smlf 0xFFFFull, /* DMA counter register */ 1091709Smlf 512, /* DMA address alignment */ 1101709Smlf 1, /* DMA burstsizes */ 1111709Smlf 1, /* min effective DMA size */ 1121709Smlf 0xFFFFFFFFull, /* max DMA xfer size */ 1131709Smlf 0xFFFFFFFFull, /* segment boundary */ 1141709Smlf 0, /* s/g list length [set in _init()] */ 1151709Smlf 512, /* granularity of device */ 1161709Smlf 0, /* DMA transfer flags */ 1171709Smlf }; 1181709Smlf 1191709Smlf uint64_t dadk_max_phys_addr = 0xFFFFFFFFull; 1201709Smlf int dadk_sgl_size = 0xFF; 1211709Smlf #endif 1221709Smlf 1231709Smlf static int dadk_rmb_ioctl(struct dadk *dadkp, int cmd, intptr_t arg, int flags, 1241709Smlf int silent); 1251709Smlf static void dadk_rmb_iodone(struct buf *bp); 1261709Smlf 1271709Smlf static int dadk_dk_buf_setup(struct dadk *dadkp, opaque_t *cmdp, 1281709Smlf dev_t dev, enum uio_seg dataspace, int rw); 1291709Smlf static void dadk_dk(struct dadk *dadkp, struct dadkio_rwcmd *scmdp, 1301709Smlf struct buf *bp); 1311709Smlf static void dadkmin(struct buf *bp); 1321709Smlf static int dadk_dk_strategy(struct buf *bp); 1331709Smlf static void dadk_recorderr(struct cmpkt *pktp, struct dadkio_rwcmd *rwcmdp); 1341709Smlf 1351709Smlf struct tgdk_objops dadk_ops = { 1361709Smlf dadk_init, 1371709Smlf dadk_free, 1381709Smlf dadk_probe, 1391709Smlf dadk_attach, 1401709Smlf dadk_open, 1411709Smlf dadk_close, 1421709Smlf dadk_ioctl, 1431709Smlf dadk_strategy, 1441709Smlf dadk_setgeom, 1451709Smlf dadk_getgeom, 1461709Smlf dadk_iob_alloc, 1471709Smlf dadk_iob_free, 1481709Smlf dadk_iob_htoc, 1491709Smlf dadk_iob_xfer, 1501709Smlf dadk_dump, 1511709Smlf dadk_getphygeom, 1521709Smlf dadk_set_bbhobj, 1531709Smlf dadk_check_media, 1541709Smlf dadk_inquiry, 1551709Smlf dadk_cleanup, 1561709Smlf 0 1571709Smlf }; 1581709Smlf 1591709Smlf /* 1601709Smlf * Local static data 1611709Smlf */ 1621709Smlf 1631709Smlf #ifdef DADK_DEBUG 1641709Smlf #define DENT 0x0001 1651709Smlf #define DERR 0x0002 1661709Smlf #define DIO 0x0004 1671709Smlf #define DGEOM 0x0010 1681709Smlf #define DSTATE 0x0020 1691709Smlf static int dadk_debug = DGEOM; 1701709Smlf 1711709Smlf #endif /* DADK_DEBUG */ 1721709Smlf 1731709Smlf static int dadk_check_media_time = 3000000; /* 3 Second State Check */ 1741709Smlf static int dadk_dk_maxphys = 0x80000; 1751709Smlf 1761709Smlf static char *dadk_cmds[] = { 1771709Smlf "\000Unknown", /* unknown */ 1781709Smlf "\001read sector", /* DCMD_READ 1 */ 1791709Smlf "\002write sector", /* DCMD_WRITE 2 */ 1801709Smlf "\003format track", /* DCMD_FMTTRK 3 */ 1811709Smlf "\004format whole drive", /* DCMD_FMTDRV 4 */ 1821709Smlf "\005recalibrate", /* DCMD_RECAL 5 */ 1831709Smlf "\006seek sector", /* DCMD_SEEK 6 */ 1841709Smlf "\007read verify", /* DCMD_RDVER 7 */ 1851709Smlf "\010read defect list", /* DCMD_GETDEF 8 */ 1861709Smlf "\011lock door", /* DCMD_LOCK 9 */ 1871709Smlf "\012unlock door", /* DCMD_UNLOCK 10 */ 1881709Smlf "\013start motor", /* DCMD_START_MOTOR 11 */ 1891709Smlf "\014stop motor", /* DCMD_STOP_MOTOR 12 */ 1901709Smlf "\015eject", /* DCMD_EJECT 13 */ 1911709Smlf "\016update geometry", /* DCMD_UPDATE_GEOM 14 */ 1921709Smlf "\017get state", /* DCMD_GET_STATE 15 */ 1931709Smlf "\020cdrom pause", /* DCMD_PAUSE 16 */ 1941709Smlf "\021cdrom resume", /* DCMD_RESUME 17 */ 1951709Smlf "\022cdrom play track index", /* DCMD_PLAYTRKIND 18 */ 1961709Smlf "\023cdrom play msf", /* DCMD_PLAYMSF 19 */ 1971709Smlf "\024cdrom sub channel", /* DCMD_SUBCHNL 20 */ 1981709Smlf "\025cdrom read mode 1", /* DCMD_READMODE1 21 */ 1991709Smlf "\026cdrom read toc header", /* DCMD_READTOCHDR 22 */ 2001709Smlf "\027cdrom read toc entry", /* DCMD_READTOCENT 23 */ 2011709Smlf "\030cdrom read offset", /* DCMD_READOFFSET 24 */ 2021709Smlf "\031cdrom read mode 2", /* DCMD_READMODE2 25 */ 2031709Smlf "\032cdrom volume control", /* DCMD_VOLCTRL 26 */ 2041709Smlf "\033flush cache", /* DCMD_FLUSH_CACHE 27 */ 2051709Smlf NULL 2061709Smlf }; 2071709Smlf 2081709Smlf static char *dadk_sense[] = { 2091709Smlf "\000Success", /* DERR_SUCCESS */ 2101709Smlf "\001address mark not found", /* DERR_AMNF */ 2111709Smlf "\002track 0 not found", /* DERR_TKONF */ 2121709Smlf "\003aborted command", /* DERR_ABORT */ 2131709Smlf "\004write fault", /* DERR_DWF */ 2141709Smlf "\005ID not found", /* DERR_IDNF */ 2151709Smlf "\006drive busy", /* DERR_BUSY */ 2161709Smlf "\007uncorrectable data error", /* DERR_UNC */ 2171709Smlf "\010bad block detected", /* DERR_BBK */ 2181709Smlf "\011invalid command", /* DERR_INVCDB */ 2191709Smlf "\012device hard error", /* DERR_HARD */ 2201709Smlf "\013illegal length indicated", /* DERR_ILI */ 2211709Smlf "\014end of media", /* DERR_EOM */ 2221709Smlf "\015media change requested", /* DERR_MCR */ 2231709Smlf "\016recovered from error", /* DERR_RECOVER */ 2241709Smlf "\017device not ready", /* DERR_NOTREADY */ 2251709Smlf "\020medium error", /* DERR_MEDIUM */ 2261709Smlf "\021hardware error", /* DERR_HW */ 2271709Smlf "\022illegal request", /* DERR_ILL */ 2281709Smlf "\023unit attention", /* DERR_UNIT_ATTN */ 2291709Smlf "\024data protection", /* DERR_DATA_PROT */ 2301709Smlf "\025miscompare", /* DERR_MISCOMPARE */ 2311709Smlf "\026ICRC error during UDMA", /* DERR_ICRC */ 2321709Smlf "\027reserved", /* DERR_RESV */ 2331709Smlf NULL 2341709Smlf }; 2351709Smlf 2361709Smlf static char *dadk_name = "Disk"; 2371709Smlf 2381709Smlf /* 2391709Smlf * This is the loadable module wrapper 2401709Smlf */ 2411709Smlf #include <sys/modctl.h> 2421709Smlf 2431709Smlf extern struct mod_ops mod_miscops; 2441709Smlf 2451709Smlf static struct modlmisc modlmisc = { 2461709Smlf &mod_miscops, /* Type of module */ 2471709Smlf "Direct Attached Disk %I%" 2481709Smlf }; 2491709Smlf 2501709Smlf static struct modlinkage modlinkage = { 2511709Smlf MODREV_1, (void *)&modlmisc, NULL 2521709Smlf }; 2531709Smlf 2541709Smlf int 2551709Smlf _init(void) 2561709Smlf { 2571709Smlf #ifdef DADK_DEBUG 2581709Smlf if (dadk_debug & DENT) 2591709Smlf PRF("dadk_init: call\n"); 2601709Smlf #endif 2611709Smlf 2621709Smlf #if defined(__x86) 2631709Smlf /* set the max physical address for iob allocs on x86 */ 2641709Smlf dadk_alloc_attr.dma_attr_addr_hi = dadk_max_phys_addr; 2651709Smlf 2661709Smlf /* 2671709Smlf * set the sgllen for iob allocs on x86. If this is set less than 2681709Smlf * the number of pages the buffer will take (taking into account 2691709Smlf * alignment), it would force the allocator to try and allocate 2701709Smlf * contiguous pages. 2711709Smlf */ 2721709Smlf dadk_alloc_attr.dma_attr_sgllen = dadk_sgl_size; 2731709Smlf #endif 2741709Smlf 2751709Smlf return (mod_install(&modlinkage)); 2761709Smlf } 2771709Smlf 2781709Smlf int 2791709Smlf _fini(void) 2801709Smlf { 2811709Smlf #ifdef DADK_DEBUG 2821709Smlf if (dadk_debug & DENT) 2831709Smlf PRF("dadk_fini: call\n"); 2841709Smlf #endif 2851709Smlf 2861709Smlf return (mod_remove(&modlinkage)); 2871709Smlf } 2881709Smlf 2891709Smlf int 2901709Smlf _info(struct modinfo *modinfop) 2911709Smlf { 2921709Smlf return (mod_info(&modlinkage, modinfop)); 2931709Smlf } 2941709Smlf 2951709Smlf struct tgdk_obj * 2961709Smlf dadk_create() 2971709Smlf { 2981709Smlf struct tgdk_obj *dkobjp; 2991709Smlf struct dadk *dadkp; 3001709Smlf 3011709Smlf dkobjp = kmem_zalloc((sizeof (*dkobjp) + sizeof (*dadkp)), KM_NOSLEEP); 3021709Smlf if (!dkobjp) 3031709Smlf return (NULL); 3041709Smlf dadkp = (struct dadk *)(dkobjp+1); 3051709Smlf 3061709Smlf dkobjp->tg_ops = (struct tgdk_objops *)&dadk_ops; 3071709Smlf dkobjp->tg_data = (opaque_t)dadkp; 3081709Smlf dkobjp->tg_ext = &(dkobjp->tg_extblk); 3091709Smlf dadkp->dad_extp = &(dkobjp->tg_extblk); 3101709Smlf 3111709Smlf #ifdef DADK_DEBUG 3121709Smlf if (dadk_debug & DENT) 3131709Smlf PRF("dadk_create: tgdkobjp= 0x%x dadkp= 0x%x\n", dkobjp, dadkp); 3141709Smlf #endif 3151709Smlf return (dkobjp); 3161709Smlf } 3171709Smlf 3181709Smlf int 3191709Smlf dadk_init(opaque_t objp, opaque_t devp, opaque_t flcobjp, opaque_t queobjp, 3201709Smlf opaque_t bbhobjp, void *lkarg) 3211709Smlf { 3221709Smlf struct dadk *dadkp = (struct dadk *)objp; 3231709Smlf struct scsi_device *sdevp = (struct scsi_device *)devp; 3241709Smlf 3251709Smlf dadkp->dad_sd = devp; 3261709Smlf dadkp->dad_ctlobjp = (opaque_t)sdevp->sd_address.a_hba_tran; 3271709Smlf sdevp->sd_private = (caddr_t)dadkp; 3281709Smlf 3291709Smlf /* initialize the communication object */ 3301709Smlf dadkp->dad_com.com_data = (opaque_t)dadkp; 3311709Smlf dadkp->dad_com.com_ops = &dadk_com_ops; 3321709Smlf 3331709Smlf dadkp->dad_bbhobjp = bbhobjp; 3341709Smlf BBH_INIT(bbhobjp); 3351709Smlf 3361709Smlf dadkp->dad_flcobjp = flcobjp; 3371709Smlf return (FLC_INIT(flcobjp, &(dadkp->dad_com), queobjp, lkarg)); 3381709Smlf } 3391709Smlf 3401709Smlf int 3411709Smlf dadk_free(struct tgdk_obj *dkobjp) 3421709Smlf { 3431709Smlf TGDK_CLEANUP(dkobjp); 3441709Smlf kmem_free(dkobjp, (sizeof (*dkobjp) + sizeof (struct dadk))); 3451709Smlf 3461709Smlf return (DDI_SUCCESS); 3471709Smlf } 3481709Smlf 3491709Smlf void 3501709Smlf dadk_cleanup(struct tgdk_obj *dkobjp) 3511709Smlf { 3521709Smlf struct dadk *dadkp; 3531709Smlf 3541709Smlf dadkp = (struct dadk *)(dkobjp->tg_data); 3551709Smlf if (dadkp->dad_sd) 3561709Smlf dadkp->dad_sd->sd_private = NULL; 3571709Smlf if (dadkp->dad_bbhobjp) { 3581709Smlf BBH_FREE(dadkp->dad_bbhobjp); 3591709Smlf dadkp->dad_bbhobjp = NULL; 3601709Smlf } 3611709Smlf if (dadkp->dad_flcobjp) { 3621709Smlf FLC_FREE(dadkp->dad_flcobjp); 3631709Smlf dadkp->dad_flcobjp = NULL; 3641709Smlf } 3651709Smlf } 3661709Smlf 3671709Smlf /* ARGSUSED */ 3681709Smlf int 3691709Smlf dadk_probe(opaque_t objp, int kmsflg) 3701709Smlf { 3711709Smlf struct dadk *dadkp = (struct dadk *)objp; 3721709Smlf struct scsi_device *devp; 3731709Smlf char name[80]; 3741709Smlf 3751709Smlf devp = dadkp->dad_sd; 3761709Smlf if (!devp->sd_inq || (devp->sd_inq->inq_dtype == DTYPE_NOTPRESENT) || 3771709Smlf (devp->sd_inq->inq_dtype == DTYPE_UNKNOWN)) { 3781709Smlf return (DDI_PROBE_FAILURE); 3791709Smlf } 3801709Smlf 3811709Smlf switch (devp->sd_inq->inq_dtype) { 3821709Smlf case DTYPE_DIRECT: 3831709Smlf dadkp->dad_ctype = DKC_DIRECT; 3841709Smlf dadkp->dad_extp->tg_nodetype = DDI_NT_BLOCK; 3851709Smlf dadkp->dad_extp->tg_ctype = DKC_DIRECT; 3861709Smlf break; 3871709Smlf case DTYPE_RODIRECT: /* eg cdrom */ 3881709Smlf dadkp->dad_ctype = DKC_CDROM; 3891709Smlf dadkp->dad_extp->tg_rdonly = 1; 3901709Smlf dadkp->dad_rdonly = 1; 3911709Smlf dadkp->dad_cdrom = 1; 3921709Smlf dadkp->dad_extp->tg_nodetype = DDI_NT_CD; 3931709Smlf dadkp->dad_extp->tg_ctype = DKC_CDROM; 3941709Smlf break; 3951709Smlf case DTYPE_WORM: 3961709Smlf case DTYPE_OPTICAL: 3971709Smlf default: 3981709Smlf return (DDI_PROBE_FAILURE); 3991709Smlf } 4001709Smlf 4011709Smlf dadkp->dad_extp->tg_rmb = dadkp->dad_rmb = devp->sd_inq->inq_rmb; 4021709Smlf 4031709Smlf dadkp->dad_secshf = SCTRSHFT; 4041709Smlf dadkp->dad_blkshf = 0; 4051709Smlf 4061709Smlf /* display the device name */ 4071709Smlf (void) strcpy(name, "Vendor '"); 4081709Smlf gda_inqfill((caddr_t)devp->sd_inq->inq_vid, 8, &name[strlen(name)]); 4091709Smlf (void) strcat(name, "' Product '"); 4101709Smlf gda_inqfill((caddr_t)devp->sd_inq->inq_pid, 16, &name[strlen(name)]); 4111709Smlf (void) strcat(name, "'"); 4121709Smlf gda_log(devp->sd_dev, dadk_name, CE_NOTE, "!<%s>\n", name); 4131709Smlf 4141709Smlf return (DDI_PROBE_SUCCESS); 4151709Smlf } 4161709Smlf 4171709Smlf 4181709Smlf /* ARGSUSED */ 4191709Smlf int 4201709Smlf dadk_attach(opaque_t objp) 4211709Smlf { 4221709Smlf return (DDI_SUCCESS); 4231709Smlf } 4241709Smlf 4251709Smlf int 4261709Smlf dadk_set_bbhobj(opaque_t objp, opaque_t bbhobjp) 4271709Smlf { 4281709Smlf struct dadk *dadkp = (struct dadk *)objp; 4291709Smlf /* free the old bbh object */ 4301709Smlf if (dadkp->dad_bbhobjp) 4311709Smlf BBH_FREE(dadkp->dad_bbhobjp); 4321709Smlf 4331709Smlf /* initialize the new bbh object */ 4341709Smlf dadkp->dad_bbhobjp = bbhobjp; 4351709Smlf BBH_INIT(bbhobjp); 4361709Smlf 4371709Smlf return (DDI_SUCCESS); 4381709Smlf } 4391709Smlf 4401709Smlf /* ARGSUSED */ 4411709Smlf int 4421709Smlf dadk_open(opaque_t objp, int flag) 4431709Smlf { 4441709Smlf struct dadk *dadkp = (struct dadk *)objp; 4451709Smlf int error; 4461709Smlf int wce; 4471709Smlf 4481709Smlf if (!dadkp->dad_rmb) { 4491709Smlf if (dadkp->dad_phyg.g_cap) { 4501709Smlf FLC_START_KSTAT(dadkp->dad_flcobjp, "disk", 4511709Smlf ddi_get_instance(CTL_DIP_DEV(dadkp->dad_ctlobjp))); 4521709Smlf return (DDI_SUCCESS); 4531709Smlf } 4541709Smlf } else { 4551709Smlf mutex_enter(&dadkp->dad_mutex); 4561709Smlf dadkp->dad_iostate = DKIO_NONE; 4571709Smlf cv_broadcast(&dadkp->dad_state_cv); 4581709Smlf mutex_exit(&dadkp->dad_mutex); 4591709Smlf 4601709Smlf if (dadk_rmb_ioctl(dadkp, DCMD_START_MOTOR, 0, 0, DADK_SILENT) || 4611709Smlf dadk_rmb_ioctl(dadkp, DCMD_LOCK, 0, 0, DADK_SILENT) || 4621709Smlf dadk_rmb_ioctl(dadkp, DCMD_UPDATE_GEOM, 0, 0, DADK_SILENT)) { 4631709Smlf return (DDI_FAILURE); 4641709Smlf } 4651709Smlf 4661709Smlf mutex_enter(&dadkp->dad_mutex); 4671709Smlf dadkp->dad_iostate = DKIO_INSERTED; 4681709Smlf cv_broadcast(&dadkp->dad_state_cv); 4691709Smlf mutex_exit(&dadkp->dad_mutex); 4701709Smlf } 4711709Smlf 4721709Smlf /* 4731709Smlf * get write cache enable state 4741709Smlf * If there is an error, must assume that write cache 4751709Smlf * is enabled. 4761709Smlf * NOTE: Since there is currently no Solaris mechanism to 4771709Smlf * change the state of the Write Cache Enable feature, 4781709Smlf * this code just checks the value of the WCE bit 4791709Smlf * obtained at device init time. If a mechanism 4801709Smlf * is added to the driver to change WCE, dad_wce 4811709Smlf * must be updated appropriately. 4821709Smlf */ 4831709Smlf error = CTL_IOCTL(dadkp->dad_ctlobjp, DIOCTL_GETWCE, 4842799Smarx (uintptr_t)&wce, FKIOCTL | FNATIVE); 4851709Smlf mutex_enter(&dadkp->dad_mutex); 4861709Smlf dadkp->dad_wce = (error != 0) || (wce != 0); 4871709Smlf mutex_exit(&dadkp->dad_mutex); 4881709Smlf 4891709Smlf /* logical disk geometry */ 4901709Smlf CTL_IOCTL(dadkp->dad_ctlobjp, DIOCTL_GETGEOM, 4912799Smarx (uintptr_t)&dadkp->dad_logg, FKIOCTL | FNATIVE); 4921709Smlf if (dadkp->dad_logg.g_cap == 0) 4931709Smlf return (DDI_FAILURE); 4941709Smlf 4951709Smlf /* get physical disk geometry */ 4961709Smlf CTL_IOCTL(dadkp->dad_ctlobjp, DIOCTL_GETPHYGEOM, 4972799Smarx (uintptr_t)&dadkp->dad_phyg, FKIOCTL | FNATIVE); 4981709Smlf if (dadkp->dad_phyg.g_cap == 0) 4991709Smlf return (DDI_FAILURE); 5001709Smlf 5011709Smlf dadk_setcap(dadkp); 5021709Smlf 5032799Smarx dadk_create_errstats(dadkp, 5042799Smarx ddi_get_instance(CTL_DIP_DEV(dadkp->dad_ctlobjp))); 5052799Smarx 5061709Smlf /* start profiling */ 5071709Smlf FLC_START_KSTAT(dadkp->dad_flcobjp, "disk", 5081709Smlf ddi_get_instance(CTL_DIP_DEV(dadkp->dad_ctlobjp))); 5091709Smlf 5101709Smlf return (DDI_SUCCESS); 5111709Smlf } 5121709Smlf 5131709Smlf static void 5141709Smlf dadk_setcap(struct dadk *dadkp) 5151709Smlf { 5161709Smlf int totsize; 5171709Smlf int i; 5181709Smlf 5191709Smlf totsize = dadkp->dad_phyg.g_secsiz; 5201709Smlf 5211709Smlf if (totsize == 0) { 5221709Smlf if (dadkp->dad_cdrom) { 5231709Smlf totsize = 2048; 5241709Smlf } else { 5251709Smlf totsize = NBPSCTR; 5261709Smlf } 5271709Smlf } else { 5281709Smlf /* Round down sector size to multiple of 512B */ 5291709Smlf totsize &= ~(NBPSCTR-1); 5301709Smlf } 5311709Smlf dadkp->dad_phyg.g_secsiz = totsize; 5321709Smlf 5331709Smlf /* set sec,block shift factor - (512->0, 1024->1, 2048->2, etc.) */ 5341709Smlf totsize >>= SCTRSHFT; 5351709Smlf for (i = 0; totsize != 1; i++, totsize >>= 1); 5361709Smlf dadkp->dad_blkshf = i; 5371709Smlf dadkp->dad_secshf = i + SCTRSHFT; 5381709Smlf } 5391709Smlf 5401709Smlf 5412799Smarx static void 5422799Smarx dadk_create_errstats(struct dadk *dadkp, int instance) 5432799Smarx { 5442799Smarx dadk_errstats_t *dep; 5452799Smarx char kstatname[KSTAT_STRLEN]; 5462799Smarx dadk_ioc_string_t dadk_ioc_string; 5472799Smarx 5482799Smarx if (dadkp->dad_errstats) 5492799Smarx return; 5502799Smarx 5512799Smarx (void) sprintf(kstatname, "cmdk%d,error", instance); 5522799Smarx dadkp->dad_errstats = kstat_create("cmdkerror", instance, 5532799Smarx kstatname, "device_error", KSTAT_TYPE_NAMED, 5542799Smarx sizeof (dadk_errstats_t) / sizeof (kstat_named_t), 5552799Smarx KSTAT_FLAG_PERSISTENT); 5562799Smarx 5572799Smarx if (!dadkp->dad_errstats) 5582799Smarx return; 5592799Smarx 5602799Smarx dep = (dadk_errstats_t *)dadkp->dad_errstats->ks_data; 5612799Smarx 5622799Smarx kstat_named_init(&dep->dadk_softerrs, 5632799Smarx "Soft Errors", KSTAT_DATA_UINT32); 5642799Smarx kstat_named_init(&dep->dadk_harderrs, 5652799Smarx "Hard Errors", KSTAT_DATA_UINT32); 5662799Smarx kstat_named_init(&dep->dadk_transerrs, 5672799Smarx "Transport Errors", KSTAT_DATA_UINT32); 5682799Smarx kstat_named_init(&dep->dadk_model, 5692799Smarx "Model", KSTAT_DATA_CHAR); 5702799Smarx kstat_named_init(&dep->dadk_revision, 5712799Smarx "Revision", KSTAT_DATA_CHAR); 5722799Smarx kstat_named_init(&dep->dadk_serial, 5732799Smarx "Serial No", KSTAT_DATA_CHAR); 5742799Smarx kstat_named_init(&dep->dadk_capacity, 5752799Smarx "Size", KSTAT_DATA_ULONGLONG); 5762799Smarx kstat_named_init(&dep->dadk_rq_media_err, 5772799Smarx "Media Error", KSTAT_DATA_UINT32); 5782799Smarx kstat_named_init(&dep->dadk_rq_ntrdy_err, 5792799Smarx "Device Not Ready", KSTAT_DATA_UINT32); 5802799Smarx kstat_named_init(&dep->dadk_rq_nodev_err, 5812799Smarx "No Device", KSTAT_DATA_UINT32); 5822799Smarx kstat_named_init(&dep->dadk_rq_recov_err, 5832799Smarx "Recoverable", KSTAT_DATA_UINT32); 5842799Smarx kstat_named_init(&dep->dadk_rq_illrq_err, 5852799Smarx "Illegal Request", KSTAT_DATA_UINT32); 5862799Smarx 5872799Smarx dadkp->dad_errstats->ks_private = dep; 5882799Smarx dadkp->dad_errstats->ks_update = nulldev; 5892799Smarx kstat_install(dadkp->dad_errstats); 5902799Smarx 5912799Smarx /* get model */ 5922799Smarx dep->dadk_model.value.c[0] = 0; 5932799Smarx dadk_ioc_string.is_buf = &dep->dadk_model.value.c[0]; 594*3399Smarx dadk_ioc_string.is_size = sizeof (dep->dadk_model.value.c); 5952799Smarx CTL_IOCTL(dadkp->dad_ctlobjp, DIOCTL_GETMODEL, 5962799Smarx (uintptr_t)&dadk_ioc_string, FKIOCTL | FNATIVE); 5972799Smarx 5982799Smarx /* get serial */ 5992799Smarx dep->dadk_serial.value.c[0] = 0; 6002799Smarx dadk_ioc_string.is_buf = &dep->dadk_serial.value.c[0]; 601*3399Smarx dadk_ioc_string.is_size = sizeof (dep->dadk_serial.value.c); 6022799Smarx CTL_IOCTL(dadkp->dad_ctlobjp, DIOCTL_GETSERIAL, 6032799Smarx (uintptr_t)&dadk_ioc_string, FKIOCTL | FNATIVE); 6042799Smarx 6052799Smarx /* Get revision */ 6062799Smarx dep->dadk_revision.value.c[0] = 0; 6072799Smarx 6082799Smarx /* Get capacity */ 6092799Smarx 6102799Smarx dep->dadk_capacity.value.ui64 = 6112799Smarx (uint64_t)dadkp->dad_logg.g_cap * 6122799Smarx (uint64_t)dadkp->dad_logg.g_secsiz; 6132799Smarx } 6142799Smarx 6152799Smarx 6161709Smlf int 6171709Smlf dadk_close(opaque_t objp) 6181709Smlf { 6191709Smlf struct dadk *dadkp = (struct dadk *)objp; 6201709Smlf 6211709Smlf if (dadkp->dad_rmb) { 6221709Smlf (void) dadk_rmb_ioctl(dadkp, DCMD_STOP_MOTOR, 0, 0, 6231709Smlf DADK_SILENT); 6241709Smlf (void) dadk_rmb_ioctl(dadkp, DCMD_UNLOCK, 0, 0, DADK_SILENT); 6251709Smlf } 6261709Smlf FLC_STOP_KSTAT(dadkp->dad_flcobjp); 6272799Smarx 6282799Smarx dadk_destroy_errstats(dadkp); 6292799Smarx 6301709Smlf return (DDI_SUCCESS); 6311709Smlf } 6321709Smlf 6332799Smarx static void 6342799Smarx dadk_destroy_errstats(struct dadk *dadkp) 6352799Smarx { 6362799Smarx if (!dadkp->dad_errstats) 6372799Smarx return; 6382799Smarx 6392799Smarx kstat_delete(dadkp->dad_errstats); 6402799Smarx dadkp->dad_errstats = NULL; 6412799Smarx } 6422799Smarx 6432799Smarx 6441709Smlf int 6451709Smlf dadk_strategy(opaque_t objp, struct buf *bp) 6461709Smlf { 6471709Smlf struct dadk *dadkp = (struct dadk *)objp; 6481709Smlf 6491709Smlf if (dadkp->dad_rdonly && !(bp->b_flags & B_READ)) { 6501709Smlf bioerror(bp, EROFS); 6511709Smlf return (DDI_FAILURE); 6521709Smlf } 6531709Smlf 6541709Smlf if (bp->b_bcount & (dadkp->DAD_SECSIZ-1)) { 6551709Smlf bioerror(bp, ENXIO); 6561709Smlf return (DDI_FAILURE); 6571709Smlf } 6581709Smlf 6591709Smlf SET_BP_SEC(bp, (LBLK2SEC(GET_BP_SEC(bp), dadkp->dad_blkshf))); 6601709Smlf FLC_ENQUE(dadkp->dad_flcobjp, bp); 6611709Smlf 6621709Smlf return (DDI_SUCCESS); 6631709Smlf } 6641709Smlf 6651709Smlf int 6661709Smlf dadk_dump(opaque_t objp, struct buf *bp) 6671709Smlf { 6681709Smlf struct dadk *dadkp = (struct dadk *)objp; 6691709Smlf struct cmpkt *pktp; 6701709Smlf 6711709Smlf if (dadkp->dad_rdonly) { 6721709Smlf bioerror(bp, EROFS); 6731709Smlf return (DDI_FAILURE); 6741709Smlf } 6751709Smlf 6761709Smlf if (bp->b_bcount & (dadkp->DAD_SECSIZ-1)) { 6771709Smlf bioerror(bp, ENXIO); 6781709Smlf return (DDI_FAILURE); 6791709Smlf } 6801709Smlf 6811709Smlf SET_BP_SEC(bp, (LBLK2SEC(GET_BP_SEC(bp), dadkp->dad_blkshf))); 6821709Smlf 6831709Smlf pktp = dadk_pktprep(dadkp, NULL, bp, dadk_polldone, NULL, NULL); 6841709Smlf if (!pktp) { 6851709Smlf cmn_err(CE_WARN, "no resources for dumping"); 6861709Smlf bioerror(bp, EIO); 6871709Smlf return (DDI_FAILURE); 6881709Smlf } 6891709Smlf pktp->cp_flags |= CPF_NOINTR; 6901709Smlf 6911709Smlf (void) dadk_ioprep(dadkp, pktp); 6921709Smlf dadk_transport(dadkp, bp); 6931709Smlf pktp->cp_byteleft -= pktp->cp_bytexfer; 6941709Smlf 6951709Smlf while (geterror(bp) == 0 && pktp->cp_byteleft != 0) { 6961709Smlf (void) dadk_iosetup(dadkp, pktp); 6971709Smlf dadk_transport(dadkp, bp); 6981709Smlf pktp->cp_byteleft -= pktp->cp_bytexfer; 6991709Smlf } 7001709Smlf 7011709Smlf if (pktp->cp_private) 7021709Smlf BBH_FREEHANDLE(dadkp->dad_bbhobjp, pktp->cp_private); 7031709Smlf gda_free(dadkp->dad_ctlobjp, pktp, NULL); 7041709Smlf return (DDI_SUCCESS); 7051709Smlf } 7061709Smlf 7071709Smlf /* ARGSUSED */ 7081709Smlf int 7091709Smlf dadk_ioctl(opaque_t objp, dev_t dev, int cmd, intptr_t arg, int flag, 7101709Smlf cred_t *cred_p, int *rval_p) 7111709Smlf { 7121709Smlf struct dadk *dadkp = (struct dadk *)objp; 7131709Smlf 7141709Smlf switch (cmd) { 7151709Smlf case DKIOCGETDEF: 7161709Smlf { 7171709Smlf struct buf *bp; 7181709Smlf int err, head; 7191709Smlf unsigned char *secbuf; 7201709Smlf STRUCT_DECL(defect_header, adh); 7211709Smlf 7221709Smlf STRUCT_INIT(adh, flag & FMODELS); 7231709Smlf 7241709Smlf /* 7251709Smlf * copyin header .... 7261709Smlf * yields head number and buffer address 7271709Smlf */ 7281709Smlf if (ddi_copyin((caddr_t)arg, STRUCT_BUF(adh), STRUCT_SIZE(adh), 7291709Smlf flag)) 7301709Smlf return (EFAULT); 7311709Smlf head = STRUCT_FGET(adh, head); 7321709Smlf if (head < 0 || head >= dadkp->dad_phyg.g_head) 7331709Smlf return (ENXIO); 7341709Smlf secbuf = kmem_zalloc(NBPSCTR, KM_SLEEP); 7351709Smlf if (!secbuf) 7361709Smlf return (ENOMEM); 7371709Smlf bp = getrbuf(KM_SLEEP); 7381709Smlf if (!bp) { 7391709Smlf kmem_free(secbuf, NBPSCTR); 7401709Smlf return (ENOMEM); 7411709Smlf } 7421709Smlf 7431709Smlf bp->b_edev = dev; 7441709Smlf bp->b_dev = cmpdev(dev); 7451709Smlf bp->b_flags = B_BUSY; 7461709Smlf bp->b_resid = 0; 7471709Smlf bp->b_bcount = NBPSCTR; 7481709Smlf bp->b_un.b_addr = (caddr_t)secbuf; 7491709Smlf bp->b_blkno = head; /* I had to put it somwhere! */ 7501709Smlf bp->b_forw = (struct buf *)dadkp; 7511709Smlf bp->b_back = (struct buf *)DCMD_GETDEF; 7521709Smlf 7531709Smlf FLC_ENQUE(dadkp->dad_flcobjp, bp); 7541709Smlf err = biowait(bp); 7551709Smlf if (!err) { 7561709Smlf if (ddi_copyout((caddr_t)secbuf, 7571709Smlf STRUCT_FGETP(adh, buffer), NBPSCTR, flag)) 7581709Smlf err = ENXIO; 7591709Smlf } 7601709Smlf kmem_free(secbuf, NBPSCTR); 7611709Smlf freerbuf(bp); 7621709Smlf return (err); 7631709Smlf } 7641709Smlf case DIOCTL_RWCMD: 7651709Smlf { 7661709Smlf struct dadkio_rwcmd *rwcmdp; 7671709Smlf int status, rw; 7681709Smlf 7691709Smlf /* 7701709Smlf * copied in by cmdk and, if necessary, converted to the 7711709Smlf * correct datamodel 7721709Smlf */ 7731709Smlf rwcmdp = (struct dadkio_rwcmd *)(intptr_t)arg; 7741709Smlf 7751709Smlf /* 7761709Smlf * handle the complex cases here; we pass these 7771709Smlf * through to the driver, which will queue them and 7781709Smlf * handle the requests asynchronously. The simpler 7791709Smlf * cases ,which can return immediately, fail here, and 7801709Smlf * the request reverts to the dadk_ioctl routine, while 7811709Smlf * will reroute them directly to the ata driver. 7821709Smlf */ 7831709Smlf switch (rwcmdp->cmd) { 7841709Smlf case DADKIO_RWCMD_READ : 7851709Smlf /*FALLTHROUGH*/ 7861709Smlf case DADKIO_RWCMD_WRITE: 7871709Smlf rw = ((rwcmdp->cmd == DADKIO_RWCMD_WRITE) ? 7881709Smlf B_WRITE : B_READ); 7891709Smlf status = dadk_dk_buf_setup(dadkp, 7901709Smlf (opaque_t)rwcmdp, dev, ((flag &FKIOCTL) ? 7911709Smlf UIO_SYSSPACE : UIO_USERSPACE), rw); 7921709Smlf return (status); 7931709Smlf default: 7941709Smlf return (EINVAL); 7951709Smlf } 7961709Smlf } 7971709Smlf case DKIOCFLUSHWRITECACHE: 7981709Smlf { 7991709Smlf struct buf *bp; 8001709Smlf int err = 0; 8011709Smlf struct dk_callback *dkc = (struct dk_callback *)arg; 8021709Smlf struct cmpkt *pktp; 8031709Smlf int is_sync = 1; 8041709Smlf 8051709Smlf mutex_enter(&dadkp->dad_mutex); 8061709Smlf if (dadkp->dad_noflush || ! dadkp->dad_wce) { 8071709Smlf err = dadkp->dad_noflush ? ENOTSUP : 0; 8081709Smlf mutex_exit(&dadkp->dad_mutex); 8091709Smlf /* 8101709Smlf * If a callback was requested: a 8111709Smlf * callback will always be done if the 8121709Smlf * caller saw the DKIOCFLUSHWRITECACHE 8131709Smlf * ioctl return 0, and never done if the 8141709Smlf * caller saw the ioctl return an error. 8151709Smlf */ 8161709Smlf if ((flag & FKIOCTL) && dkc != NULL && 8171709Smlf dkc->dkc_callback != NULL) { 8181709Smlf (*dkc->dkc_callback)(dkc->dkc_cookie, 8191709Smlf err); 8201709Smlf /* 8211709Smlf * Did callback and reported error. 8221709Smlf * Since we did a callback, ioctl 8231709Smlf * should return 0. 8241709Smlf */ 8251709Smlf err = 0; 8261709Smlf } 8271709Smlf return (err); 8281709Smlf } 8291709Smlf mutex_exit(&dadkp->dad_mutex); 8301709Smlf 8311709Smlf bp = getrbuf(KM_SLEEP); 8321709Smlf 8331709Smlf bp->b_edev = dev; 8341709Smlf bp->b_dev = cmpdev(dev); 8351709Smlf bp->b_flags = B_BUSY; 8361709Smlf bp->b_resid = 0; 8371709Smlf bp->b_bcount = 0; 8381709Smlf SET_BP_SEC(bp, 0); 8391709Smlf 8401709Smlf if ((flag & FKIOCTL) && dkc != NULL && 8411709Smlf dkc->dkc_callback != NULL) { 8421709Smlf struct dk_callback *dkc2 = 8431709Smlf (struct dk_callback *)kmem_zalloc( 8441709Smlf sizeof (struct dk_callback), KM_SLEEP); 8451709Smlf 8461709Smlf bcopy(dkc, dkc2, sizeof (*dkc2)); 8471709Smlf /* 8481709Smlf * Borrow b_list to carry private data 8491709Smlf * to the b_iodone func. 8501709Smlf */ 8511709Smlf bp->b_list = (struct buf *)dkc2; 8521709Smlf bp->b_iodone = dadk_flushdone; 8531709Smlf is_sync = 0; 8541709Smlf } 8551709Smlf 8561709Smlf /* 8571709Smlf * Setup command pkt 8581709Smlf * dadk_pktprep() can't fail since DDI_DMA_SLEEP set 8591709Smlf */ 8601709Smlf pktp = dadk_pktprep(dadkp, NULL, bp, 8611709Smlf dadk_iodone, DDI_DMA_SLEEP, NULL); 8621709Smlf 8631709Smlf pktp->cp_time = DADK_FLUSH_CACHE_TIME; 8641709Smlf 8651709Smlf *((char *)(pktp->cp_cdbp)) = DCMD_FLUSH_CACHE; 8661709Smlf pktp->cp_byteleft = 0; 8671709Smlf pktp->cp_private = NULL; 8681709Smlf pktp->cp_secleft = 0; 8691709Smlf pktp->cp_srtsec = -1; 8701709Smlf pktp->cp_bytexfer = 0; 8711709Smlf 8721709Smlf CTL_IOSETUP(dadkp->dad_ctlobjp, pktp); 8731709Smlf 8741709Smlf FLC_ENQUE(dadkp->dad_flcobjp, bp); 8751709Smlf 8761709Smlf if (is_sync) { 8771709Smlf err = biowait(bp); 8781709Smlf freerbuf(bp); 8791709Smlf } 8801709Smlf return (err); 8811709Smlf } 8821709Smlf default: 8831709Smlf if (!dadkp->dad_rmb) 8841709Smlf return (CTL_IOCTL(dadkp->dad_ctlobjp, cmd, arg, flag)); 8851709Smlf } 8861709Smlf 8871709Smlf switch (cmd) { 8881709Smlf case CDROMSTOP: 8891709Smlf return (dadk_rmb_ioctl(dadkp, DCMD_STOP_MOTOR, 0, 8901709Smlf 0, DADK_SILENT)); 8911709Smlf case CDROMSTART: 8921709Smlf return (dadk_rmb_ioctl(dadkp, DCMD_START_MOTOR, 0, 8931709Smlf 0, DADK_SILENT)); 8941709Smlf case DKIOCLOCK: 8951709Smlf return (dadk_rmb_ioctl(dadkp, DCMD_LOCK, 0, 0, DADK_SILENT)); 8961709Smlf case DKIOCUNLOCK: 8971709Smlf return (dadk_rmb_ioctl(dadkp, DCMD_UNLOCK, 0, 0, DADK_SILENT)); 8981709Smlf case DKIOCEJECT: 8991709Smlf case CDROMEJECT: 9001709Smlf { 9011709Smlf int ret; 9021709Smlf 9031709Smlf if (ret = dadk_rmb_ioctl(dadkp, DCMD_UNLOCK, 0, 0, 9041709Smlf DADK_SILENT)) { 9051709Smlf return (ret); 9061709Smlf } 9071709Smlf if (ret = dadk_rmb_ioctl(dadkp, DCMD_EJECT, 0, 0, 9081709Smlf DADK_SILENT)) { 9091709Smlf return (ret); 9101709Smlf } 9111709Smlf mutex_enter(&dadkp->dad_mutex); 9121709Smlf dadkp->dad_iostate = DKIO_EJECTED; 9131709Smlf cv_broadcast(&dadkp->dad_state_cv); 9141709Smlf mutex_exit(&dadkp->dad_mutex); 9151709Smlf 9161709Smlf return (0); 9171709Smlf 9181709Smlf } 9191709Smlf default: 9201709Smlf return (ENOTTY); 9211709Smlf /* 9221709Smlf * cdrom audio commands 9231709Smlf */ 9241709Smlf case CDROMPAUSE: 9251709Smlf cmd = DCMD_PAUSE; 9261709Smlf break; 9271709Smlf case CDROMRESUME: 9281709Smlf cmd = DCMD_RESUME; 9291709Smlf break; 9301709Smlf case CDROMPLAYMSF: 9311709Smlf cmd = DCMD_PLAYMSF; 9321709Smlf break; 9331709Smlf case CDROMPLAYTRKIND: 9341709Smlf cmd = DCMD_PLAYTRKIND; 9351709Smlf break; 9361709Smlf case CDROMREADTOCHDR: 9371709Smlf cmd = DCMD_READTOCHDR; 9381709Smlf break; 9391709Smlf case CDROMREADTOCENTRY: 9401709Smlf cmd = DCMD_READTOCENT; 9411709Smlf break; 9421709Smlf case CDROMVOLCTRL: 9431709Smlf cmd = DCMD_VOLCTRL; 9441709Smlf break; 9451709Smlf case CDROMSUBCHNL: 9461709Smlf cmd = DCMD_SUBCHNL; 9471709Smlf break; 9481709Smlf case CDROMREADMODE2: 9491709Smlf cmd = DCMD_READMODE2; 9501709Smlf break; 9511709Smlf case CDROMREADMODE1: 9521709Smlf cmd = DCMD_READMODE1; 9531709Smlf break; 9541709Smlf case CDROMREADOFFSET: 9551709Smlf cmd = DCMD_READOFFSET; 9561709Smlf break; 9571709Smlf } 9581709Smlf return (dadk_rmb_ioctl(dadkp, cmd, arg, flag, 0)); 9591709Smlf } 9601709Smlf 9611709Smlf int 9621709Smlf dadk_flushdone(struct buf *bp) 9631709Smlf { 9641709Smlf struct dk_callback *dkc = (struct dk_callback *)bp->b_list; 9651709Smlf 9661709Smlf ASSERT(dkc != NULL && dkc->dkc_callback != NULL); 9671709Smlf 9681709Smlf (*dkc->dkc_callback)(dkc->dkc_cookie, geterror(bp)); 9691709Smlf 9701709Smlf kmem_free(dkc, sizeof (*dkc)); 9711709Smlf freerbuf(bp); 9721709Smlf return (0); 9731709Smlf } 9741709Smlf 9751709Smlf int 9761709Smlf dadk_getphygeom(opaque_t objp, struct tgdk_geom *dkgeom_p) 9771709Smlf { 9781709Smlf struct dadk *dadkp = (struct dadk *)objp; 9791709Smlf 9801709Smlf bcopy((caddr_t)&dadkp->dad_phyg, (caddr_t)dkgeom_p, 9811709Smlf sizeof (struct tgdk_geom)); 9821709Smlf return (DDI_SUCCESS); 9831709Smlf } 9841709Smlf 9851709Smlf int 9861709Smlf dadk_getgeom(opaque_t objp, struct tgdk_geom *dkgeom_p) 9871709Smlf { 9881709Smlf struct dadk *dadkp = (struct dadk *)objp; 9891709Smlf bcopy((caddr_t)&dadkp->dad_logg, (caddr_t)dkgeom_p, 9901709Smlf sizeof (struct tgdk_geom)); 9911709Smlf return (DDI_SUCCESS); 9921709Smlf } 9931709Smlf 9941709Smlf int 9951709Smlf dadk_setgeom(opaque_t objp, struct tgdk_geom *dkgeom_p) 9961709Smlf { 9971709Smlf struct dadk *dadkp = (struct dadk *)objp; 9981709Smlf 9991709Smlf dadkp->dad_logg.g_cyl = dkgeom_p->g_cyl; 10001709Smlf dadkp->dad_logg.g_head = dkgeom_p->g_head; 10011709Smlf dadkp->dad_logg.g_sec = dkgeom_p->g_sec; 10021709Smlf dadkp->dad_logg.g_cap = dkgeom_p->g_cap; 10031709Smlf return (DDI_SUCCESS); 10041709Smlf } 10051709Smlf 10061709Smlf 10071709Smlf tgdk_iob_handle 10081709Smlf dadk_iob_alloc(opaque_t objp, daddr_t blkno, ssize_t xfer, int kmsflg) 10091709Smlf { 10101709Smlf struct dadk *dadkp = (struct dadk *)objp; 10111709Smlf struct buf *bp; 10121709Smlf struct tgdk_iob *iobp; 10131709Smlf size_t rlen; 10141709Smlf 10151709Smlf iobp = kmem_zalloc(sizeof (*iobp), kmsflg); 10161709Smlf if (iobp == NULL) 10171709Smlf return (NULL); 10181709Smlf if ((bp = getrbuf(kmsflg)) == NULL) { 10191709Smlf kmem_free(iobp, sizeof (*iobp)); 10201709Smlf return (NULL); 10211709Smlf } 10221709Smlf 10231709Smlf iobp->b_psec = LBLK2SEC(blkno, dadkp->dad_blkshf); 10241709Smlf iobp->b_pbyteoff = (blkno & ((1<<dadkp->dad_blkshf) - 1)) << SCTRSHFT; 10251709Smlf iobp->b_pbytecnt = ((iobp->b_pbyteoff + xfer + dadkp->DAD_SECSIZ - 1) 10261709Smlf >> dadkp->dad_secshf) << dadkp->dad_secshf; 10271709Smlf 10281709Smlf bp->b_un.b_addr = 0; 10291709Smlf /* 10301709Smlf * use i_ddi_mem_alloc() for now until we have an interface to allocate 10311709Smlf * memory for DMA which doesn't require a DMA handle. ddi_iopb_alloc() 10321709Smlf * is obsolete and we want more flexibility in controlling the DMA 10331709Smlf * address constraints.. 10341709Smlf */ 10351709Smlf if (i_ddi_mem_alloc((dadkp->dad_sd)->sd_dev, &dadk_alloc_attr, 10361709Smlf (size_t)iobp->b_pbytecnt, ((kmsflg == KM_SLEEP) ? 1 : 0), 0, NULL, 10371709Smlf &bp->b_un.b_addr, &rlen, NULL) != DDI_SUCCESS) { 10381709Smlf freerbuf(bp); 10391709Smlf kmem_free(iobp, sizeof (*iobp)); 10401709Smlf return (NULL); 10411709Smlf } 10421709Smlf iobp->b_flag |= IOB_BPALLOC | IOB_BPBUFALLOC; 10431709Smlf iobp->b_bp = bp; 10441709Smlf iobp->b_lblk = blkno; 10451709Smlf iobp->b_xfer = xfer; 10461709Smlf iobp->b_lblk = blkno; 10471709Smlf iobp->b_xfer = xfer; 10481709Smlf return (iobp); 10491709Smlf } 10501709Smlf 10511709Smlf /* ARGSUSED */ 10521709Smlf int 10531709Smlf dadk_iob_free(opaque_t objp, struct tgdk_iob *iobp) 10541709Smlf { 10551709Smlf struct buf *bp; 10561709Smlf 10571709Smlf if (iobp) { 10581709Smlf if (iobp->b_bp && (iobp->b_flag & IOB_BPALLOC)) { 10591709Smlf bp = iobp->b_bp; 10601709Smlf if (bp->b_un.b_addr && (iobp->b_flag & IOB_BPBUFALLOC)) 10611900Seota i_ddi_mem_free((caddr_t)bp->b_un.b_addr, NULL); 10621709Smlf freerbuf(bp); 10631709Smlf } 10641709Smlf kmem_free(iobp, sizeof (*iobp)); 10651709Smlf } 10661709Smlf return (DDI_SUCCESS); 10671709Smlf } 10681709Smlf 10691709Smlf /* ARGSUSED */ 10701709Smlf caddr_t 10711709Smlf dadk_iob_htoc(opaque_t objp, struct tgdk_iob *iobp) 10721709Smlf { 10731709Smlf return (iobp->b_bp->b_un.b_addr+iobp->b_pbyteoff); 10741709Smlf } 10751709Smlf 10761709Smlf 10771709Smlf caddr_t 10781709Smlf dadk_iob_xfer(opaque_t objp, struct tgdk_iob *iobp, int rw) 10791709Smlf { 10801709Smlf struct dadk *dadkp = (struct dadk *)objp; 10811709Smlf struct buf *bp; 10821709Smlf int err; 10831709Smlf 10841709Smlf bp = iobp->b_bp; 10851709Smlf if (dadkp->dad_rdonly && !(rw & B_READ)) { 10861709Smlf bioerror(bp, EROFS); 10871709Smlf return (NULL); 10881709Smlf } 10891709Smlf 10901709Smlf bp->b_flags |= (B_BUSY | rw); 10911709Smlf bp->b_bcount = iobp->b_pbytecnt; 10921709Smlf SET_BP_SEC(bp, iobp->b_psec); 10931709Smlf bp->av_back = (struct buf *)0; 10941709Smlf bp->b_resid = 0; 10951709Smlf 10961709Smlf /* call flow control */ 10971709Smlf FLC_ENQUE(dadkp->dad_flcobjp, bp); 10981709Smlf err = biowait(bp); 10991709Smlf 11001709Smlf bp->b_bcount = iobp->b_xfer; 11011709Smlf bp->b_flags &= ~(B_DONE|B_BUSY); 11021709Smlf 11031709Smlf if (err) 11041709Smlf return (NULL); 11051709Smlf 11061709Smlf return (bp->b_un.b_addr+iobp->b_pbyteoff); 11071709Smlf } 11081709Smlf 11091709Smlf static void 11101709Smlf dadk_transport(opaque_t com_data, struct buf *bp) 11111709Smlf { 11121709Smlf struct dadk *dadkp = (struct dadk *)com_data; 11131709Smlf 11141709Smlf if (CTL_TRANSPORT(dadkp->dad_ctlobjp, GDA_BP_PKT(bp)) == 11151709Smlf CTL_SEND_SUCCESS) 11161709Smlf return; 11171709Smlf dadk_restart((void*)GDA_BP_PKT(bp)); 11181709Smlf } 11191709Smlf 11201709Smlf static int 11211709Smlf dadk_pkt(opaque_t com_data, struct buf *bp, int (*func)(caddr_t), caddr_t arg) 11221709Smlf { 11231709Smlf struct cmpkt *pktp; 11241709Smlf struct dadk *dadkp = (struct dadk *)com_data; 11251709Smlf 11261709Smlf if (GDA_BP_PKT(bp)) 11271709Smlf return (DDI_SUCCESS); 11281709Smlf 11291709Smlf pktp = dadk_pktprep(dadkp, NULL, bp, dadk_iodone, func, arg); 11301709Smlf if (!pktp) 11311709Smlf return (DDI_FAILURE); 11321709Smlf 11331709Smlf return (dadk_ioprep(dadkp, pktp)); 11341709Smlf } 11351709Smlf 11361709Smlf /* 11371709Smlf * Read, Write preparation 11381709Smlf */ 11391709Smlf static int 11401709Smlf dadk_ioprep(struct dadk *dadkp, struct cmpkt *pktp) 11411709Smlf { 11421709Smlf struct buf *bp; 11431709Smlf 11441709Smlf bp = pktp->cp_bp; 11451709Smlf if (bp->b_forw == (struct buf *)dadkp) 11461709Smlf *((char *)(pktp->cp_cdbp)) = (char)(intptr_t)bp->b_back; 11471709Smlf 11481709Smlf else if (bp->b_flags & B_READ) 11491709Smlf *((char *)(pktp->cp_cdbp)) = DCMD_READ; 11501709Smlf else 11511709Smlf *((char *)(pktp->cp_cdbp)) = DCMD_WRITE; 11521709Smlf pktp->cp_byteleft = bp->b_bcount; 11531709Smlf 11541709Smlf /* setup the bad block list handle */ 11551709Smlf pktp->cp_private = BBH_GETHANDLE(dadkp->dad_bbhobjp, bp); 11561709Smlf return (dadk_iosetup(dadkp, pktp)); 11571709Smlf } 11581709Smlf 11591709Smlf static int 11601709Smlf dadk_iosetup(struct dadk *dadkp, struct cmpkt *pktp) 11611709Smlf { 11621709Smlf struct buf *bp; 11631709Smlf bbh_cookie_t bbhckp; 11641709Smlf int seccnt; 11651709Smlf 11661709Smlf seccnt = pktp->cp_bytexfer >> dadkp->dad_secshf; 11671709Smlf pktp->cp_secleft -= seccnt; 11681709Smlf 11691709Smlf if (pktp->cp_secleft) { 11701709Smlf pktp->cp_srtsec += seccnt; 11711709Smlf } else { 11721709Smlf /* get the first cookie from the bad block list */ 11731709Smlf if (!pktp->cp_private) { 11741709Smlf bp = pktp->cp_bp; 11751709Smlf pktp->cp_srtsec = GET_BP_SEC(bp); 11761709Smlf pktp->cp_secleft = (bp->b_bcount >> dadkp->dad_secshf); 11771709Smlf } else { 11781709Smlf bbhckp = BBH_HTOC(dadkp->dad_bbhobjp, 11791709Smlf pktp->cp_private); 11801709Smlf pktp->cp_srtsec = BBH_GETCK_SECTOR(dadkp->dad_bbhobjp, 11811709Smlf bbhckp); 11821709Smlf pktp->cp_secleft = BBH_GETCK_SECLEN(dadkp->dad_bbhobjp, 11831709Smlf bbhckp); 11841709Smlf } 11851709Smlf } 11861709Smlf 11871709Smlf pktp->cp_bytexfer = pktp->cp_secleft << dadkp->dad_secshf; 11881709Smlf 11891709Smlf if (CTL_IOSETUP(dadkp->dad_ctlobjp, pktp)) { 11901709Smlf return (DDI_SUCCESS); 11911709Smlf } else { 11921709Smlf return (DDI_FAILURE); 11931709Smlf } 11941709Smlf 11951709Smlf 11961709Smlf 11971709Smlf 11981709Smlf } 11991709Smlf 12001709Smlf static struct cmpkt * 12011709Smlf dadk_pktprep(struct dadk *dadkp, struct cmpkt *in_pktp, struct buf *bp, 12021709Smlf void (*cb_func)(struct buf *), int (*func)(caddr_t), caddr_t arg) 12031709Smlf { 12041709Smlf struct cmpkt *pktp; 12051709Smlf 12061709Smlf pktp = gda_pktprep(dadkp->dad_ctlobjp, in_pktp, (opaque_t)bp, func, 12071709Smlf arg); 12081709Smlf 12091709Smlf if (pktp) { 12101709Smlf pktp->cp_callback = dadk_pktcb; 12111709Smlf pktp->cp_time = DADK_IO_TIME; 12121709Smlf pktp->cp_flags = 0; 12131709Smlf pktp->cp_iodone = cb_func; 12141709Smlf pktp->cp_dev_private = (opaque_t)dadkp; 12151709Smlf 12161709Smlf } 12171709Smlf 12181709Smlf return (pktp); 12191709Smlf } 12201709Smlf 12211709Smlf 12221709Smlf static void 12231709Smlf dadk_restart(void *vpktp) 12241709Smlf { 12251709Smlf struct cmpkt *pktp = (struct cmpkt *)vpktp; 12261709Smlf 12271709Smlf if (dadk_ioretry(pktp, QUE_COMMAND) == JUST_RETURN) 12281709Smlf return; 12291709Smlf pktp->cp_iodone(pktp->cp_bp); 12301709Smlf } 12311709Smlf 12321709Smlf static int 12331709Smlf dadk_ioretry(struct cmpkt *pktp, int action) 12341709Smlf { 12351709Smlf struct buf *bp; 12361709Smlf struct dadk *dadkp = PKT2DADK(pktp); 12371709Smlf 12381709Smlf switch (action) { 12391709Smlf case QUE_COMMAND: 12401709Smlf if (pktp->cp_retry++ < DADK_RETRY_COUNT) { 12411709Smlf CTL_IOSETUP(dadkp->dad_ctlobjp, pktp); 12421709Smlf if (CTL_TRANSPORT(dadkp->dad_ctlobjp, pktp) == 12431709Smlf CTL_SEND_SUCCESS) { 12441709Smlf return (JUST_RETURN); 12451709Smlf } 12461709Smlf gda_log(dadkp->dad_sd->sd_dev, dadk_name, 12471709Smlf CE_WARN, 12481709Smlf "transport of command fails\n"); 12491709Smlf } else 12501709Smlf gda_log(dadkp->dad_sd->sd_dev, 12511709Smlf dadk_name, CE_WARN, 12521709Smlf "exceeds maximum number of retries\n"); 12531709Smlf bioerror(pktp->cp_bp, ENXIO); 12541709Smlf /*FALLTHROUGH*/ 12551709Smlf case COMMAND_DONE_ERROR: 12561709Smlf bp = pktp->cp_bp; 12571709Smlf bp->b_resid += pktp->cp_byteleft - pktp->cp_bytexfer + 12581709Smlf pktp->cp_resid; 12591709Smlf if (geterror(bp) == 0) { 12601709Smlf if ((*((char *)(pktp->cp_cdbp)) == DCMD_FLUSH_CACHE) && 12611709Smlf (pktp->cp_dev_private == (opaque_t)dadkp) && 12621709Smlf ((int)(*(char *)pktp->cp_scbp) == DERR_ABORT)) { 12631709Smlf /* 12641709Smlf * Flag "unimplemented" responses for 12651709Smlf * DCMD_FLUSH_CACHE as ENOTSUP 12661709Smlf */ 12671709Smlf bioerror(bp, ENOTSUP); 12681709Smlf mutex_enter(&dadkp->dad_mutex); 12691709Smlf dadkp->dad_noflush = 1; 12701709Smlf mutex_exit(&dadkp->dad_mutex); 12711709Smlf } else { 12721709Smlf bioerror(bp, EIO); 12731709Smlf } 12741709Smlf } 12751709Smlf /*FALLTHROUGH*/ 12761709Smlf case COMMAND_DONE: 12771709Smlf default: 12781709Smlf return (COMMAND_DONE); 12791709Smlf } 12801709Smlf } 12811709Smlf 12821709Smlf 12831709Smlf static void 12841709Smlf dadk_pktcb(struct cmpkt *pktp) 12851709Smlf { 12861709Smlf int action; 12871709Smlf struct dadkio_rwcmd *rwcmdp; 12881709Smlf 12891709Smlf rwcmdp = (struct dadkio_rwcmd *)pktp->cp_passthru; /* ioctl packet */ 12901709Smlf 12911709Smlf if (pktp->cp_reason == CPS_SUCCESS) { 12921709Smlf if (rwcmdp && (rwcmdp != (opaque_t)DADK_SILENT)) 12931709Smlf rwcmdp->status.status = DADKIO_STAT_NO_ERROR; 12941709Smlf pktp->cp_iodone(pktp->cp_bp); 12951709Smlf return; 12961709Smlf } 12971709Smlf 12981709Smlf if (rwcmdp && (rwcmdp != (opaque_t)DADK_SILENT)) { 12991709Smlf if (pktp->cp_reason == CPS_CHKERR) 13001709Smlf dadk_recorderr(pktp, rwcmdp); 13011709Smlf dadk_iodone(pktp->cp_bp); 13021709Smlf return; 13031709Smlf } 13041709Smlf 13051709Smlf if (pktp->cp_reason == CPS_CHKERR) 13061709Smlf action = dadk_chkerr(pktp); 13071709Smlf else 13081709Smlf action = COMMAND_DONE_ERROR; 13091709Smlf 13101709Smlf if (action == JUST_RETURN) 13111709Smlf return; 13121709Smlf 13131709Smlf if (action != COMMAND_DONE) { 13141709Smlf if ((dadk_ioretry(pktp, action)) == JUST_RETURN) 13151709Smlf return; 13161709Smlf } 13171709Smlf pktp->cp_iodone(pktp->cp_bp); 13181709Smlf } 13191709Smlf 13201709Smlf 13211709Smlf 13221709Smlf static struct dadkio_derr dadk_errtab[] = { 13231709Smlf {COMMAND_DONE, GDA_INFORMATIONAL}, /* 0 DERR_SUCCESS */ 13241709Smlf {QUE_COMMAND, GDA_FATAL}, /* 1 DERR_AMNF */ 13251709Smlf {QUE_COMMAND, GDA_FATAL}, /* 2 DERR_TKONF */ 13261709Smlf {COMMAND_DONE_ERROR, GDA_INFORMATIONAL}, /* 3 DERR_ABORT */ 13271709Smlf {QUE_COMMAND, GDA_RETRYABLE}, /* 4 DERR_DWF */ 13281709Smlf {QUE_COMMAND, GDA_FATAL}, /* 5 DERR_IDNF */ 13291709Smlf {JUST_RETURN, GDA_INFORMATIONAL}, /* 6 DERR_BUSY */ 13301709Smlf {QUE_COMMAND, GDA_FATAL}, /* 7 DERR_UNC */ 13311709Smlf {QUE_COMMAND, GDA_RETRYABLE}, /* 8 DERR_BBK */ 13321709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 9 DERR_INVCDB */ 13331709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 10 DERR_HARD */ 13341709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 11 DERR_ILI */ 13351709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 12 DERR_EOM */ 13361709Smlf {COMMAND_DONE, GDA_INFORMATIONAL}, /* 13 DERR_MCR */ 13371709Smlf {COMMAND_DONE, GDA_INFORMATIONAL}, /* 14 DERR_RECOVER */ 13381709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 15 DERR_NOTREADY */ 13391709Smlf {QUE_COMMAND, GDA_RETRYABLE}, /* 16 DERR_MEDIUM */ 13401709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 17 DERR_HW */ 13411709Smlf {COMMAND_DONE, GDA_FATAL}, /* 18 DERR_ILL */ 13421709Smlf {COMMAND_DONE, GDA_FATAL}, /* 19 DERR_UNIT_ATTN */ 13431709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 20 DERR_DATA_PROT */ 13441709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 21 DERR_MISCOMPARE */ 13451709Smlf {QUE_COMMAND, GDA_RETRYABLE}, /* 22 DERR_ICRC */ 13461709Smlf {COMMAND_DONE_ERROR, GDA_FATAL}, /* 23 DERR_RESV */ 13471709Smlf }; 13481709Smlf 13491709Smlf static int 13501709Smlf dadk_chkerr(struct cmpkt *pktp) 13511709Smlf { 13521709Smlf int err_blkno; 13532799Smarx struct dadk *dadkp = PKT2DADK(pktp); 13542799Smarx dadk_errstats_t *dep; 13552799Smarx int scb = *(char *)pktp->cp_scbp; 13561709Smlf 13572799Smarx if (scb == DERR_SUCCESS) { 13582799Smarx if (pktp->cp_retry != 0 && dadkp->dad_errstats != NULL) { 13592799Smarx dep = (dadk_errstats_t *) 13602799Smarx dadkp->dad_errstats->ks_data; 13612799Smarx dep->dadk_rq_recov_err.value.ui32++; 13622799Smarx } 13631709Smlf return (COMMAND_DONE); 13642799Smarx } 13651709Smlf 13661709Smlf if (pktp->cp_retry) { 13671709Smlf err_blkno = pktp->cp_srtsec + ((pktp->cp_bytexfer - 13681709Smlf pktp->cp_resid) >> dadkp->dad_secshf); 13691709Smlf } else 13701709Smlf err_blkno = -1; 13711709Smlf 13722799Smarx if (dadkp->dad_errstats != NULL) { 13732799Smarx dep = (dadk_errstats_t *)dadkp->dad_errstats->ks_data; 13742799Smarx 1375*3399Smarx switch (dadk_errtab[scb].d_severity) { 1376*3399Smarx case GDA_RETRYABLE: 1377*3399Smarx dep->dadk_softerrs.value.ui32++; 1378*3399Smarx break; 1379*3399Smarx 1380*3399Smarx case GDA_FATAL: 1381*3399Smarx dep->dadk_harderrs.value.ui32++; 1382*3399Smarx break; 1383*3399Smarx 1384*3399Smarx default: 1385*3399Smarx break; 1386*3399Smarx } 13872799Smarx 13882799Smarx switch (scb) { 13892799Smarx case DERR_INVCDB: 13902799Smarx case DERR_ILI: 13912799Smarx case DERR_EOM: 13922799Smarx case DERR_HW: 13932799Smarx case DERR_ICRC: 13942799Smarx dep->dadk_transerrs.value.ui32++; 13952799Smarx break; 13962799Smarx 13972799Smarx case DERR_AMNF: 13982799Smarx case DERR_TKONF: 13992799Smarx case DERR_DWF: 14002799Smarx case DERR_BBK: 14012799Smarx case DERR_UNC: 14022799Smarx case DERR_HARD: 14032799Smarx case DERR_MEDIUM: 14042799Smarx case DERR_DATA_PROT: 14052799Smarx case DERR_MISCOMP: 14062799Smarx dep->dadk_rq_media_err.value.ui32++; 14072799Smarx break; 14082799Smarx 14092799Smarx case DERR_NOTREADY: 14102799Smarx dep->dadk_rq_ntrdy_err.value.ui32++; 14112799Smarx break; 14122799Smarx 14132799Smarx case DERR_IDNF: 14142799Smarx case DERR_UNIT_ATTN: 14152799Smarx dep->dadk_rq_nodev_err.value.ui32++; 14162799Smarx break; 14172799Smarx 14182799Smarx case DERR_ILL: 14192799Smarx case DERR_RESV: 14202799Smarx dep->dadk_rq_illrq_err.value.ui32++; 14212799Smarx break; 14222799Smarx 14232799Smarx default: 14242799Smarx break; 14252799Smarx } 14262799Smarx } 14272799Smarx 14281709Smlf /* if attempting to read a sector from a cdrom audio disk */ 14291709Smlf if ((dadkp->dad_cdrom) && 14301709Smlf (*((char *)(pktp->cp_cdbp)) == DCMD_READ) && 14311709Smlf (scb == DERR_ILL)) { 14321709Smlf return (COMMAND_DONE); 14331709Smlf } 14341709Smlf if (pktp->cp_passthru == NULL) { 14351709Smlf gda_errmsg(dadkp->dad_sd, pktp, dadk_name, 14361709Smlf dadk_errtab[scb].d_severity, pktp->cp_srtsec, 14371709Smlf err_blkno, dadk_cmds, dadk_sense); 14381709Smlf } 14391709Smlf 14401709Smlf if (scb == DERR_BUSY) { 14411709Smlf (void) timeout(dadk_restart, (void *)pktp, DADK_BSY_TIMEOUT); 14421709Smlf } 14431709Smlf 1444*3399Smarx return (dadk_errtab[scb].d_action); 14451709Smlf } 14461709Smlf 14471709Smlf static void 14481709Smlf dadk_recorderr(struct cmpkt *pktp, struct dadkio_rwcmd *rwcmdp) 14491709Smlf { 14501709Smlf struct dadk *dadkp; 14511709Smlf int scb; 14521709Smlf 14531709Smlf dadkp = PKT2DADK(pktp); 14541709Smlf scb = (int)(*(char *)pktp->cp_scbp); 14551709Smlf 14561709Smlf 14571709Smlf rwcmdp->status.failed_blk = rwcmdp->blkaddr + 14581709Smlf ((pktp->cp_bytexfer - 14591709Smlf pktp->cp_resid) >> dadkp->dad_secshf); 14601709Smlf 14611709Smlf rwcmdp->status.resid = pktp->cp_bp->b_resid + 14621709Smlf pktp->cp_byteleft - pktp->cp_bytexfer + pktp->cp_resid; 14631709Smlf switch ((int)(* (char *)pktp->cp_scbp)) { 14641709Smlf case DERR_AMNF: 14651709Smlf case DERR_ABORT: 14661709Smlf rwcmdp->status.status = DADKIO_STAT_ILLEGAL_REQUEST; 14671709Smlf break; 14681709Smlf case DERR_DWF: 14691709Smlf case DERR_IDNF: 14701709Smlf rwcmdp->status.status = DADKIO_STAT_ILLEGAL_ADDRESS; 14711709Smlf break; 14721709Smlf case DERR_TKONF: 14731709Smlf case DERR_UNC: 14741709Smlf case DERR_BBK: 14751709Smlf rwcmdp->status.status = DADKIO_STAT_MEDIUM_ERROR; 14761709Smlf rwcmdp->status.failed_blk_is_valid = 1; 14771709Smlf rwcmdp->status.resid = 0; 14781709Smlf break; 14791709Smlf case DERR_BUSY: 14801709Smlf rwcmdp->status.status = DADKIO_STAT_NOT_READY; 14811709Smlf break; 14821709Smlf case DERR_INVCDB: 14831709Smlf case DERR_HARD: 14841709Smlf rwcmdp->status.status = DADKIO_STAT_HARDWARE_ERROR; 14851709Smlf break; 14861709Smlf case DERR_ICRC: 14871709Smlf default: 14881709Smlf rwcmdp->status.status = DADKIO_STAT_NOT_SUPPORTED; 14891709Smlf } 14901709Smlf 14911709Smlf if (rwcmdp->flags & DADKIO_FLAG_SILENT) 14921709Smlf return; 14931709Smlf gda_errmsg(dadkp->dad_sd, pktp, dadk_name, dadk_errtab[scb].d_severity, 14941709Smlf rwcmdp->blkaddr, rwcmdp->status.failed_blk, 14951709Smlf dadk_cmds, dadk_sense); 14961709Smlf } 14971709Smlf 14981709Smlf /*ARGSUSED*/ 14991709Smlf static void 15001709Smlf dadk_polldone(struct buf *bp) 15011709Smlf { 15021709Smlf } 15031709Smlf 15041709Smlf static void 15051709Smlf dadk_iodone(struct buf *bp) 15061709Smlf { 15071709Smlf struct cmpkt *pktp; 15081709Smlf struct dadk *dadkp; 15091709Smlf 15101709Smlf pktp = GDA_BP_PKT(bp); 15111709Smlf dadkp = PKT2DADK(pktp); 15121709Smlf 15131709Smlf /* check for all iodone */ 15141709Smlf pktp->cp_byteleft -= pktp->cp_bytexfer; 15151709Smlf if (geterror(bp) == 0 && pktp->cp_byteleft != 0) { 15161709Smlf pktp->cp_retry = 0; 15171709Smlf (void) dadk_iosetup(dadkp, pktp); 15181709Smlf 15191709Smlf 15201709Smlf /* transport the next one */ 15211709Smlf if (CTL_TRANSPORT(dadkp->dad_ctlobjp, pktp) == CTL_SEND_SUCCESS) 15221709Smlf return; 15231709Smlf if ((dadk_ioretry(pktp, QUE_COMMAND)) == JUST_RETURN) 15241709Smlf return; 15251709Smlf } 15261709Smlf 15271709Smlf /* start next one */ 15281709Smlf FLC_DEQUE(dadkp->dad_flcobjp, bp); 15291709Smlf 15301709Smlf /* free pkt */ 15311709Smlf if (pktp->cp_private) 15321709Smlf BBH_FREEHANDLE(dadkp->dad_bbhobjp, pktp->cp_private); 15331709Smlf gda_free(dadkp->dad_ctlobjp, pktp, NULL); 15341709Smlf biodone(bp); 15351709Smlf } 15361709Smlf 15371709Smlf int 15381709Smlf dadk_check_media(opaque_t objp, int *state) 15391709Smlf { 15401709Smlf struct dadk *dadkp = (struct dadk *)objp; 15411709Smlf 15421709Smlf if (!dadkp->dad_rmb) { 15431709Smlf return (ENXIO); 15441709Smlf } 15451709Smlf #ifdef DADK_DEBUG 15461709Smlf if (dadk_debug & DSTATE) 15471709Smlf PRF("dadk_check_media: user state %x disk state %x\n", 15481709Smlf *state, dadkp->dad_iostate); 15491709Smlf #endif 15501709Smlf /* 15511709Smlf * If state already changed just return 15521709Smlf */ 15531709Smlf if (*state != dadkp->dad_iostate) { 15541709Smlf *state = dadkp->dad_iostate; 15551709Smlf return (0); 15561709Smlf } 15571709Smlf 15581709Smlf /* 15591709Smlf * Startup polling on thread state 15601709Smlf */ 15611709Smlf mutex_enter(&dadkp->dad_mutex); 15621709Smlf if (dadkp->dad_thread_cnt == 0) { 15631709Smlf /* 15641709Smlf * One thread per removable dadk device 15651709Smlf */ 15661709Smlf (void) thread_create(NULL, 0, dadk_watch_thread, dadkp, 0, &p0, 15671709Smlf TS_RUN, v.v_maxsyspri - 2); 15681709Smlf } 15691709Smlf dadkp->dad_thread_cnt++; 15701709Smlf 15711709Smlf /* 15721709Smlf * Wait for state to change 15731709Smlf */ 15741709Smlf do { 15751709Smlf if (cv_wait_sig(&dadkp->dad_state_cv, &dadkp->dad_mutex) == 0) { 15761709Smlf dadkp->dad_thread_cnt--; 15771709Smlf mutex_exit(&dadkp->dad_mutex); 15781709Smlf return (EINTR); 15791709Smlf } 15801709Smlf } while (*state == dadkp->dad_iostate); 15811709Smlf *state = dadkp->dad_iostate; 15821709Smlf dadkp->dad_thread_cnt--; 15831709Smlf mutex_exit(&dadkp->dad_mutex); 15841709Smlf return (0); 15851709Smlf } 15861709Smlf 15871709Smlf 15881709Smlf #define MEDIA_ACCESS_DELAY 2000000 15891709Smlf 15901709Smlf static void 15911709Smlf dadk_watch_thread(struct dadk *dadkp) 15921709Smlf { 15931709Smlf enum dkio_state state; 15941709Smlf int interval; 15951709Smlf 15961709Smlf interval = drv_usectohz(dadk_check_media_time); 15971709Smlf 15981709Smlf do { 15991709Smlf if (dadk_rmb_ioctl(dadkp, DCMD_GET_STATE, (intptr_t)&state, 0, 16001709Smlf DADK_SILENT)) { 16011709Smlf /* 16021709Smlf * Assume state remained the same 16031709Smlf */ 16041709Smlf state = dadkp->dad_iostate; 16051709Smlf } 16061709Smlf 16071709Smlf /* 16081709Smlf * now signal the waiting thread if this is *not* the 16091709Smlf * specified state; 16101709Smlf * delay the signal if the state is DKIO_INSERTED 16111709Smlf * to allow the target to recover 16121709Smlf */ 16131709Smlf if (state != dadkp->dad_iostate) { 16141709Smlf 16151709Smlf dadkp->dad_iostate = state; 16161709Smlf if (state == DKIO_INSERTED) { 16171709Smlf /* 16181709Smlf * delay the signal to give the drive a chance 16191709Smlf * to do what it apparently needs to do 16201709Smlf */ 16211709Smlf (void) timeout((void(*)(void *))cv_broadcast, 16221709Smlf (void *)&dadkp->dad_state_cv, 16231709Smlf drv_usectohz((clock_t)MEDIA_ACCESS_DELAY)); 16241709Smlf } else { 16251709Smlf cv_broadcast(&dadkp->dad_state_cv); 16261709Smlf } 16271709Smlf } 16281709Smlf delay(interval); 16291709Smlf } while (dadkp->dad_thread_cnt); 16301709Smlf } 16311709Smlf 16321709Smlf int 16331709Smlf dadk_inquiry(opaque_t objp, opaque_t *inqpp) 16341709Smlf { 16351709Smlf struct dadk *dadkp = (struct dadk *)objp; 16361709Smlf struct scsi_inquiry **sinqpp = (struct scsi_inquiry **)inqpp; 16371709Smlf 16381709Smlf if (dadkp && dadkp->dad_sd && dadkp->dad_sd->sd_inq) { 16391709Smlf *sinqpp = dadkp->dad_sd->sd_inq; 16401709Smlf return (DDI_SUCCESS); 16411709Smlf } 16421709Smlf 16431709Smlf return (DDI_FAILURE); 16441709Smlf } 16451709Smlf 16461709Smlf static int 16471709Smlf dadk_rmb_ioctl(struct dadk *dadkp, int cmd, intptr_t arg, int flags, int silent) 16481709Smlf 16491709Smlf { 16501709Smlf struct buf *bp; 16511709Smlf int err; 16521709Smlf struct cmpkt *pktp; 16531709Smlf 16541709Smlf if ((bp = getrbuf(KM_SLEEP)) == NULL) { 16551709Smlf return (ENOMEM); 16561709Smlf } 16571709Smlf pktp = dadk_pktprep(dadkp, NULL, bp, dadk_rmb_iodone, NULL, NULL); 16581709Smlf if (!pktp) { 16591709Smlf freerbuf(bp); 16601709Smlf return (ENOMEM); 16611709Smlf } 16621709Smlf bp->b_back = (struct buf *)arg; 16631709Smlf bp->b_forw = (struct buf *)dadkp->dad_flcobjp; 16641709Smlf pktp->cp_passthru = (opaque_t)(intptr_t)silent; 16651709Smlf 16661709Smlf err = CTL_IOCTL(dadkp->dad_ctlobjp, cmd, (uintptr_t)pktp, flags); 16671709Smlf freerbuf(bp); 16681709Smlf gda_free(dadkp->dad_ctlobjp, pktp, NULL); 16691709Smlf return (err); 16701709Smlf 16711709Smlf 16721709Smlf } 16731709Smlf 16741709Smlf static void 16751709Smlf dadk_rmb_iodone(struct buf *bp) 16761709Smlf { 16771709Smlf struct cmpkt *pktp; 16781709Smlf struct dadk *dadkp; 16791709Smlf 16801709Smlf pktp = GDA_BP_PKT(bp); 16811709Smlf dadkp = PKT2DADK(pktp); 16821709Smlf 16831709Smlf bp->b_flags &= ~(B_DONE|B_BUSY); 16841709Smlf 16851709Smlf /* Start next one */ 16861709Smlf FLC_DEQUE(dadkp->dad_flcobjp, bp); 16871709Smlf 16881709Smlf biodone(bp); 16891709Smlf } 16901709Smlf 16911709Smlf static int 16921709Smlf dadk_dk_buf_setup(struct dadk *dadkp, opaque_t *cmdp, dev_t dev, 16931709Smlf enum uio_seg dataspace, int rw) 16941709Smlf { 16951709Smlf struct dadkio_rwcmd *rwcmdp = (struct dadkio_rwcmd *)cmdp; 16961709Smlf struct buf *bp; 16971709Smlf struct iovec aiov; 16981709Smlf struct uio auio; 16991709Smlf struct uio *uio = &auio; 17001709Smlf int status; 17011709Smlf 17021709Smlf bp = getrbuf(KM_SLEEP); 17031709Smlf 17041709Smlf bp->av_forw = bp->b_forw = (struct buf *)dadkp; 17051709Smlf bp->b_back = (struct buf *)rwcmdp; /* ioctl packet */ 17061709Smlf 17071709Smlf bzero((caddr_t)&auio, sizeof (struct uio)); 17081709Smlf bzero((caddr_t)&aiov, sizeof (struct iovec)); 17091709Smlf aiov.iov_base = rwcmdp->bufaddr; 17101709Smlf aiov.iov_len = rwcmdp->buflen; 17111709Smlf uio->uio_iov = &aiov; 17121709Smlf 17131709Smlf uio->uio_iovcnt = 1; 17141709Smlf uio->uio_resid = rwcmdp->buflen; 17151709Smlf uio->uio_segflg = dataspace; 17161709Smlf 17171709Smlf /* Let physio do the rest... */ 17181709Smlf status = physio(dadk_dk_strategy, bp, dev, rw, dadkmin, uio); 17191709Smlf 17201709Smlf freerbuf(bp); 17211709Smlf return (status); 17221709Smlf 17231709Smlf } 17241709Smlf 17251709Smlf /* Do not let a user gendisk request get too big or */ 17261709Smlf /* else we could use to many resources. */ 17271709Smlf 17281709Smlf static void 17291709Smlf dadkmin(struct buf *bp) 17301709Smlf { 17311709Smlf if (bp->b_bcount > dadk_dk_maxphys) 17321709Smlf bp->b_bcount = dadk_dk_maxphys; 17331709Smlf } 17341709Smlf 17351709Smlf static int 17361709Smlf dadk_dk_strategy(struct buf *bp) 17371709Smlf { 17381709Smlf dadk_dk((struct dadk *)bp->av_forw, (struct dadkio_rwcmd *)bp->b_back, 17391709Smlf bp); 17401709Smlf return (0); 17411709Smlf } 17421709Smlf 17431709Smlf static void 17441709Smlf dadk_dk(struct dadk *dadkp, struct dadkio_rwcmd *rwcmdp, struct buf *bp) 17451709Smlf { 17461709Smlf struct cmpkt *pktp; 17471709Smlf 17481709Smlf pktp = dadk_pktprep(dadkp, NULL, bp, dadk_iodone, NULL, NULL); 17491709Smlf if (!pktp) { 17501709Smlf bioerror(bp, ENOMEM); 17511709Smlf biodone(bp); 17521709Smlf return; 17531709Smlf } 17541709Smlf 17551709Smlf pktp->cp_passthru = rwcmdp; 17561709Smlf 17571709Smlf (void) dadk_ioprep(dadkp, pktp); 17581709Smlf 17591709Smlf FLC_ENQUE(dadkp->dad_flcobjp, bp); 17601709Smlf } 1761