13786Sarutz /* 23786Sarutz * CDDL HEADER START 33786Sarutz * 43786Sarutz * The contents of this file are subject to the terms of the 53786Sarutz * Common Development and Distribution License (the "License"). 63786Sarutz * You may not use this file except in compliance with the License. 73786Sarutz * 83786Sarutz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93786Sarutz * or http://www.opensolaris.org/os/licensing. 103786Sarutz * See the License for the specific language governing permissions 113786Sarutz * and limitations under the License. 123786Sarutz * 133786Sarutz * When distributing Covered Code, include this CDDL HEADER in each 143786Sarutz * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153786Sarutz * If applicable, add the following below this CDDL HEADER, with the 163786Sarutz * fields enclosed by brackets "[]" replaced with your own identifying 173786Sarutz * information: Portions Copyright [yyyy] [name of copyright owner] 183786Sarutz * 193786Sarutz * CDDL HEADER END 203786Sarutz */ 213786Sarutz 223786Sarutz /* 237224Scth * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 243786Sarutz * Use is subject to license terms. 253786Sarutz */ 263786Sarutz 273786Sarutz 283786Sarutz /* 293786Sarutz * Direct Attached disk driver for SPARC machines. 303786Sarutz */ 313786Sarutz 323786Sarutz /* 333786Sarutz * Includes, Declarations and Local Data 343786Sarutz */ 353786Sarutz #include <sys/dada/dada.h> 363786Sarutz #include <sys/dkbad.h> 373786Sarutz #include <sys/dklabel.h> 383786Sarutz #include <sys/dkio.h> 393786Sarutz #include <sys/cdio.h> 403786Sarutz #include <sys/vtoc.h> 413786Sarutz #include <sys/dada/targets/daddef.h> 423786Sarutz #include <sys/dada/targets/dadpriv.h> 433786Sarutz #include <sys/file.h> 443786Sarutz #include <sys/stat.h> 453786Sarutz #include <sys/kstat.h> 463786Sarutz #include <sys/vtrace.h> 473786Sarutz #include <sys/aio_req.h> 483786Sarutz #include <sys/note.h> 493786Sarutz #include <sys/cmlb.h> 503786Sarutz 513786Sarutz /* 523786Sarutz * Global Error Levels for Error Reporting 533786Sarutz */ 543786Sarutz int dcd_error_level = DCD_ERR_RETRYABLE; 553786Sarutz /* 563786Sarutz * Local Static Data 573786Sarutz */ 583786Sarutz 593786Sarutz static int dcd_io_time = DCD_IO_TIME; 603786Sarutz static int dcd_retry_count = DCD_RETRY_COUNT; 613786Sarutz #ifndef lint 623786Sarutz static int dcd_report_pfa = 1; 633786Sarutz #endif 643786Sarutz static int dcd_rot_delay = 4; 653786Sarutz static int dcd_poll_busycnt = DCD_POLL_TIMEOUT; 663786Sarutz 673786Sarutz /* 683786Sarutz * Local Function Prototypes 693786Sarutz */ 703786Sarutz 713786Sarutz static int dcdopen(dev_t *dev_p, int flag, int otyp, cred_t *cred_p); 723786Sarutz static int dcdclose(dev_t dev, int flag, int otyp, cred_t *cred_p); 733786Sarutz static int dcdstrategy(struct buf *bp); 743786Sarutz static int dcddump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk); 753786Sarutz static int dcdioctl(dev_t, int, intptr_t, int, cred_t *, int *); 763786Sarutz static int dcdread(dev_t dev, struct uio *uio, cred_t *cred_p); 773786Sarutz static int dcdwrite(dev_t dev, struct uio *uio, cred_t *cred_p); 783786Sarutz static int dcd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, 793786Sarutz char *, caddr_t, int *); 803786Sarutz static int dcdaread(dev_t dev, struct aio_req *aio, cred_t *cred_p); 813786Sarutz static int dcdawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p); 823786Sarutz 833786Sarutz 843786Sarutz static void dcd_free_softstate(struct dcd_disk *un, dev_info_t *devi); 853786Sarutz static int dcd_doattach(dev_info_t *devi, int (*f)()); 863786Sarutz static int dcd_validate_geometry(struct dcd_disk *un); 873786Sarutz static ddi_devid_t dcd_get_devid(struct dcd_disk *un); 883786Sarutz static ddi_devid_t dcd_create_devid(struct dcd_disk *un); 893786Sarutz static int dcd_make_devid_from_serial(struct dcd_disk *un); 903786Sarutz static void dcd_validate_model_serial(char *str, int *retlen, int totallen); 913786Sarutz static int dcd_read_deviceid(struct dcd_disk *un); 923786Sarutz static int dcd_write_deviceid(struct dcd_disk *un); 933786Sarutz static int dcd_poll(struct dcd_pkt *pkt); 943786Sarutz static char *dcd_rname(int reason); 953786Sarutz static void dcd_flush_cache(struct dcd_disk *un); 963786Sarutz 973786Sarutz static int dcd_compute_dk_capacity(struct dcd_device *devp, 983786Sarutz diskaddr_t *capacity); 993786Sarutz static int dcd_send_lb_rw_cmd(dev_info_t *devinfo, void *bufaddr, 1003786Sarutz diskaddr_t start_block, size_t reqlength, uchar_t cmd); 1013786Sarutz 1023786Sarutz static void dcdmin(struct buf *bp); 1033786Sarutz 1043786Sarutz static int dcdioctl_cmd(dev_t, struct udcd_cmd *, 1053786Sarutz enum uio_seg, enum uio_seg); 1063786Sarutz 1073786Sarutz static void dcdstart(struct dcd_disk *un); 1083786Sarutz static void dcddone_and_mutex_exit(struct dcd_disk *un, struct buf *bp); 1093786Sarutz static void make_dcd_cmd(struct dcd_disk *un, struct buf *bp, int (*f)()); 1103786Sarutz static void dcdudcdmin(struct buf *bp); 1113786Sarutz 1123786Sarutz static int dcdrunout(caddr_t); 1133786Sarutz static int dcd_check_wp(dev_t dev); 1143786Sarutz static int dcd_unit_ready(dev_t dev); 1153786Sarutz static void dcd_handle_tran_busy(struct buf *bp, struct diskhd *dp, 1163786Sarutz struct dcd_disk *un); 1173786Sarutz static void dcdintr(struct dcd_pkt *pkt); 1183786Sarutz static int dcd_handle_incomplete(struct dcd_disk *un, struct buf *bp); 1193786Sarutz static void dcd_offline(struct dcd_disk *un, int bechatty); 1203786Sarutz static int dcd_ready_and_valid(dev_t dev, struct dcd_disk *un); 1213786Sarutz static void dcd_reset_disk(struct dcd_disk *un, struct dcd_pkt *pkt); 1223786Sarutz static void dcd_translate(struct dadkio_status32 *statp, struct udcd_cmd *cmdp); 1233786Sarutz static int dcdflushdone(struct buf *bp); 1243786Sarutz 1253786Sarutz /* Function prototypes for cmlb */ 1263786Sarutz 1273786Sarutz static int dcd_lb_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr, 1283786Sarutz diskaddr_t start_block, size_t reqlength, void *tg_cookie); 1293786Sarutz 1303786Sarutz static int dcd_lb_getphygeom(dev_info_t *devi, cmlb_geom_t *phygeomp); 1313786Sarutz static int dcd_lb_getinfo(dev_info_t *devi, int cmd, void *arg, 1323786Sarutz void *tg_cookie); 1333786Sarutz 1343786Sarutz 1353786Sarutz static cmlb_tg_ops_t dcd_lb_ops = { 1363786Sarutz TG_DK_OPS_VERSION_1, 1373786Sarutz dcd_lb_rdwr, 1383786Sarutz dcd_lb_getinfo 1393786Sarutz }; 1403786Sarutz 1413786Sarutz /* 1423786Sarutz * Error and Logging Functions 1433786Sarutz */ 1443786Sarutz #ifndef lint 1453786Sarutz static void clean_print(dev_info_t *dev, char *label, uint_t level, 1463786Sarutz char *title, char *data, int len); 1473786Sarutz static void dcdrestart(void *arg); 1483786Sarutz #endif /* lint */ 1493786Sarutz 1503786Sarutz static int dcd_check_error(struct dcd_disk *un, struct buf *bp); 1513786Sarutz 1523786Sarutz /* 1533786Sarutz * Error statistics create/update functions 1543786Sarutz */ 1553786Sarutz static int dcd_create_errstats(struct dcd_disk *, int); 1563786Sarutz 1573786Sarutz 1583786Sarutz 1593786Sarutz /*PRINTFLIKE4*/ 1603786Sarutz extern void dcd_log(dev_info_t *, char *, uint_t, const char *, ...) 1613786Sarutz __KPRINTFLIKE(4); 1623786Sarutz extern void makecommand(struct dcd_pkt *, int, uchar_t, uint32_t, 1633786Sarutz uchar_t, uint32_t, uchar_t, uchar_t); 1643786Sarutz 1653786Sarutz 1663786Sarutz /* 1673786Sarutz * Configuration Routines 1683786Sarutz */ 1693786Sarutz static int dcdinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 1703786Sarutz void **result); 1713786Sarutz static int dcdprobe(dev_info_t *devi); 1723786Sarutz static int dcdattach(dev_info_t *devi, ddi_attach_cmd_t cmd); 1733786Sarutz static int dcddetach(dev_info_t *devi, ddi_detach_cmd_t cmd); 1743786Sarutz static int dcdreset(dev_info_t *dip, ddi_reset_cmd_t cmd); 1753786Sarutz static int dcd_dr_detach(dev_info_t *devi); 1763786Sarutz static int dcdpower(dev_info_t *devi, int component, int level); 1773786Sarutz 1783786Sarutz static void *dcd_state; 1793786Sarutz static int dcd_max_instance; 1803786Sarutz static char *dcd_label = "dad"; 1813786Sarutz 1823786Sarutz static char *diskokay = "disk okay\n"; 1833786Sarutz 1843786Sarutz #if DEBUG || lint 1853786Sarutz #define DCDDEBUG 1863786Sarutz #endif 1873786Sarutz 1883786Sarutz int dcd_test_flag = 0; 1893786Sarutz /* 1903786Sarutz * Debugging macros 1913786Sarutz */ 1923786Sarutz #ifdef DCDDEBUG 1933786Sarutz static int dcddebug = 0; 1943786Sarutz #define DEBUGGING (dcddebug > 1) 1953786Sarutz #define DAD_DEBUG if (dcddebug == 1) dcd_log 1963786Sarutz #define DAD_DEBUG2 if (dcddebug > 1) dcd_log 1973786Sarutz #else /* DCDDEBUG */ 1983786Sarutz #define dcddebug (0) 1993786Sarutz #define DEBUGGING (0) 2003786Sarutz #define DAD_DEBUG if (0) dcd_log 2013786Sarutz #define DAD_DEBUG2 if (0) dcd_log 2023786Sarutz #endif 2033786Sarutz 2043786Sarutz /* 2053786Sarutz * we use pkt_private area for storing bp and retry_count 2063786Sarutz * XXX: Really is this usefull. 2073786Sarutz */ 2083786Sarutz struct dcd_pkt_private { 2093786Sarutz struct buf *dcdpp_bp; 2103786Sarutz short dcdpp_retry_count; 2113786Sarutz short dcdpp_victim_retry_count; 2123786Sarutz }; 2133786Sarutz 2143786Sarutz 2153786Sarutz _NOTE(SCHEME_PROTECTS_DATA("Unique per pkt", dcd_pkt_private buf)) 2163786Sarutz 2173786Sarutz #define PP_LEN (sizeof (struct dcd_pkt_private)) 2183786Sarutz 2193786Sarutz #define PKT_SET_BP(pkt, bp) \ 2203786Sarutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_bp = bp 2213786Sarutz #define PKT_GET_BP(pkt) \ 2223786Sarutz (((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_bp) 2233786Sarutz 2243786Sarutz 2253786Sarutz #define PKT_SET_RETRY_CNT(pkt, n) \ 2263786Sarutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_retry_count = n 2273786Sarutz 2283786Sarutz #define PKT_GET_RETRY_CNT(pkt) \ 2293786Sarutz (((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_retry_count) 2303786Sarutz 2313786Sarutz #define PKT_INCR_RETRY_CNT(pkt, n) \ 2323786Sarutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_retry_count += n 2333786Sarutz 2343786Sarutz #define PKT_SET_VICTIM_RETRY_CNT(pkt, n) \ 2353786Sarutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_victim_retry_count \ 2363786Sarutz = n 2373786Sarutz 2383786Sarutz #define PKT_GET_VICTIM_RETRY_CNT(pkt) \ 2393786Sarutz (((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_victim_retry_count) 2403786Sarutz #define PKT_INCR_VICTIM_RETRY_CNT(pkt, n) \ 2413786Sarutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_victim_retry_count \ 2423786Sarutz += n 2433786Sarutz 2443786Sarutz #define DISK_NOT_READY_RETRY_COUNT (dcd_retry_count / 2) 2453786Sarutz 2463786Sarutz 2473786Sarutz /* 2483786Sarutz * Urk! 2493786Sarutz */ 2503786Sarutz #define SET_BP_ERROR(bp, err) \ 2513786Sarutz bioerror(bp, err); 2523786Sarutz 2533786Sarutz #define IOSP KSTAT_IO_PTR(un->un_stats) 2543786Sarutz #define IO_PARTITION_STATS un->un_pstats[DCDPART(bp->b_edev)] 2553786Sarutz #define IOSP_PARTITION KSTAT_IO_PTR(IO_PARTITION_STATS) 2563786Sarutz 2573786Sarutz #define DCD_DO_KSTATS(un, kstat_function, bp) \ 2583786Sarutz ASSERT(mutex_owned(DCD_MUTEX)); \ 2593786Sarutz if (bp != un->un_sbufp) { \ 2603786Sarutz if (un->un_stats) { \ 2613786Sarutz kstat_function(IOSP); \ 2623786Sarutz } \ 2633786Sarutz if (IO_PARTITION_STATS) { \ 2643786Sarutz kstat_function(IOSP_PARTITION); \ 2653786Sarutz } \ 2663786Sarutz } 2673786Sarutz 2683786Sarutz #define DCD_DO_ERRSTATS(un, x) \ 2693786Sarutz if (un->un_errstats) { \ 2703786Sarutz struct dcd_errstats *dtp; \ 2713786Sarutz dtp = (struct dcd_errstats *)un->un_errstats->ks_data; \ 2723786Sarutz dtp->x.value.ui32++; \ 2733786Sarutz } 2743786Sarutz 2753786Sarutz #define GET_SOFT_STATE(dev) \ 2763786Sarutz struct dcd_disk *un; \ 2773786Sarutz int instance, part; \ 2783786Sarutz minor_t minor = getminor(dev); \ 2793786Sarutz \ 2803786Sarutz part = minor & DCDPART_MASK; \ 2813786Sarutz instance = minor >> DCDUNIT_SHIFT; \ 2823786Sarutz if ((un = ddi_get_soft_state(dcd_state, instance)) == NULL) \ 2833786Sarutz return (ENXIO); 2843786Sarutz 2853786Sarutz #define LOGICAL_BLOCK_ALIGN(blkno, blknoshift) \ 2863786Sarutz (((blkno) & ((1 << (blknoshift)) - 1)) == 0) 2873786Sarutz 2883786Sarutz /* 2893786Sarutz * After the following number of sectors, the cylinder number spills over 2903786Sarutz * 0xFFFF if sectors = 63 and heads = 16. 2913786Sarutz */ 2923786Sarutz #define NUM_SECTORS_32G 0x3EFFC10 2933786Sarutz 2943786Sarutz /* 2953786Sarutz * Configuration Data 2963786Sarutz */ 2973786Sarutz 2983786Sarutz /* 2993786Sarutz * Device driver ops vector 3003786Sarutz */ 3013786Sarutz 3023786Sarutz static struct cb_ops dcd_cb_ops = { 3033786Sarutz dcdopen, /* open */ 3043786Sarutz dcdclose, /* close */ 3053786Sarutz dcdstrategy, /* strategy */ 3063786Sarutz nodev, /* print */ 3073786Sarutz dcddump, /* dump */ 3083786Sarutz dcdread, /* read */ 3093786Sarutz dcdwrite, /* write */ 3103786Sarutz dcdioctl, /* ioctl */ 3113786Sarutz nodev, /* devmap */ 3123786Sarutz nodev, /* mmap */ 3133786Sarutz nodev, /* segmap */ 3143786Sarutz nochpoll, /* poll */ 3153786Sarutz dcd_prop_op, /* cb_prop_op */ 3163786Sarutz 0, /* streamtab */ 3173786Sarutz D_64BIT | D_MP | D_NEW, /* Driver compatibility flag */ 3183786Sarutz CB_REV, /* cb_rev */ 3193786Sarutz dcdaread, /* async I/O read entry point */ 3203786Sarutz dcdawrite /* async I/O write entry point */ 3213786Sarutz }; 3223786Sarutz 3233786Sarutz static struct dev_ops dcd_ops = { 3243786Sarutz DEVO_REV, /* devo_rev, */ 3253786Sarutz 0, /* refcnt */ 3263786Sarutz dcdinfo, /* info */ 3273786Sarutz nulldev, /* identify */ 3283786Sarutz dcdprobe, /* probe */ 3293786Sarutz dcdattach, /* attach */ 3303786Sarutz dcddetach, /* detach */ 3313786Sarutz dcdreset, /* reset */ 3323786Sarutz &dcd_cb_ops, /* driver operations */ 3333786Sarutz (struct bus_ops *)0, /* bus operations */ 3347656SSherry.Moore@Sun.COM dcdpower, /* power */ 3357656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 3363786Sarutz }; 3373786Sarutz 3383786Sarutz 3393786Sarutz /* 3403786Sarutz * This is the loadable module wrapper. 3413786Sarutz */ 3423786Sarutz #include <sys/modctl.h> 3433786Sarutz 3443786Sarutz static struct modldrv modldrv = { 3453786Sarutz &mod_driverops, /* Type of module. This one is a driver */ 3467656SSherry.Moore@Sun.COM "DAD Disk Driver", /* Name of the module. */ 3473786Sarutz &dcd_ops, /* driver ops */ 3483786Sarutz }; 3493786Sarutz 3503786Sarutz 3513786Sarutz 3523786Sarutz static struct modlinkage modlinkage = { 3533786Sarutz MODREV_1, &modldrv, NULL 3543786Sarutz }; 3553786Sarutz 3563786Sarutz /* 3573786Sarutz * the dcd_attach_mutex only protects dcd_max_instance in multi-threaded 3583786Sarutz * attach situations 3593786Sarutz */ 3603786Sarutz static kmutex_t dcd_attach_mutex; 3613786Sarutz 3623786Sarutz int 3633786Sarutz _init(void) 3643786Sarutz { 3653786Sarutz int e; 3663786Sarutz 3673786Sarutz if ((e = ddi_soft_state_init(&dcd_state, sizeof (struct dcd_disk), 3683786Sarutz DCD_MAXUNIT)) != 0) 3693786Sarutz return (e); 3703786Sarutz 3713786Sarutz mutex_init(&dcd_attach_mutex, NULL, MUTEX_DRIVER, NULL); 3723786Sarutz e = mod_install(&modlinkage); 3733786Sarutz if (e != 0) { 3743786Sarutz mutex_destroy(&dcd_attach_mutex); 3753786Sarutz ddi_soft_state_fini(&dcd_state); 3763786Sarutz return (e); 3773786Sarutz } 3783786Sarutz 3793786Sarutz return (e); 3803786Sarutz } 3813786Sarutz 3823786Sarutz int 3833786Sarutz _fini(void) 3843786Sarutz { 3853786Sarutz int e; 3863786Sarutz 3873786Sarutz if ((e = mod_remove(&modlinkage)) != 0) 3883786Sarutz return (e); 3893786Sarutz 3903786Sarutz ddi_soft_state_fini(&dcd_state); 3913786Sarutz mutex_destroy(&dcd_attach_mutex); 3923786Sarutz 3933786Sarutz return (e); 3943786Sarutz } 3953786Sarutz 3963786Sarutz int 3973786Sarutz _info(struct modinfo *modinfop) 3983786Sarutz { 3993786Sarutz 4003786Sarutz return (mod_info(&modlinkage, modinfop)); 4013786Sarutz } 4023786Sarutz 4033786Sarutz static int 4043786Sarutz dcdprobe(dev_info_t *devi) 4053786Sarutz { 4063786Sarutz struct dcd_device *devp; 4073786Sarutz int rval = DDI_PROBE_PARTIAL; 4083786Sarutz int instance; 4093786Sarutz 4103786Sarutz devp = ddi_get_driver_private(devi); 4113786Sarutz instance = ddi_get_instance(devi); 4123786Sarutz 4133786Sarutz /* 4143786Sarutz * Keep a count of how many disks (ie. highest instance no) we have 4153786Sarutz * XXX currently not used but maybe useful later again 4163786Sarutz */ 4173786Sarutz mutex_enter(&dcd_attach_mutex); 4183786Sarutz if (instance > dcd_max_instance) 4193786Sarutz dcd_max_instance = instance; 4203786Sarutz mutex_exit(&dcd_attach_mutex); 4213786Sarutz 4227224Scth DAD_DEBUG2(devp->dcd_dev, dcd_label, DCD_DEBUG, "dcdprobe:\n"); 4233786Sarutz 4243786Sarutz if (ddi_get_soft_state(dcd_state, instance) != NULL) 4253786Sarutz return (DDI_PROBE_PARTIAL); 4263786Sarutz 4273786Sarutz /* 4283786Sarutz * Turn around and call utility probe routine 4293786Sarutz * to see whether we actually have a disk at 4303786Sarutz */ 4313786Sarutz 4323786Sarutz DAD_DEBUG2(devp->dcd_dev, dcd_label, DCD_DEBUG, 4333786Sarutz "dcdprobe: %x\n", dcd_probe(devp, NULL_FUNC)); 4343786Sarutz 4353786Sarutz switch (dcd_probe(devp, NULL_FUNC)) { 4363786Sarutz default: 4373786Sarutz case DCDPROBE_NORESP: 4383786Sarutz case DCDPROBE_NONCCS: 4393786Sarutz case DCDPROBE_NOMEM: 4403786Sarutz case DCDPROBE_FAILURE: 4413786Sarutz case DCDPROBE_BUSY: 4423786Sarutz break; 4433786Sarutz 4443786Sarutz case DCDPROBE_EXISTS: 4453786Sarutz /* 4463786Sarutz * Check whether it is a ATA device and then 4473786Sarutz * return SUCCESS. 4483786Sarutz */ 4493786Sarutz DAD_DEBUG2(devp->dcd_dev, dcd_label, DCD_DEBUG, 4503786Sarutz "config %x\n", devp->dcd_ident->dcd_config); 4513786Sarutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) { 4523786Sarutz if (devp->dcd_ident->dcd_config & ATANON_REMOVABLE) { 4533786Sarutz rval = DDI_PROBE_SUCCESS; 4543786Sarutz } else 4553786Sarutz rval = DDI_PROBE_FAILURE; 4563786Sarutz } else { 4573786Sarutz rval = DDI_PROBE_FAILURE; 4583786Sarutz } 4593786Sarutz break; 4603786Sarutz } 4613786Sarutz dcd_unprobe(devp); 4623786Sarutz 4633786Sarutz DAD_DEBUG2(devp->dcd_dev, dcd_label, DCD_DEBUG, 4643786Sarutz "dcdprobe returns %x\n", rval); 4653786Sarutz 4663786Sarutz return (rval); 4673786Sarutz } 4683786Sarutz 4693786Sarutz 4703786Sarutz /*ARGSUSED*/ 4713786Sarutz static int 4723786Sarutz dcdattach(dev_info_t *devi, ddi_attach_cmd_t cmd) 4733786Sarutz { 4743786Sarutz int instance, rval; 4753786Sarutz struct dcd_device *devp; 4763786Sarutz struct dcd_disk *un; 4773786Sarutz struct diskhd *dp; 4783786Sarutz char *pm_comp[] = 4793786Sarutz { "NAME=ide-disk", "0=standby", "1=idle", "2=active" }; 4803786Sarutz 4813786Sarutz /* CONSTCOND */ 4823786Sarutz ASSERT(NO_COMPETING_THREADS); 4833786Sarutz 4843786Sarutz 4853786Sarutz devp = ddi_get_driver_private(devi); 4863786Sarutz instance = ddi_get_instance(devi); 4873786Sarutz DAD_DEBUG2(devp->dcd_dev, dcd_label, DCD_DEBUG, "Attach Started\n"); 4883786Sarutz 4893786Sarutz switch (cmd) { 4903786Sarutz case DDI_ATTACH: 4913786Sarutz break; 4923786Sarutz 4933786Sarutz case DDI_RESUME: 4943786Sarutz if (!(un = ddi_get_soft_state(dcd_state, instance))) 4953786Sarutz return (DDI_FAILURE); 4963786Sarutz mutex_enter(DCD_MUTEX); 4973786Sarutz Restore_state(un); 4983786Sarutz /* 4993786Sarutz * Restore the state which was saved to give the 5003786Sarutz * the right state in un_last_state 5013786Sarutz */ 5023786Sarutz un->un_last_state = un->un_save_state; 5033786Sarutz un->un_throttle = 2; 5043786Sarutz cv_broadcast(&un->un_suspend_cv); 5053786Sarutz /* 5063786Sarutz * Raise the power level of the device to active. 5073786Sarutz */ 5083786Sarutz mutex_exit(DCD_MUTEX); 5093786Sarutz (void) pm_raise_power(DCD_DEVINFO, 0, DCD_DEVICE_ACTIVE); 5103786Sarutz mutex_enter(DCD_MUTEX); 5113786Sarutz 5123786Sarutz /* 5133786Sarutz * start unit - if this is a low-activity device 5143786Sarutz * commands in queue will have to wait until new 5153786Sarutz * commands come in, which may take awhile. 5163786Sarutz * Also, we specifically don't check un_ncmds 5173786Sarutz * because we know that there really are no 5183786Sarutz * commands in progress after the unit was suspended 5193786Sarutz * and we could have reached the throttle level, been 5203786Sarutz * suspended, and have no new commands coming in for 5213786Sarutz * awhile. Highly unlikely, but so is the low- 5223786Sarutz * activity disk scenario. 5233786Sarutz */ 5243786Sarutz dp = &un->un_utab; 5253786Sarutz if (dp->b_actf && (dp->b_forw == NULL)) { 5263786Sarutz dcdstart(un); 5273786Sarutz } 5283786Sarutz 5293786Sarutz mutex_exit(DCD_MUTEX); 5303786Sarutz return (DDI_SUCCESS); 5313786Sarutz 5323786Sarutz default: 5333786Sarutz return (DDI_FAILURE); 5343786Sarutz } 5353786Sarutz 5363786Sarutz if (dcd_doattach(devi, SLEEP_FUNC) == DDI_FAILURE) { 5373786Sarutz return (DDI_FAILURE); 5383786Sarutz } 5393786Sarutz 5403786Sarutz if (!(un = (struct dcd_disk *) 5413786Sarutz ddi_get_soft_state(dcd_state, instance))) { 5423786Sarutz return (DDI_FAILURE); 5433786Sarutz } 5443786Sarutz devp->dcd_private = (ataopaque_t)un; 5453786Sarutz 5463786Sarutz /* 5473786Sarutz * Add a zero-length attribute to tell the world we support 5483786Sarutz * kernel ioctls (for layered drivers) 5493786Sarutz */ 5503786Sarutz (void) ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP, 5513786Sarutz DDI_KERNEL_IOCTL, NULL, 0); 5523786Sarutz 5533786Sarutz /* 5543786Sarutz * Since the dad device does not have the 'reg' property, 5553786Sarutz * cpr will not call its DDI_SUSPEND/DDI_RESUME entries. 5563786Sarutz * The following code is to tell cpr that this device 5573786Sarutz * does need to be suspended and resumed. 5583786Sarutz */ 5593786Sarutz (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, 5603786Sarutz "pm-hardware-state", (caddr_t)"needs-suspend-resume"); 5613786Sarutz 5623786Sarutz /* 5633786Sarutz * Initialize power management bookkeeping; 5643786Sarutz * Create components - In IDE case there are 3 levels and one 5653786Sarutz * component. The levels being - active, idle, standby. 5663786Sarutz */ 5673786Sarutz 5683786Sarutz rval = ddi_prop_update_string_array(DDI_DEV_T_NONE, 5693786Sarutz devi, "pm-components", pm_comp, 4); 5703786Sarutz if (rval == DDI_PROP_SUCCESS) { 5713786Sarutz /* 5723786Sarutz * Ignore the return value of pm_raise_power 5733786Sarutz * Even if we check the return values and 5743786Sarutz * remove the property created above, PM 5753786Sarutz * framework will not honour the change after 5763786Sarutz * first call to pm_raise_power. Hence, the 5773786Sarutz * removal of that property does not help if 5783786Sarutz * pm_raise_power fails. 5793786Sarutz */ 5803786Sarutz (void) pm_raise_power(DCD_DEVINFO, 0, DCD_DEVICE_ACTIVE); 5813786Sarutz } 5823786Sarutz 5833786Sarutz ddi_report_dev(devi); 5843786Sarutz 5853786Sarutz cmlb_alloc_handle(&un->un_dklbhandle); 5863786Sarutz 5873786Sarutz if (cmlb_attach(devi, 5887224Scth &dcd_lb_ops, 5897224Scth 0, 5907224Scth 0, 5917224Scth 0, 5927224Scth DDI_NT_BLOCK_CHAN, 5937224Scth CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8, 5947224Scth un->un_dklbhandle, 5957224Scth 0) != 0) { 5963786Sarutz cmlb_free_handle(&un->un_dklbhandle); 5973786Sarutz dcd_free_softstate(un, devi); 5983786Sarutz return (DDI_FAILURE); 5993786Sarutz } 6003786Sarutz 6013786Sarutz mutex_enter(DCD_MUTEX); 6023786Sarutz (void) dcd_validate_geometry(un); 6033786Sarutz 6043786Sarutz /* Get devid; create a devid ONLY IF could not get ID */ 6053786Sarutz if (dcd_get_devid(un) == NULL) { 6063786Sarutz /* Create the fab'd devid */ 6073786Sarutz (void) dcd_create_devid(un); 6083786Sarutz } 6093786Sarutz mutex_exit(DCD_MUTEX); 6103786Sarutz 6113786Sarutz return (DDI_SUCCESS); 6123786Sarutz } 6133786Sarutz 6143786Sarutz static void 6153786Sarutz dcd_free_softstate(struct dcd_disk *un, dev_info_t *devi) 6163786Sarutz { 6173786Sarutz struct dcd_device *devp; 6183786Sarutz int instance = ddi_get_instance(devi); 6193786Sarutz 6203786Sarutz devp = ddi_get_driver_private(devi); 6213786Sarutz 6223786Sarutz if (un) { 6233786Sarutz sema_destroy(&un->un_semoclose); 6243786Sarutz cv_destroy(&un->un_sbuf_cv); 6253786Sarutz cv_destroy(&un->un_state_cv); 6263786Sarutz cv_destroy(&un->un_disk_busy_cv); 6273786Sarutz cv_destroy(&un->un_suspend_cv); 6283786Sarutz 6293786Sarutz /* 6303786Sarutz * Deallocate command packet resources. 6313786Sarutz */ 6323786Sarutz if (un->un_sbufp) 6333786Sarutz freerbuf(un->un_sbufp); 6343786Sarutz if (un->un_dp) { 6353786Sarutz kmem_free((caddr_t)un->un_dp, sizeof (*un->un_dp)); 6363786Sarutz } 6373786Sarutz /* 6383786Sarutz * Unregister the devid and free devid resources allocated 6393786Sarutz */ 6403786Sarutz ddi_devid_unregister(DCD_DEVINFO); 6413786Sarutz if (un->un_devid) { 6423786Sarutz ddi_devid_free(un->un_devid); 6433786Sarutz un->un_devid = NULL; 6443786Sarutz } 6453786Sarutz 6463786Sarutz /* 6473786Sarutz * Delete kstats. Kstats for non CD devices are deleted 6483786Sarutz * in dcdclose. 6493786Sarutz */ 6503786Sarutz if (un->un_stats) { 6513786Sarutz kstat_delete(un->un_stats); 6523786Sarutz } 6533786Sarutz 6543786Sarutz } 6553786Sarutz 6563786Sarutz /* 6573786Sarutz * Cleanup scsi_device resources. 6583786Sarutz */ 6593786Sarutz ddi_soft_state_free(dcd_state, instance); 6603786Sarutz devp->dcd_private = (ataopaque_t)0; 6613786Sarutz /* unprobe scsi device */ 6623786Sarutz dcd_unprobe(devp); 6633786Sarutz 6643786Sarutz /* Remove properties created during attach */ 6653786Sarutz ddi_prop_remove_all(devi); 6663786Sarutz } 6673786Sarutz 6683786Sarutz static int 6693786Sarutz dcddetach(dev_info_t *devi, ddi_detach_cmd_t cmd) 6703786Sarutz { 6713786Sarutz int instance; 6723786Sarutz struct dcd_disk *un; 6733786Sarutz clock_t wait_cmds_complete; 6743786Sarutz instance = ddi_get_instance(devi); 6753786Sarutz 6763786Sarutz if (!(un = ddi_get_soft_state(dcd_state, instance))) 6773786Sarutz return (DDI_FAILURE); 6783786Sarutz 6793786Sarutz switch (cmd) { 6803786Sarutz case DDI_DETACH: 6813786Sarutz return (dcd_dr_detach(devi)); 6823786Sarutz 6833786Sarutz case DDI_SUSPEND: 6843786Sarutz mutex_enter(DCD_MUTEX); 6853786Sarutz if (un->un_state == DCD_STATE_SUSPENDED) { 6863786Sarutz mutex_exit(DCD_MUTEX); 6873786Sarutz return (DDI_SUCCESS); 6883786Sarutz } 6893786Sarutz un->un_throttle = 0; 6903786Sarutz /* 6913786Sarutz * Save the last state first 6923786Sarutz */ 6933786Sarutz un->un_save_state = un->un_last_state; 6943786Sarutz 6953786Sarutz New_state(un, DCD_STATE_SUSPENDED); 6963786Sarutz 6973786Sarutz /* 6983786Sarutz * wait till current operation completed. If we are 6993786Sarutz * in the resource wait state (with an intr outstanding) 7003786Sarutz * then we need to wait till the intr completes and 7013786Sarutz * starts the next cmd. We wait for 7023786Sarutz * DCD_WAIT_CMDS_COMPLETE seconds before failing the 7033786Sarutz * DDI_SUSPEND. 7043786Sarutz */ 7053786Sarutz wait_cmds_complete = ddi_get_lbolt(); 7063786Sarutz wait_cmds_complete += 7077224Scth DCD_WAIT_CMDS_COMPLETE * drv_usectohz(1000000); 7083786Sarutz 7093786Sarutz while (un->un_ncmds) { 7103786Sarutz if (cv_timedwait(&un->un_disk_busy_cv, 7113786Sarutz DCD_MUTEX, wait_cmds_complete) == -1) { 7123786Sarutz /* 7133786Sarutz * commands Didn't finish in the 7143786Sarutz * specified time, fail the DDI_SUSPEND. 7153786Sarutz */ 7163786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, 7173786Sarutz DCD_DEBUG, "dcddetach: SUSPEND " 7183786Sarutz "failed due to outstanding cmds\n"); 7193786Sarutz Restore_state(un); 7203786Sarutz mutex_exit(DCD_MUTEX); 7213786Sarutz return (DDI_FAILURE); 7223786Sarutz } 7233786Sarutz } 7243786Sarutz mutex_exit(DCD_MUTEX); 7253786Sarutz return (DDI_SUCCESS); 7263786Sarutz } 7273786Sarutz return (DDI_FAILURE); 7283786Sarutz } 7293786Sarutz 7303786Sarutz /* 7313786Sarutz * The reset entry point gets invoked at the system shutdown time or through 7323786Sarutz * CPR code at system suspend. 7333786Sarutz * Will be flushing the cache and expect this to be last I/O operation to the 7343786Sarutz * disk before system reset/power off. 7353786Sarutz */ 7363786Sarutz /*ARGSUSED*/ 7373786Sarutz static int 7383786Sarutz dcdreset(dev_info_t *dip, ddi_reset_cmd_t cmd) 7393786Sarutz { 7403786Sarutz struct dcd_disk *un; 7413786Sarutz int instance; 7423786Sarutz 7433786Sarutz instance = ddi_get_instance(dip); 7443786Sarutz 7453786Sarutz if (!(un = ddi_get_soft_state(dcd_state, instance))) 7463786Sarutz return (DDI_FAILURE); 7473786Sarutz 7483786Sarutz dcd_flush_cache(un); 7493786Sarutz 7503786Sarutz return (DDI_SUCCESS); 7513786Sarutz } 7523786Sarutz 7533786Sarutz 7543786Sarutz static int 7553786Sarutz dcd_dr_detach(dev_info_t *devi) 7563786Sarutz { 7573786Sarutz struct dcd_device *devp; 7583786Sarutz struct dcd_disk *un; 7593786Sarutz 7603786Sarutz /* 7613786Sarutz * Get scsi_device structure for this instance. 7623786Sarutz */ 7633786Sarutz if ((devp = ddi_get_driver_private(devi)) == NULL) 7643786Sarutz return (DDI_FAILURE); 7653786Sarutz 7663786Sarutz /* 7673786Sarutz * Get dcd_disk structure containing target 'private' information 7683786Sarutz */ 7693786Sarutz un = (struct dcd_disk *)devp->dcd_private; 7703786Sarutz 7713786Sarutz /* 7723786Sarutz * Verify there are NO outstanding commands issued to this device. 7733786Sarutz * ie, un_ncmds == 0. 7743786Sarutz * It's possible to have outstanding commands through the physio 7753786Sarutz * code path, even though everything's closed. 7763786Sarutz */ 7773786Sarutz #ifndef lint 7783786Sarutz _NOTE(COMPETING_THREADS_NOW); 7793786Sarutz #endif 7803786Sarutz mutex_enter(DCD_MUTEX); 7813786Sarutz if (un->un_ncmds) { 7823786Sarutz mutex_exit(DCD_MUTEX); 7833786Sarutz _NOTE(NO_COMPETING_THREADS_NOW); 7843786Sarutz return (DDI_FAILURE); 7853786Sarutz } 7863786Sarutz 7873786Sarutz mutex_exit(DCD_MUTEX); 7883786Sarutz 7893786Sarutz cmlb_detach(un->un_dklbhandle, 0); 7903786Sarutz cmlb_free_handle(&un->un_dklbhandle); 7913786Sarutz 7923786Sarutz 7933786Sarutz /* 7943786Sarutz * Lower the power state of the device 7953786Sarutz * i.e. the minimum power consumption state - sleep. 7963786Sarutz */ 7973786Sarutz (void) pm_lower_power(DCD_DEVINFO, 0, DCD_DEVICE_STANDBY); 7983786Sarutz 7993786Sarutz _NOTE(NO_COMPETING_THREADS_NOW); 8003786Sarutz 8013786Sarutz /* 8023786Sarutz * at this point there are no competing threads anymore 8033786Sarutz * release active MT locks and all device resources. 8043786Sarutz */ 8053786Sarutz dcd_free_softstate(un, devi); 8063786Sarutz 8073786Sarutz return (DDI_SUCCESS); 8083786Sarutz } 8093786Sarutz 8103786Sarutz static int 8113786Sarutz dcdpower(dev_info_t *devi, int component, int level) 8123786Sarutz { 8133786Sarutz struct dcd_pkt *pkt; 8143786Sarutz struct dcd_disk *un; 8153786Sarutz int instance; 8163786Sarutz uchar_t cmd; 8173786Sarutz 8183786Sarutz 8193786Sarutz instance = ddi_get_instance(devi); 8203786Sarutz 8213786Sarutz if (!(un = ddi_get_soft_state(dcd_state, instance)) || 8227224Scth (DCD_DEVICE_STANDBY > level) || (level > DCD_DEVICE_ACTIVE) || 8237224Scth component != 0) { 8243786Sarutz return (DDI_FAILURE); 8253786Sarutz } 8263786Sarutz 8273786Sarutz mutex_enter(DCD_MUTEX); 8283786Sarutz /* 8293786Sarutz * if there are active commands for the device or device will be 8303786Sarutz * active soon. At the same time there is request to lower power 8313786Sarutz * return failure. 8323786Sarutz */ 8333786Sarutz if ((un->un_ncmds) && (level != DCD_DEVICE_ACTIVE)) { 8343786Sarutz mutex_exit(DCD_MUTEX); 8353786Sarutz return (DDI_FAILURE); 8363786Sarutz } 8373786Sarutz 8383786Sarutz if ((un->un_state == DCD_STATE_OFFLINE) || 8393786Sarutz (un->un_state == DCD_STATE_FATAL)) { 8403786Sarutz mutex_exit(DCD_MUTEX); 8413786Sarutz return (DDI_FAILURE); 8423786Sarutz } 8433786Sarutz 8443786Sarutz if (level == DCD_DEVICE_ACTIVE) { 8453786Sarutz /* 8463786Sarutz * No need to fire any command, just set the state structure 8473786Sarutz * to indicate previous state and set the level to active 8483786Sarutz */ 8493786Sarutz un->un_power_level = DCD_DEVICE_ACTIVE; 8503786Sarutz if (un->un_state == DCD_STATE_PM_SUSPENDED) 8513786Sarutz Restore_state(un); 8523786Sarutz mutex_exit(DCD_MUTEX); 8533786Sarutz } else { 8543786Sarutz pkt = dcd_init_pkt(ROUTE, (struct dcd_pkt *)NULL, 8553786Sarutz NULL, (uint32_t)sizeof (struct dcd_cmd), 2, PP_LEN, 8563786Sarutz PKT_CONSISTENT, NULL_FUNC, NULL); 8573786Sarutz 8583786Sarutz if (pkt == (struct dcd_pkt *)NULL) { 8593786Sarutz mutex_exit(DCD_MUTEX); 8603786Sarutz return (DDI_FAILURE); 8613786Sarutz } 8623786Sarutz 8633786Sarutz switch (level) { 8643786Sarutz case DCD_DEVICE_IDLE: 8653786Sarutz cmd = ATA_IDLE_IMMEDIATE; 8663786Sarutz break; 8673786Sarutz 8683786Sarutz case DCD_DEVICE_STANDBY: 8693786Sarutz cmd = ATA_STANDBY_IMMEDIATE; 8703786Sarutz break; 8713786Sarutz } 8723786Sarutz 8733786Sarutz makecommand(pkt, 0, cmd, 0, 0, 0, NO_DATA_XFER, 0); 8743786Sarutz mutex_exit(DCD_MUTEX); 8753786Sarutz /* 8763786Sarutz * Issue the appropriate command 8773786Sarutz */ 8783786Sarutz if ((dcd_poll(pkt)) || (SCBP_C(pkt) != STATUS_GOOD)) { 8793786Sarutz dcd_destroy_pkt(pkt); 8803786Sarutz return (DDI_FAILURE); 8813786Sarutz } 8823786Sarutz dcd_destroy_pkt(pkt); 8833786Sarutz mutex_enter(DCD_MUTEX); 8843786Sarutz if (un->un_state != DCD_STATE_PM_SUSPENDED) 8853786Sarutz New_state(un, DCD_STATE_PM_SUSPENDED); 8863786Sarutz un->un_power_level = level; 8873786Sarutz mutex_exit(DCD_MUTEX); 8883786Sarutz } 8893786Sarutz 8903786Sarutz return (DDI_SUCCESS); 8913786Sarutz } 8923786Sarutz 8933786Sarutz static int 8943786Sarutz dcd_doattach(dev_info_t *devi, int (*canwait)()) 8953786Sarutz { 8963786Sarutz struct dcd_device *devp; 8973786Sarutz struct dcd_disk *un = (struct dcd_disk *)0; 8983786Sarutz int instance; 8993786Sarutz int km_flags = (canwait != NULL_FUNC)? KM_SLEEP : KM_NOSLEEP; 9003786Sarutz int rval; 9013786Sarutz char *prop_template = "target%x-dcd-options"; 9023786Sarutz int options; 9033786Sarutz char prop_str[32]; 9043786Sarutz int target; 9053786Sarutz diskaddr_t capacity; 9063786Sarutz 9073786Sarutz devp = ddi_get_driver_private(devi); 9083786Sarutz 9093786Sarutz /* 9103786Sarutz * Call the routine scsi_probe to do some of the dirty work. 9113786Sarutz * If the INQUIRY command succeeds, the field dcd_inq in the 9123786Sarutz * device structure will be filled in. The dcd_sense structure 9133786Sarutz * will also be allocated. 9143786Sarutz */ 9153786Sarutz 9163786Sarutz switch (dcd_probe(devp, canwait)) { 9173786Sarutz default: 9183786Sarutz return (DDI_FAILURE); 9193786Sarutz 9203786Sarutz case DCDPROBE_EXISTS: 9213786Sarutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) { 9223786Sarutz if (devp->dcd_ident->dcd_config & ATANON_REMOVABLE) { 9233786Sarutz rval = DDI_SUCCESS; 9243786Sarutz } else { 9253786Sarutz rval = DDI_FAILURE; 9263786Sarutz goto error; 9273786Sarutz } 9283786Sarutz } else { 9293786Sarutz rval = DDI_FAILURE; 9303786Sarutz goto error; 9313786Sarutz } 9323786Sarutz } 9333786Sarutz 9343786Sarutz 9353786Sarutz instance = ddi_get_instance(devp->dcd_dev); 9363786Sarutz 9373786Sarutz if (ddi_soft_state_zalloc(dcd_state, instance) != DDI_SUCCESS) { 9383786Sarutz rval = DDI_FAILURE; 9393786Sarutz goto error; 9403786Sarutz } 9413786Sarutz 9423786Sarutz un = ddi_get_soft_state(dcd_state, instance); 9433786Sarutz 9443786Sarutz un->un_sbufp = getrbuf(km_flags); 9453786Sarutz if (un->un_sbufp == (struct buf *)NULL) { 9463786Sarutz rval = DDI_FAILURE; 9473786Sarutz goto error; 9483786Sarutz } 9493786Sarutz 9503786Sarutz 9513786Sarutz un->un_dcd = devp; 9523786Sarutz un->un_power_level = -1; 9533786Sarutz un->un_tgattribute.media_is_writable = 1; 9543786Sarutz 9553786Sarutz sema_init(&un->un_semoclose, 1, NULL, SEMA_DRIVER, NULL); 9563786Sarutz cv_init(&un->un_sbuf_cv, NULL, CV_DRIVER, NULL); 9573786Sarutz cv_init(&un->un_state_cv, NULL, CV_DRIVER, NULL); 9583786Sarutz /* Initialize power management conditional variable */ 9593786Sarutz cv_init(&un->un_disk_busy_cv, NULL, CV_DRIVER, NULL); 9603786Sarutz cv_init(&un->un_suspend_cv, NULL, CV_DRIVER, NULL); 9613786Sarutz 9623786Sarutz if (un->un_dp == 0) { 9633786Sarutz /* 9643786Sarutz * Assume CCS drive, assume parity, but call 9653786Sarutz * it a CDROM if it is a RODIRECT device. 9663786Sarutz */ 9673786Sarutz un->un_dp = (struct dcd_drivetype *) 9683786Sarutz kmem_zalloc(sizeof (struct dcd_drivetype), km_flags); 9693786Sarutz if (!un->un_dp) { 9703786Sarutz rval = DDI_FAILURE; 9713786Sarutz goto error; 9723786Sarutz } 9733786Sarutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) { 9743786Sarutz if (devp->dcd_ident->dcd_config & ATANON_REMOVABLE) { 9753786Sarutz un->un_dp->ctype = CTYPE_DISK; 9763786Sarutz } 9773786Sarutz } else { 9783786Sarutz rval = DDI_FAILURE; 9793786Sarutz goto error; 9803786Sarutz } 9813786Sarutz un->un_dp->name = "CCS"; 9823786Sarutz un->un_dp->options = 0; 9833786Sarutz } 9843786Sarutz 9853786Sarutz /* 9863786Sarutz * Allow I/O requests at un_secsize offset in multiple of un_secsize. 9873786Sarutz */ 9883786Sarutz un->un_secsize = DEV_BSIZE; 9893786Sarutz 9903786Sarutz /* 9913786Sarutz * If the device is not a removable media device, make sure that 9923786Sarutz * that the device is ready, by issuing the another identify but 9933786Sarutz * not needed. Get the capacity from identify data and store here. 9943786Sarutz */ 9953786Sarutz if (dcd_compute_dk_capacity(devp, &capacity) == 0) { 9963786Sarutz un->un_diskcapacity = capacity; 9973786Sarutz un->un_lbasize = DEV_BSIZE; 9983786Sarutz } 9993786Sarutz 10003786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "Geometry Data\n"); 10013786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "cyls %x, heads %x", 10023786Sarutz devp->dcd_ident->dcd_fixcyls, 10033786Sarutz devp->dcd_ident->dcd_heads); 10043786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "sectors %x,", 10053786Sarutz devp->dcd_ident->dcd_sectors); 10063786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "capacity %llx\n", 10073786Sarutz capacity); 10083786Sarutz 10093786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 10103786Sarutz "dcdprobe: drive selected\n"); 10113786Sarutz 10123786Sarutz /* 10133786Sarutz * Check for the property target<n>-dcd-options to find the option 10143786Sarutz * set by the HBA driver for this target so that we can set the 10153786Sarutz * Unit structure variable so that we can send commands accordingly. 10163786Sarutz */ 1017*7875SChris.Horne@Sun.COM target = devp->dcd_address->da_target; 10183786Sarutz (void) sprintf(prop_str, prop_template, target); 10193786Sarutz options = ddi_prop_get_int(DDI_DEV_T_ANY, devi, DDI_PROP_NOTPROM, 10203786Sarutz prop_str, -1); 10213786Sarutz if (options < 0) { 10223786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 10233786Sarutz "No per target properties"); 10243786Sarutz } else { 10253786Sarutz if ((options & DCD_DMA_MODE) == DCD_DMA_MODE) { 10263786Sarutz un->un_dp->options |= DMA_SUPPORTTED; 10273786Sarutz un->un_dp->dma_mode = (options >> 3) & 0x03; 10283786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 10293786Sarutz "mode %x\n", un->un_dp->dma_mode); 10303786Sarutz } else { 10313786Sarutz un->un_dp->options &= ~DMA_SUPPORTTED; 10323786Sarutz un->un_dp->pio_mode = options & 0x7; 10333786Sarutz if (options & DCD_BLOCK_MODE) 10343786Sarutz un->un_dp->options |= BLOCK_MODE; 10353786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 10363786Sarutz "mode %x\n", un->un_dp->pio_mode); 10373786Sarutz } 10383786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 10393786Sarutz "options %x,", un->un_dp->options); 10403786Sarutz } 10413786Sarutz 10423786Sarutz un->un_throttle = 2; 10433786Sarutz /* 10443786Sarutz * set default max_xfer_size - This should depend on whether the 10453786Sarutz * Block mode is supported by the device or not. 10463786Sarutz */ 10473786Sarutz un->un_max_xfer_size = MAX_ATA_XFER_SIZE; 10483786Sarutz 10493786Sarutz /* 10503786Sarutz * Set write cache enable softstate 10513786Sarutz * 10523786Sarutz * WCE is only supported in ATAPI-4 or higher; for 10533786Sarutz * lower rev devices, must assume write cache is 10543786Sarutz * enabled. 10553786Sarutz */ 10563786Sarutz mutex_enter(DCD_MUTEX); 10573786Sarutz un->un_write_cache_enabled = (devp->dcd_ident->dcd_majvers == 0xffff) || 10583786Sarutz ((devp->dcd_ident->dcd_majvers & IDENTIFY_80_ATAPI_4) == 0) || 10593786Sarutz (devp->dcd_ident->dcd_features85 & IDENTIFY_85_WCE) != 0; 10603786Sarutz mutex_exit(DCD_MUTEX); 10613786Sarutz 10623786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 10633786Sarutz "dcd_doattach returns good\n"); 10643786Sarutz 10653786Sarutz return (rval); 10663786Sarutz 10673786Sarutz error: 10683786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcd_doattach failed\n"); 10693786Sarutz dcd_free_softstate(un, devi); 10703786Sarutz return (rval); 10713786Sarutz } 10723786Sarutz 10733786Sarutz #ifdef NOTNEEDED 10743786Sarutz /* 10753786Sarutz * This routine is used to set the block mode of operation by issuing the 10763786Sarutz * Set Block mode ata command with the maximum block mode possible 10773786Sarutz */ 10783786Sarutz dcd_set_multiple(struct dcd_disk *un) 10793786Sarutz { 10803786Sarutz int status; 10813786Sarutz struct udcd_cmd ucmd; 10823786Sarutz struct dcd_cmd cdb; 10833786Sarutz dev_t dev; 10843786Sarutz 10853786Sarutz 10863786Sarutz /* Zero all the required structure */ 10873786Sarutz (void) bzero((caddr_t)&ucmd, sizeof (ucmd)); 10883786Sarutz 10893786Sarutz (void) bzero((caddr_t)&cdb, sizeof (struct dcd_cmd)); 10903786Sarutz 10913786Sarutz cdb.cmd = ATA_SET_MULTIPLE; 10923786Sarutz /* 10933786Sarutz * Here we should pass what needs to go into sector count REGISTER. 10943786Sarutz * Eventhough this field indicates the number of bytes to read we 10953786Sarutz * need to specify the block factor in terms of bytes so that it 10963786Sarutz * will be programmed by the HBA driver into the sector count register. 10973786Sarutz */ 10983786Sarutz cdb.size = un->un_lbasize * un->un_dp->block_factor; 10993786Sarutz 11003786Sarutz cdb.sector_num.lba_num = 0; 11013786Sarutz cdb.address_mode = ADD_LBA_MODE; 11023786Sarutz cdb.direction = NO_DATA_XFER; 11033786Sarutz 11043786Sarutz ucmd.udcd_flags = 0; 11053786Sarutz ucmd.udcd_cmd = &cdb; 11063786Sarutz ucmd.udcd_bufaddr = NULL; 11073786Sarutz ucmd.udcd_buflen = 0; 11083786Sarutz ucmd.udcd_flags |= UDCD_SILENT; 11093786Sarutz 11103786Sarutz dev = makedevice(ddi_driver_major(DCD_DEVINFO), 11113786Sarutz ddi_get_instance(DCD_DEVINFO) << DCDUNIT_SHIFT); 11123786Sarutz 11133786Sarutz 11143786Sarutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE); 11153786Sarutz 11163786Sarutz return (status); 11173786Sarutz } 11183786Sarutz /* 11193786Sarutz * The following routine is used only for setting the transfer mode 11203786Sarutz * and it is not designed for transferring any other features subcommand. 11213786Sarutz */ 11223786Sarutz dcd_set_features(struct dcd_disk *un, uchar_t mode) 11233786Sarutz { 11243786Sarutz int status; 11253786Sarutz struct udcd_cmd ucmd; 11263786Sarutz struct dcd_cmd cdb; 11273786Sarutz dev_t dev; 11283786Sarutz 11293786Sarutz 11303786Sarutz /* Zero all the required structure */ 11313786Sarutz (void) bzero((caddr_t)&ucmd, sizeof (ucmd)); 11323786Sarutz 11333786Sarutz (void) bzero((caddr_t)&cdb, sizeof (struct dcd_cmd)); 11343786Sarutz 11353786Sarutz cdb.cmd = ATA_SET_FEATURES; 11363786Sarutz /* 11373786Sarutz * Here we need to pass what needs to go into the sector count register 11383786Sarutz * But in the case of SET FEATURES command the value taken in the 11393786Sarutz * sector count register depends what type of subcommand is 11403786Sarutz * passed in the features register. Since we have defined the size to 11413786Sarutz * be the size in bytes in this context it does not indicate bytes 11423786Sarutz * instead it indicates the mode to be programmed. 11433786Sarutz */ 11443786Sarutz cdb.size = un->un_lbasize * mode; 11453786Sarutz 11463786Sarutz cdb.sector_num.lba_num = 0; 11473786Sarutz cdb.address_mode = ADD_LBA_MODE; 11483786Sarutz cdb.direction = NO_DATA_XFER; 11493786Sarutz cdb.features = ATA_FEATURE_SET_MODE; 11503786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 11513786Sarutz "size %x, features %x, cmd %x\n", 11523786Sarutz cdb.size, cdb.features, cdb.cmd); 11533786Sarutz 11543786Sarutz ucmd.udcd_flags = 0; 11553786Sarutz ucmd.udcd_cmd = &cdb; 11563786Sarutz ucmd.udcd_bufaddr = NULL; 11573786Sarutz ucmd.udcd_buflen = 0; 11583786Sarutz ucmd.udcd_flags |= UDCD_SILENT; 11593786Sarutz 11603786Sarutz dev = makedevice(ddi_driver_major(DCD_DEVINFO), 11613786Sarutz ddi_get_instance(DCD_DEVINFO) << DCDUNIT_SHIFT); 11623786Sarutz 11633786Sarutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE); 11643786Sarutz 11653786Sarutz return (status); 11663786Sarutz } 11673786Sarutz #endif 11683786Sarutz 11693786Sarutz /* 11703786Sarutz * Validate the geometry for this disk, e.g., 11713786Sarutz * see whether it has a valid label. 11723786Sarutz */ 11733786Sarutz static int 11743786Sarutz dcd_validate_geometry(struct dcd_disk *un) 11753786Sarutz { 11763786Sarutz int secsize = 0; 11773786Sarutz struct dcd_device *devp; 11783786Sarutz int secdiv; 11793786Sarutz int rval; 11803786Sarutz 11813786Sarutz ASSERT(mutex_owned(DCD_MUTEX)); 11823786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 11833786Sarutz "dcd_validate_geometry: started \n"); 11843786Sarutz 11853786Sarutz if (un->un_lbasize < 0) { 11863786Sarutz return (DCD_BAD_LABEL); 11873786Sarutz } 11883786Sarutz 11893786Sarutz if (un->un_state == DCD_STATE_PM_SUSPENDED) { 11903786Sarutz mutex_exit(DCD_MUTEX); 11917224Scth if (pm_raise_power(DCD_DEVINFO, 0, DCD_DEVICE_ACTIVE) != 11927224Scth DDI_SUCCESS) { 11933786Sarutz mutex_enter(DCD_MUTEX); 11943786Sarutz return (DCD_BAD_LABEL); 11953786Sarutz } 11963786Sarutz mutex_enter(DCD_MUTEX); 11973786Sarutz } 11983786Sarutz 11993786Sarutz secsize = un->un_secsize; 12003786Sarutz 12013786Sarutz /* 12023786Sarutz * take a log base 2 of sector size (sorry) 12033786Sarutz */ 12043786Sarutz for (secdiv = 0; secsize = secsize >> 1; secdiv++) 12053786Sarutz ; 12063786Sarutz un->un_secdiv = secdiv; 12073786Sarutz 12083786Sarutz /* 12093786Sarutz * Only DIRECT ACCESS devices will have Sun labels. 12103786Sarutz * CD's supposedly have a Sun label, too 12113786Sarutz */ 12123786Sarutz 12133786Sarutz devp = un->un_dcd; 12143786Sarutz 12153786Sarutz if (((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) && 12163786Sarutz (devp->dcd_ident->dcd_config & ATANON_REMOVABLE)) { 12173786Sarutz mutex_exit(DCD_MUTEX); 12183786Sarutz rval = cmlb_validate(un->un_dklbhandle, 0, 0); 12193786Sarutz mutex_enter(DCD_MUTEX); 12203786Sarutz if (rval == ENOMEM) 12213786Sarutz return (DCD_NO_MEM_FOR_LABEL); 12223786Sarutz else if (rval != 0) 12233786Sarutz return (DCD_BAD_LABEL); 12243786Sarutz } else { 12253786Sarutz /* it should never get here. */ 12263786Sarutz return (DCD_BAD_LABEL); 12273786Sarutz } 12283786Sarutz 12293786Sarutz /* 12303786Sarutz * take a log base 2 of logical block size 12313786Sarutz */ 12323786Sarutz secsize = un->un_lbasize; 12333786Sarutz for (secdiv = 0; secsize = secsize >> 1; secdiv++) 12343786Sarutz ; 12353786Sarutz un->un_lbadiv = secdiv; 12363786Sarutz 12373786Sarutz /* 12383786Sarutz * take a log base 2 of the multiple of DEV_BSIZE blocks that 12393786Sarutz * make up one logical block 12403786Sarutz */ 12413786Sarutz secsize = un->un_lbasize >> DEV_BSHIFT; 12423786Sarutz for (secdiv = 0; secsize = secsize >> 1; secdiv++) 12433786Sarutz ; 12443786Sarutz un->un_blknoshift = secdiv; 12453786Sarutz return (0); 12463786Sarutz } 12473786Sarutz 12483786Sarutz /* 12493786Sarutz * Unix Entry Points 12503786Sarutz */ 12513786Sarutz 12523786Sarutz /* ARGSUSED3 */ 12533786Sarutz static int 12543786Sarutz dcdopen(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 12553786Sarutz { 12563786Sarutz dev_t dev = *dev_p; 12573786Sarutz int rval = EIO; 12583786Sarutz int partmask; 12593786Sarutz int nodelay = (flag & (FNDELAY | FNONBLOCK)); 12603786Sarutz int i; 12613786Sarutz char kstatname[KSTAT_STRLEN]; 12623786Sarutz diskaddr_t lblocks; 12633786Sarutz char *partname; 12643786Sarutz 12653786Sarutz GET_SOFT_STATE(dev); 12663786Sarutz 12673786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 12683786Sarutz "Inside Open flag %x, otyp %x\n", flag, otyp); 12693786Sarutz 12703786Sarutz if (otyp >= OTYPCNT) { 12713786Sarutz return (EINVAL); 12723786Sarutz } 12733786Sarutz 12743786Sarutz partmask = 1 << part; 12753786Sarutz 12763786Sarutz /* 12773786Sarutz * We use a semaphore here in order to serialize 12783786Sarutz * open and close requests on the device. 12793786Sarutz */ 12803786Sarutz sema_p(&un->un_semoclose); 12813786Sarutz 12823786Sarutz mutex_enter(DCD_MUTEX); 12833786Sarutz 12843786Sarutz if ((un->un_state & DCD_STATE_FATAL) == DCD_STATE_FATAL) { 12853786Sarutz rval = ENXIO; 12863786Sarutz goto done; 12873786Sarutz } 12883786Sarutz 12893786Sarutz while (un->un_state == DCD_STATE_SUSPENDED) { 12903786Sarutz cv_wait(&un->un_suspend_cv, DCD_MUTEX); 12913786Sarutz } 12923786Sarutz 12933786Sarutz if ((un->un_state == DCD_STATE_PM_SUSPENDED) && (!nodelay)) { 12943786Sarutz mutex_exit(DCD_MUTEX); 12953786Sarutz if (pm_raise_power(DCD_DEVINFO, 0, DCD_DEVICE_ACTIVE) 12963786Sarutz != DDI_SUCCESS) { 12973786Sarutz mutex_enter(DCD_MUTEX); 12983786Sarutz rval = EIO; 12993786Sarutz goto done; 13003786Sarutz } 13013786Sarutz mutex_enter(DCD_MUTEX); 13023786Sarutz } 13033786Sarutz 13043786Sarutz /* 13053786Sarutz * set make_dcd_cmd() flags and stat_size here since these 13063786Sarutz * are unlikely to change 13073786Sarutz */ 13083786Sarutz un->un_cmd_flags = 0; 13093786Sarutz 13103786Sarutz un->un_cmd_stat_size = 2; 13113786Sarutz 13123786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdopen un=0x%p\n", 13133786Sarutz (void *)un); 13143786Sarutz /* 13153786Sarutz * check for previous exclusive open 13163786Sarutz */ 13173786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 13183786Sarutz "exclopen=%x, flag=%x, regopen=%x\n", 13193786Sarutz un->un_exclopen, flag, un->un_ocmap.regopen[otyp]); 13203786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 13213786Sarutz "Exclusive open flag %x, partmask %x\n", 13223786Sarutz un->un_exclopen, partmask); 13233786Sarutz 13243786Sarutz if (un->un_exclopen & (partmask)) { 13253786Sarutz failed_exclusive: 13263786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 13273786Sarutz "exclusive open fails\n"); 13283786Sarutz rval = EBUSY; 13293786Sarutz goto done; 13303786Sarutz } 13313786Sarutz 13323786Sarutz if (flag & FEXCL) { 13333786Sarutz int i; 13343786Sarutz if (un->un_ocmap.lyropen[part]) { 13353786Sarutz goto failed_exclusive; 13363786Sarutz } 13373786Sarutz for (i = 0; i < (OTYPCNT - 1); i++) { 13383786Sarutz if (un->un_ocmap.regopen[i] & (partmask)) { 13393786Sarutz goto failed_exclusive; 13403786Sarutz } 13413786Sarutz } 13423786Sarutz } 13433786Sarutz if (flag & FWRITE) { 13443786Sarutz mutex_exit(DCD_MUTEX); 13453786Sarutz if (dcd_check_wp(dev)) { 13463786Sarutz sema_v(&un->un_semoclose); 13473786Sarutz return (EROFS); 13483786Sarutz } 13493786Sarutz mutex_enter(DCD_MUTEX); 13503786Sarutz } 13513786Sarutz 13523786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 13533786Sarutz "Check Write Protect handled\n"); 13543786Sarutz 13553786Sarutz if (!nodelay) { 13563786Sarutz mutex_exit(DCD_MUTEX); 13573786Sarutz if ((rval = dcd_ready_and_valid(dev, un)) != 0) { 13583786Sarutz rval = EIO; 13593786Sarutz } 13603786Sarutz (void) pm_idle_component(DCD_DEVINFO, 0); 13613786Sarutz /* 13623786Sarutz * Fail if device is not ready or if the number of disk 13633786Sarutz * blocks is zero or negative for non CD devices. 13643786Sarutz */ 13653786Sarutz if (rval || cmlb_partinfo(un->un_dklbhandle, 13663786Sarutz part, &lblocks, NULL, &partname, NULL, 0) || 13673786Sarutz lblocks <= 0) { 13683786Sarutz rval = EIO; 13693786Sarutz mutex_enter(DCD_MUTEX); 13703786Sarutz goto done; 13713786Sarutz } 13723786Sarutz mutex_enter(DCD_MUTEX); 13733786Sarutz } 13743786Sarutz 13753786Sarutz if (otyp == OTYP_LYR) { 13763786Sarutz un->un_ocmap.lyropen[part]++; 13773786Sarutz } else { 13783786Sarutz un->un_ocmap.regopen[otyp] |= partmask; 13793786Sarutz } 13803786Sarutz 13813786Sarutz /* 13823786Sarutz * set up open and exclusive open flags 13833786Sarutz */ 13843786Sarutz if (flag & FEXCL) { 13853786Sarutz un->un_exclopen |= (partmask); 13863786Sarutz } 13873786Sarutz 13883786Sarutz 13893786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 13903786Sarutz "open of part %d type %d\n", 13913786Sarutz part, otyp); 13923786Sarutz 13933786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 13943786Sarutz "Kstats getting updated\n"); 13953786Sarutz /* 13963786Sarutz * only create kstats for disks, CD kstats created in dcdattach 13973786Sarutz */ 13983786Sarutz _NOTE(NO_COMPETING_THREADS_NOW); 13993786Sarutz mutex_exit(DCD_MUTEX); 14003786Sarutz if (un->un_stats == (kstat_t *)0) { 14013786Sarutz un->un_stats = kstat_create("dad", instance, 14023786Sarutz NULL, "disk", KSTAT_TYPE_IO, 1, 14033786Sarutz KSTAT_FLAG_PERSISTENT); 14043786Sarutz if (un->un_stats) { 14053786Sarutz un->un_stats->ks_lock = DCD_MUTEX; 14063786Sarutz kstat_install(un->un_stats); 14073786Sarutz } 14083786Sarutz 14093786Sarutz /* 14103786Sarutz * set up partition statistics for each partition 14113786Sarutz * with number of blocks > 0 14123786Sarutz */ 14133786Sarutz if (!nodelay) { 14143786Sarutz for (i = 0; i < NDKMAP; i++) { 14153786Sarutz if ((un->un_pstats[i] == (kstat_t *)0) && 14163786Sarutz (cmlb_partinfo(un->un_dklbhandle, 14173786Sarutz i, &lblocks, NULL, &partname, 14183786Sarutz NULL, 0) == 0) && lblocks > 0) { 14193786Sarutz (void) sprintf(kstatname, "dad%d,%s", 14203786Sarutz instance, partname); 14213786Sarutz un->un_pstats[i] = kstat_create("dad", 14223786Sarutz instance, 14233786Sarutz kstatname, 14243786Sarutz "partition", 14253786Sarutz KSTAT_TYPE_IO, 14263786Sarutz 1, 14273786Sarutz KSTAT_FLAG_PERSISTENT); 14283786Sarutz if (un->un_pstats[i]) { 14293786Sarutz un->un_pstats[i]->ks_lock = 14303786Sarutz DCD_MUTEX; 14313786Sarutz kstat_install(un->un_pstats[i]); 14323786Sarutz } 14333786Sarutz } 14343786Sarutz } 14353786Sarutz } 14363786Sarutz /* 14373786Sarutz * set up error kstats 14383786Sarutz */ 14393786Sarutz (void) dcd_create_errstats(un, instance); 14403786Sarutz } 14413786Sarutz #ifndef lint 14423786Sarutz _NOTE(COMPETING_THREADS_NOW); 14433786Sarutz #endif 14443786Sarutz 14453786Sarutz sema_v(&un->un_semoclose); 14463786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "Open success\n"); 14473786Sarutz return (0); 14483786Sarutz 14493786Sarutz done: 14503786Sarutz mutex_exit(DCD_MUTEX); 14513786Sarutz sema_v(&un->un_semoclose); 14523786Sarutz return (rval); 14533786Sarutz 14543786Sarutz } 14553786Sarutz 14563786Sarutz /* 14573786Sarutz * Test if disk is ready and has a valid geometry. 14583786Sarutz */ 14593786Sarutz static int 14603786Sarutz dcd_ready_and_valid(dev_t dev, struct dcd_disk *un) 14613786Sarutz { 14623786Sarutz int rval = 1; 14633786Sarutz int g_error = 0; 14643786Sarutz 14653786Sarutz mutex_enter(DCD_MUTEX); 14663786Sarutz /* 14673786Sarutz * cmds outstanding 14683786Sarutz */ 14693786Sarutz if (un->un_ncmds == 0) { 14703786Sarutz (void) dcd_unit_ready(dev); 14713786Sarutz } 14723786Sarutz 14733786Sarutz /* 14743786Sarutz * If device is not yet ready here, inform it is offline 14753786Sarutz */ 14763786Sarutz if (un->un_state == DCD_STATE_NORMAL) { 14773786Sarutz rval = dcd_unit_ready(dev); 14783786Sarutz if (rval != 0 && rval != EACCES) { 14793786Sarutz dcd_offline(un, 1); 14803786Sarutz goto done; 14813786Sarutz } 14823786Sarutz } 14833786Sarutz 14843786Sarutz if (un->un_format_in_progress == 0) { 14853786Sarutz g_error = dcd_validate_geometry(un); 14863786Sarutz } 14873786Sarutz 14883786Sarutz /* 14893786Sarutz * check if geometry was valid. We don't check the validity of 14903786Sarutz * geometry for CDROMS. 14913786Sarutz */ 14923786Sarutz 14933786Sarutz if (g_error == DCD_BAD_LABEL) { 14943786Sarutz rval = 1; 14953786Sarutz goto done; 14963786Sarutz } 14973786Sarutz 14983786Sarutz 14993786Sarutz /* 15003786Sarutz * the state has changed; inform the media watch routines 15013786Sarutz */ 15023786Sarutz un->un_mediastate = DKIO_INSERTED; 15033786Sarutz cv_broadcast(&un->un_state_cv); 15043786Sarutz rval = 0; 15053786Sarutz 15063786Sarutz done: 15073786Sarutz mutex_exit(DCD_MUTEX); 15083786Sarutz return (rval); 15093786Sarutz } 15103786Sarutz 15113786Sarutz 15123786Sarutz /*ARGSUSED*/ 15133786Sarutz static int 15143786Sarutz dcdclose(dev_t dev, int flag, int otyp, cred_t *cred_p) 15153786Sarutz { 15163786Sarutz uchar_t *cp; 15173786Sarutz int i; 15183786Sarutz 15193786Sarutz GET_SOFT_STATE(dev); 15203786Sarutz 15213786Sarutz 15223786Sarutz if (otyp >= OTYPCNT) 15233786Sarutz return (ENXIO); 15243786Sarutz 15253786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 15263786Sarutz "close of part %d type %d\n", 15273786Sarutz part, otyp); 15283786Sarutz sema_p(&un->un_semoclose); 15293786Sarutz 15303786Sarutz mutex_enter(DCD_MUTEX); 15313786Sarutz 15323786Sarutz if (un->un_exclopen & (1<<part)) { 15333786Sarutz un->un_exclopen &= ~(1<<part); 15343786Sarutz } 15353786Sarutz 15363786Sarutz if (otyp == OTYP_LYR) { 15373786Sarutz un->un_ocmap.lyropen[part] -= 1; 15383786Sarutz } else { 15393786Sarutz un->un_ocmap.regopen[otyp] &= ~(1<<part); 15403786Sarutz } 15413786Sarutz 15423786Sarutz cp = &un->un_ocmap.chkd[0]; 15433786Sarutz while (cp < &un->un_ocmap.chkd[OCSIZE]) { 15443786Sarutz if (*cp != (uchar_t)0) { 15453786Sarutz break; 15463786Sarutz } 15473786Sarutz cp++; 15483786Sarutz } 15493786Sarutz 15503786Sarutz if (cp == &un->un_ocmap.chkd[OCSIZE]) { 15513786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "last close\n"); 15523786Sarutz if (un->un_state == DCD_STATE_OFFLINE) { 15533786Sarutz dcd_offline(un, 1); 15543786Sarutz } 15553786Sarutz 15563786Sarutz mutex_exit(DCD_MUTEX); 15573786Sarutz (void) cmlb_close(un->un_dklbhandle, 0); 15583786Sarutz 15593786Sarutz _NOTE(NO_COMPETING_THREADS_NOW); 15603786Sarutz if (un->un_stats) { 15613786Sarutz kstat_delete(un->un_stats); 15623786Sarutz un->un_stats = 0; 15633786Sarutz } 15643786Sarutz for (i = 0; i < NDKMAP; i++) { 15653786Sarutz if (un->un_pstats[i]) { 15663786Sarutz kstat_delete(un->un_pstats[i]); 15673786Sarutz un->un_pstats[i] = (kstat_t *)0; 15683786Sarutz } 15693786Sarutz } 15703786Sarutz 15713786Sarutz if (un->un_errstats) { 15723786Sarutz kstat_delete(un->un_errstats); 15733786Sarutz un->un_errstats = (kstat_t *)0; 15743786Sarutz } 15753786Sarutz mutex_enter(DCD_MUTEX); 15763786Sarutz 15773786Sarutz #ifndef lint 15783786Sarutz _NOTE(COMPETING_THREADS_NOW); 15793786Sarutz #endif 15803786Sarutz } 15813786Sarutz 15823786Sarutz mutex_exit(DCD_MUTEX); 15833786Sarutz sema_v(&un->un_semoclose); 15843786Sarutz return (0); 15853786Sarutz } 15863786Sarutz 15873786Sarutz static void 15883786Sarutz dcd_offline(struct dcd_disk *un, int bechatty) 15893786Sarutz { 15903786Sarutz if (bechatty) 15913786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, "offline\n"); 15923786Sarutz 15933786Sarutz mutex_exit(DCD_MUTEX); 15943786Sarutz cmlb_invalidate(un->un_dklbhandle, 0); 15953786Sarutz mutex_enter(DCD_MUTEX); 15963786Sarutz } 15973786Sarutz 15983786Sarutz /* 15993786Sarutz * Given the device number return the devinfo pointer 16003786Sarutz * from the scsi_device structure. 16013786Sarutz */ 16023786Sarutz /*ARGSUSED*/ 16033786Sarutz static int 16043786Sarutz dcdinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 16053786Sarutz { 16063786Sarutz dev_t dev; 16073786Sarutz struct dcd_disk *un; 16083786Sarutz int instance, error; 16093786Sarutz 16103786Sarutz 16113786Sarutz switch (infocmd) { 16123786Sarutz case DDI_INFO_DEVT2DEVINFO: 16133786Sarutz dev = (dev_t)arg; 16143786Sarutz instance = DCDUNIT(dev); 16153786Sarutz if ((un = ddi_get_soft_state(dcd_state, instance)) == NULL) 16163786Sarutz return (DDI_FAILURE); 16173786Sarutz *result = (void *) DCD_DEVINFO; 16183786Sarutz error = DDI_SUCCESS; 16193786Sarutz break; 16203786Sarutz case DDI_INFO_DEVT2INSTANCE: 16213786Sarutz dev = (dev_t)arg; 16223786Sarutz instance = DCDUNIT(dev); 16233786Sarutz *result = (void *)(uintptr_t)instance; 16243786Sarutz error = DDI_SUCCESS; 16253786Sarutz break; 16263786Sarutz default: 16273786Sarutz error = DDI_FAILURE; 16283786Sarutz } 16293786Sarutz return (error); 16303786Sarutz } 16313786Sarutz 16323786Sarutz /* 16333786Sarutz * property operation routine. return the number of blocks for the partition 16343786Sarutz * in question or forward the request to the propery facilities. 16353786Sarutz */ 16363786Sarutz static int 16373786Sarutz dcd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 16383786Sarutz char *name, caddr_t valuep, int *lengthp) 16393786Sarutz { 16403786Sarutz struct dcd_disk *un; 16417224Scth 16427224Scth if ((un = ddi_get_soft_state(dcd_state, ddi_get_instance(dip))) == NULL) 16433786Sarutz return (ddi_prop_op(dev, dip, prop_op, mod_flags, 16443786Sarutz name, valuep, lengthp)); 16457224Scth 16467224Scth return (cmlb_prop_op(un->un_dklbhandle, 16477224Scth dev, dip, prop_op, mod_flags, name, valuep, lengthp, 16487224Scth DCDPART(dev), NULL)); 16493786Sarutz } 16503786Sarutz 16513786Sarutz /* 16523786Sarutz * These routines perform raw i/o operations. 16533786Sarutz */ 16543786Sarutz /*ARGSUSED*/ 16553786Sarutz void 16563786Sarutz dcduscsimin(struct buf *bp) 16573786Sarutz { 16583786Sarutz 16593786Sarutz } 16603786Sarutz 16613786Sarutz 16623786Sarutz static void 16633786Sarutz dcdmin(struct buf *bp) 16643786Sarutz { 16653786Sarutz struct dcd_disk *un; 16663786Sarutz int instance; 16673786Sarutz minor_t minor = getminor(bp->b_edev); 16683786Sarutz instance = minor >> DCDUNIT_SHIFT; 16693786Sarutz un = ddi_get_soft_state(dcd_state, instance); 16703786Sarutz 16713786Sarutz if (bp->b_bcount > un->un_max_xfer_size) 16723786Sarutz bp->b_bcount = un->un_max_xfer_size; 16733786Sarutz } 16743786Sarutz 16753786Sarutz 16763786Sarutz /* ARGSUSED2 */ 16773786Sarutz static int 16783786Sarutz dcdread(dev_t dev, struct uio *uio, cred_t *cred_p) 16793786Sarutz { 16803786Sarutz int secmask; 16813786Sarutz GET_SOFT_STATE(dev); 16823786Sarutz #ifdef lint 16833786Sarutz part = part; 16843786Sarutz #endif /* lint */ 16853786Sarutz secmask = un->un_secsize - 1; 16863786Sarutz 16873786Sarutz if (uio->uio_loffset & ((offset_t)(secmask))) { 16883786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 16893786Sarutz "file offset not modulo %d\n", 16903786Sarutz un->un_secsize); 16913786Sarutz return (EINVAL); 16923786Sarutz } else if (uio->uio_iov->iov_len & (secmask)) { 16933786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 16943786Sarutz "transfer length not modulo %d\n", un->un_secsize); 16953786Sarutz return (EINVAL); 16963786Sarutz } 16973786Sarutz return (physio(dcdstrategy, (struct buf *)0, dev, B_READ, dcdmin, uio)); 16983786Sarutz } 16993786Sarutz 17003786Sarutz /* ARGSUSED2 */ 17013786Sarutz static int 17023786Sarutz dcdaread(dev_t dev, struct aio_req *aio, cred_t *cred_p) 17033786Sarutz { 17043786Sarutz int secmask; 17053786Sarutz struct uio *uio = aio->aio_uio; 17063786Sarutz GET_SOFT_STATE(dev); 17073786Sarutz #ifdef lint 17083786Sarutz part = part; 17093786Sarutz #endif /* lint */ 17103786Sarutz secmask = un->un_secsize - 1; 17113786Sarutz 17123786Sarutz if (uio->uio_loffset & ((offset_t)(secmask))) { 17133786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 17143786Sarutz "file offset not modulo %d\n", 17153786Sarutz un->un_secsize); 17163786Sarutz return (EINVAL); 17173786Sarutz } else if (uio->uio_iov->iov_len & (secmask)) { 17183786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 17193786Sarutz "transfer length not modulo %d\n", un->un_secsize); 17203786Sarutz return (EINVAL); 17213786Sarutz } 17223786Sarutz return (aphysio(dcdstrategy, anocancel, dev, B_READ, dcdmin, aio)); 17233786Sarutz } 17243786Sarutz 17253786Sarutz /* ARGSUSED2 */ 17263786Sarutz static int 17273786Sarutz dcdwrite(dev_t dev, struct uio *uio, cred_t *cred_p) 17283786Sarutz { 17293786Sarutz int secmask; 17303786Sarutz GET_SOFT_STATE(dev); 17313786Sarutz #ifdef lint 17323786Sarutz part = part; 17333786Sarutz #endif /* lint */ 17343786Sarutz secmask = un->un_secsize - 1; 17353786Sarutz 17363786Sarutz if (uio->uio_loffset & ((offset_t)(secmask))) { 17373786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 17383786Sarutz "file offset not modulo %d\n", 17393786Sarutz un->un_secsize); 17403786Sarutz return (EINVAL); 17413786Sarutz } else if (uio->uio_iov->iov_len & (secmask)) { 17423786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 17433786Sarutz "transfer length not modulo %d\n", un->un_secsize); 17443786Sarutz return (EINVAL); 17453786Sarutz } 17463786Sarutz return (physio(dcdstrategy, (struct buf *)0, dev, B_WRITE, dcdmin, 17473786Sarutz uio)); 17483786Sarutz } 17493786Sarutz 17503786Sarutz /* ARGSUSED2 */ 17513786Sarutz static int 17523786Sarutz dcdawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p) 17533786Sarutz { 17543786Sarutz int secmask; 17553786Sarutz struct uio *uio = aio->aio_uio; 17563786Sarutz GET_SOFT_STATE(dev); 17573786Sarutz #ifdef lint 17583786Sarutz part = part; 17593786Sarutz #endif /* lint */ 17603786Sarutz secmask = un->un_secsize - 1; 17613786Sarutz 17623786Sarutz if (uio->uio_loffset & ((offset_t)(secmask))) { 17633786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 17643786Sarutz "file offset not modulo %d\n", 17653786Sarutz un->un_secsize); 17663786Sarutz return (EINVAL); 17673786Sarutz } else if (uio->uio_iov->iov_len & (secmask)) { 17683786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 17693786Sarutz "transfer length not modulo %d\n", un->un_secsize); 17703786Sarutz return (EINVAL); 17713786Sarutz } 17723786Sarutz return (aphysio(dcdstrategy, anocancel, dev, B_WRITE, dcdmin, aio)); 17733786Sarutz } 17743786Sarutz 17753786Sarutz /* 17763786Sarutz * strategy routine 17773786Sarutz */ 17783786Sarutz static int 17793786Sarutz dcdstrategy(struct buf *bp) 17803786Sarutz { 17813786Sarutz struct dcd_disk *un; 17823786Sarutz struct diskhd *dp; 17833786Sarutz int i; 17843786Sarutz minor_t minor = getminor(bp->b_edev); 17853786Sarutz diskaddr_t p_lblksrt; 17863786Sarutz diskaddr_t lblocks; 17873786Sarutz diskaddr_t bn; 17883786Sarutz 17893786Sarutz if ((un = ddi_get_soft_state(dcd_state, 17903786Sarutz minor >> DCDUNIT_SHIFT)) == NULL || 17913786Sarutz un->un_state == DCD_STATE_DUMPING || 17923786Sarutz ((un->un_state & DCD_STATE_FATAL) == DCD_STATE_FATAL)) { 17933786Sarutz SET_BP_ERROR(bp, ((un) ? ENXIO : EIO)); 17943786Sarutz error: 17953786Sarutz bp->b_resid = bp->b_bcount; 17963786Sarutz biodone(bp); 17973786Sarutz return (0); 17983786Sarutz } 17993786Sarutz 18003786Sarutz /* 18013786Sarutz * If the request size (buf->b_bcount)is greater than the size 18023786Sarutz * (un->un_max_xfer_size) supported by the target driver fail 18033786Sarutz * the request with EINVAL error code. 18043786Sarutz * 18053786Sarutz * We are not supposed to receive requests exceeding 18063786Sarutz * un->un_max_xfer_size size because the caller is expected to 18073786Sarutz * check what is the maximum size that is supported by this 18083786Sarutz * driver either through ioctl or dcdmin routine(which is private 18093786Sarutz * to this driver). 18103786Sarutz * But we have seen cases (like meta driver(md))where dcdstrategy 18113786Sarutz * called with more than supported size and cause data corruption. 18123786Sarutz */ 18133786Sarutz 18143786Sarutz if (bp->b_bcount > un->un_max_xfer_size) { 18153786Sarutz SET_BP_ERROR(bp, EINVAL); 18163786Sarutz goto error; 18173786Sarutz } 18183786Sarutz 18193786Sarutz TRACE_2(TR_FAC_DADA, TR_DCDSTRATEGY_START, 18203786Sarutz "dcdstrategy_start: bp 0x%p un 0x%p", bp, un); 18213786Sarutz 18223786Sarutz /* 18233786Sarutz * Commands may sneak in while we released the mutex in 18243786Sarutz * DDI_SUSPEND, we should block new commands. 18253786Sarutz */ 18263786Sarutz mutex_enter(DCD_MUTEX); 18273786Sarutz while (un->un_state == DCD_STATE_SUSPENDED) { 18283786Sarutz cv_wait(&un->un_suspend_cv, DCD_MUTEX); 18293786Sarutz } 18303786Sarutz 18313786Sarutz if (un->un_state == DCD_STATE_PM_SUSPENDED) { 18323786Sarutz mutex_exit(DCD_MUTEX); 18333786Sarutz (void) pm_idle_component(DCD_DEVINFO, 0); 18343786Sarutz if (pm_raise_power(DCD_DEVINFO, 0, 18357224Scth DCD_DEVICE_ACTIVE) != DDI_SUCCESS) { 18363786Sarutz SET_BP_ERROR(bp, EIO); 18373786Sarutz goto error; 18383786Sarutz } 18393786Sarutz mutex_enter(DCD_MUTEX); 18403786Sarutz } 18413786Sarutz mutex_exit(DCD_MUTEX); 18423786Sarutz 18433786Sarutz /* 18443786Sarutz * Map-in the buffer in case starting address is not word aligned. 18453786Sarutz */ 18463786Sarutz 18473786Sarutz if (((uintptr_t)bp->b_un.b_addr) & 0x1) 18483786Sarutz bp_mapin(bp); 18493786Sarutz 18503786Sarutz bp->b_flags &= ~(B_DONE|B_ERROR); 18513786Sarutz bp->b_resid = 0; 18523786Sarutz bp->av_forw = 0; 18533786Sarutz 18543786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 18553786Sarutz "bp->b_bcount %lx\n", bp->b_bcount); 18563786Sarutz 18573786Sarutz if (bp != un->un_sbufp) { 18583786Sarutz validated: if (cmlb_partinfo(un->un_dklbhandle, 18593786Sarutz minor & DCDPART_MASK, 18603786Sarutz &lblocks, 18613786Sarutz &p_lblksrt, 18623786Sarutz NULL, 18633786Sarutz NULL, 18643786Sarutz 0) == 0) { 18653786Sarutz 18663786Sarutz bn = dkblock(bp); 18673786Sarutz 18683786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 18693786Sarutz "dkblock(bp) is %llu\n", bn); 18703786Sarutz 18713786Sarutz i = 0; 18723786Sarutz if (bn < 0) { 18733786Sarutz i = -1; 18743786Sarutz } else if (bn >= lblocks) { 18753786Sarutz /* 18763786Sarutz * For proper comparison, file system block 18773786Sarutz * number has to be scaled to actual CD 18783786Sarutz * transfer size. 18793786Sarutz * Since all the CDROM operations 18803786Sarutz * that have Sun Labels are in the correct 18813786Sarutz * block size this will work for CD's. This 18823786Sarutz * will have to change when we have different 18833786Sarutz * sector sizes. 18843786Sarutz * 18853786Sarutz * if bn == lblocks, 18863786Sarutz * Not an error, resid == count 18873786Sarutz */ 18883786Sarutz if (bn > lblocks) { 18893786Sarutz i = -1; 18903786Sarutz } else { 18913786Sarutz i = 1; 18923786Sarutz } 18933786Sarutz } else if (bp->b_bcount & (un->un_secsize-1)) { 18943786Sarutz /* 18953786Sarutz * This should really be: 18963786Sarutz * 18973786Sarutz * ... if (bp->b_bcount & (un->un_lbasize-1)) 18983786Sarutz * 18993786Sarutz */ 19003786Sarutz i = -1; 19013786Sarutz } else { 19023786Sarutz if (!bp->b_bcount) { 19033786Sarutz printf("Waring : Zero read or Write\n"); 19043786Sarutz goto error; 19053786Sarutz } 19063786Sarutz /* 19073786Sarutz * sort by absolute block number. 19083786Sarutz */ 19093786Sarutz bp->b_resid = bn; 19103786Sarutz bp->b_resid += p_lblksrt; 19113786Sarutz /* 19123786Sarutz * zero out av_back - this will be a signal 19133786Sarutz * to dcdstart to go and fetch the resources 19143786Sarutz */ 19153786Sarutz bp->av_back = NO_PKT_ALLOCATED; 19163786Sarutz } 19173786Sarutz 19183786Sarutz /* 19193786Sarutz * Check to see whether or not we are done 19203786Sarutz * (with or without errors). 19213786Sarutz */ 19223786Sarutz 19233786Sarutz if (i != 0) { 19243786Sarutz if (i < 0) { 19253786Sarutz bp->b_flags |= B_ERROR; 19263786Sarutz } 19273786Sarutz goto error; 19283786Sarutz } 19293786Sarutz } else { 19303786Sarutz /* 19313786Sarutz * opened in NDELAY/NONBLOCK mode? 19323786Sarutz * Check if disk is ready and has a valid geometry 19333786Sarutz */ 19343786Sarutz if (dcd_ready_and_valid(bp->b_edev, un) == 0) { 19353786Sarutz goto validated; 19363786Sarutz } else { 19373786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 19383786Sarutz "i/o to invalid geometry\n"); 19393786Sarutz SET_BP_ERROR(bp, EIO); 19403786Sarutz goto error; 19413786Sarutz } 19423786Sarutz } 19433786Sarutz } else if (BP_HAS_NO_PKT(bp)) { 19443786Sarutz struct udcd_cmd *tscmdp; 19453786Sarutz struct dcd_cmd *tcmdp; 19463786Sarutz /* 19473786Sarutz * This indicates that it is a special buffer 19483786Sarutz * This could be a udcd-cmd and hence call bp_mapin just 19493786Sarutz * in case that it could be a PIO command issued. 19503786Sarutz */ 19513786Sarutz tscmdp = (struct udcd_cmd *)bp->b_forw; 19523786Sarutz tcmdp = tscmdp->udcd_cmd; 19533786Sarutz if ((tcmdp->cmd != ATA_READ_DMA) && (tcmdp->cmd != 0xc9) && 19543786Sarutz (tcmdp->cmd != ATA_WRITE_DMA) && (tcmdp->cmd != 0xcb) && 19553786Sarutz (tcmdp->cmd != IDENTIFY_DMA) && 19563786Sarutz (tcmdp->cmd != ATA_FLUSH_CACHE)) { 19573786Sarutz bp_mapin(bp); 19583786Sarutz } 19593786Sarutz } 19603786Sarutz 19613786Sarutz /* 19623786Sarutz * We are doing it a bit non-standard. That is, the 19633786Sarutz * head of the b_actf chain is *not* the active command- 19643786Sarutz * it is just the head of the wait queue. The reason 19653786Sarutz * we do this is that the head of the b_actf chain is 19663786Sarutz * guaranteed to not be moved by disksort(), so that 19673786Sarutz * our restart command (pointed to by 19683786Sarutz * b_forw) and the head of the wait queue (b_actf) can 19693786Sarutz * have resources granted without it getting lost in 19703786Sarutz * the queue at some later point (where we would have 19713786Sarutz * to go and look for it). 19723786Sarutz */ 19733786Sarutz mutex_enter(DCD_MUTEX); 19743786Sarutz 19753786Sarutz DCD_DO_KSTATS(un, kstat_waitq_enter, bp); 19763786Sarutz 19773786Sarutz dp = &un->un_utab; 19783786Sarutz 19793786Sarutz if (dp->b_actf == NULL) { 19803786Sarutz dp->b_actf = bp; 19813786Sarutz dp->b_actl = bp; 19823786Sarutz } else if ((un->un_state == DCD_STATE_SUSPENDED) && 19833786Sarutz bp == un->un_sbufp) { 19843786Sarutz bp->b_actf = dp->b_actf; 19853786Sarutz dp->b_actf = bp; 19863786Sarutz } else { 19873786Sarutz TRACE_3(TR_FAC_DADA, TR_DCDSTRATEGY_DISKSORT_START, 19883786Sarutz "dcdstrategy_disksort_start: dp 0x%p bp 0x%p un 0x%p", 19893786Sarutz dp, bp, un); 19903786Sarutz disksort(dp, bp); 19913786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDSTRATEGY_DISKSORT_END, 19923786Sarutz "dcdstrategy_disksort_end"); 19933786Sarutz } 19943786Sarutz 19953786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 19963786Sarutz "ncmd %x , throttle %x, forw 0x%p\n", 19973786Sarutz un->un_ncmds, un->un_throttle, (void *)dp->b_forw); 19983786Sarutz ASSERT(un->un_ncmds >= 0); 19993786Sarutz ASSERT(un->un_throttle >= 0); 20003786Sarutz if ((un->un_ncmds < un->un_throttle) && (dp->b_forw == NULL)) { 20013786Sarutz dcdstart(un); 20023786Sarutz } else if (BP_HAS_NO_PKT(dp->b_actf)) { 20033786Sarutz struct buf *cmd_bp; 20043786Sarutz 20053786Sarutz cmd_bp = dp->b_actf; 20063786Sarutz cmd_bp->av_back = ALLOCATING_PKT; 20073786Sarutz mutex_exit(DCD_MUTEX); 20083786Sarutz /* 20093786Sarutz * try and map this one 20103786Sarutz */ 20113786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDSTRATEGY_SMALL_WINDOW_START, 20123786Sarutz "dcdstrategy_small_window_call (begin)"); 20133786Sarutz 20143786Sarutz make_dcd_cmd(un, cmd_bp, NULL_FUNC); 20153786Sarutz 20163786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDSTRATEGY_SMALL_WINDOW_END, 20173786Sarutz "dcdstrategy_small_window_call (end)"); 20183786Sarutz 20193786Sarutz /* 20203786Sarutz * there is a small window where the active cmd 20213786Sarutz * completes before make_dcd_cmd returns. 20223786Sarutz * consequently, this cmd never gets started so 20233786Sarutz * we start it from here 20243786Sarutz */ 20253786Sarutz mutex_enter(DCD_MUTEX); 20263786Sarutz if ((un->un_ncmds < un->un_throttle) && 20273786Sarutz (dp->b_forw == NULL)) { 20283786Sarutz dcdstart(un); 20293786Sarutz } 20303786Sarutz } 20313786Sarutz mutex_exit(DCD_MUTEX); 20323786Sarutz 20333786Sarutz done: 20343786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDSTRATEGY_END, "dcdstrategy_end"); 20353786Sarutz return (0); 20363786Sarutz } 20373786Sarutz 20383786Sarutz 20393786Sarutz /* 20403786Sarutz * Unit start and Completion 20413786Sarutz * NOTE: we assume that the caller has at least checked for: 20423786Sarutz * (un->un_ncmds < un->un_throttle) 20433786Sarutz * if not, there is no real harm done, dcd_transport() will 20443786Sarutz * return BUSY 20453786Sarutz */ 20463786Sarutz static void 20473786Sarutz dcdstart(struct dcd_disk *un) 20483786Sarutz { 20493786Sarutz int status, sort_key; 20503786Sarutz struct buf *bp; 20513786Sarutz struct diskhd *dp; 20523786Sarutz uchar_t state = un->un_last_state; 20533786Sarutz 20543786Sarutz TRACE_1(TR_FAC_DADA, TR_DCDSTART_START, "dcdstart_start: un 0x%p", un); 20553786Sarutz 20563786Sarutz retry: 20573786Sarutz ASSERT(mutex_owned(DCD_MUTEX)); 20583786Sarutz 20593786Sarutz dp = &un->un_utab; 20603786Sarutz if (((bp = dp->b_actf) == NULL) || (bp->av_back == ALLOCATING_PKT) || 20613786Sarutz (dp->b_forw != NULL)) { 20623786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDSTART_NO_WORK_END, 20633786Sarutz "dcdstart_end (no work)"); 20643786Sarutz return; 20653786Sarutz } 20663786Sarutz 20673786Sarutz /* 20683786Sarutz * remove from active queue 20693786Sarutz */ 20703786Sarutz dp->b_actf = bp->b_actf; 20713786Sarutz bp->b_actf = 0; 20723786Sarutz 20733786Sarutz /* 20743786Sarutz * increment ncmds before calling dcd_transport because dcdintr 20753786Sarutz * may be called before we return from dcd_transport! 20763786Sarutz */ 20773786Sarutz un->un_ncmds++; 20783786Sarutz 20793786Sarutz /* 20803786Sarutz * If measuring stats, mark exit from wait queue and 20813786Sarutz * entrance into run 'queue' if and only if we are 20823786Sarutz * going to actually start a command. 20833786Sarutz * Normally the bp already has a packet at this point 20843786Sarutz */ 20853786Sarutz DCD_DO_KSTATS(un, kstat_waitq_to_runq, bp); 20863786Sarutz 20873786Sarutz mutex_exit(DCD_MUTEX); 20883786Sarutz 20893786Sarutz if (BP_HAS_NO_PKT(bp)) { 20903786Sarutz make_dcd_cmd(un, bp, dcdrunout); 20913786Sarutz if (BP_HAS_NO_PKT(bp) && !(bp->b_flags & B_ERROR)) { 20923786Sarutz mutex_enter(DCD_MUTEX); 20933786Sarutz DCD_DO_KSTATS(un, kstat_runq_back_to_waitq, bp); 20943786Sarutz 20953786Sarutz bp->b_actf = dp->b_actf; 20963786Sarutz dp->b_actf = bp; 20973786Sarutz New_state(un, DCD_STATE_RWAIT); 20983786Sarutz un->un_ncmds--; 20993786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDSTART_NO_RESOURCES_END, 21003786Sarutz "dcdstart_end (No Resources)"); 21013786Sarutz goto done; 21023786Sarutz 21033786Sarutz } else if (bp->b_flags & B_ERROR) { 21043786Sarutz mutex_enter(DCD_MUTEX); 21053786Sarutz DCD_DO_KSTATS(un, kstat_runq_exit, bp); 21063786Sarutz 21073786Sarutz un->un_ncmds--; 21083786Sarutz bp->b_resid = bp->b_bcount; 21093786Sarutz if (bp->b_error == 0) { 21103786Sarutz SET_BP_ERROR(bp, EIO); 21113786Sarutz } 21123786Sarutz 21133786Sarutz /* 21143786Sarutz * restore old state 21153786Sarutz */ 21163786Sarutz un->un_state = un->un_last_state; 21173786Sarutz un->un_last_state = state; 21183786Sarutz 21193786Sarutz mutex_exit(DCD_MUTEX); 21203786Sarutz 21213786Sarutz biodone(bp); 21223786Sarutz mutex_enter(DCD_MUTEX); 21233786Sarutz if (un->un_state == DCD_STATE_SUSPENDED) { 21243786Sarutz cv_broadcast(&un->un_disk_busy_cv); 21253786Sarutz } 21263786Sarutz 21273786Sarutz if ((un->un_ncmds < un->un_throttle) && 21283786Sarutz (dp->b_forw == NULL)) { 21293786Sarutz goto retry; 21303786Sarutz } else { 21313786Sarutz goto done; 21323786Sarutz } 21333786Sarutz } 21343786Sarutz } 21353786Sarutz 21363786Sarutz /* 21373786Sarutz * Restore resid from the packet, b_resid had been the 21383786Sarutz * disksort key. 21393786Sarutz */ 21403786Sarutz sort_key = bp->b_resid; 21413786Sarutz bp->b_resid = BP_PKT(bp)->pkt_resid; 21423786Sarutz BP_PKT(bp)->pkt_resid = 0; 21433786Sarutz 21443786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 21453786Sarutz "bp->b_resid %lx, pkt_resid %lx\n", 21463786Sarutz bp->b_resid, BP_PKT(bp)->pkt_resid); 21473786Sarutz 21483786Sarutz /* 21493786Sarutz * We used to check whether or not to try and link commands here. 21503786Sarutz * Since we have found that there is no performance improvement 21513786Sarutz * for linked commands, this has not made much sense. 21523786Sarutz */ 21533786Sarutz if ((status = dcd_transport((struct dcd_pkt *)BP_PKT(bp))) 21543786Sarutz != TRAN_ACCEPT) { 21553786Sarutz mutex_enter(DCD_MUTEX); 21563786Sarutz un->un_ncmds--; 21573786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 21583786Sarutz "transport returned %x\n", status); 21593786Sarutz if (status == TRAN_BUSY) { 21603786Sarutz DCD_DO_ERRSTATS(un, dcd_transerrs); 21613786Sarutz DCD_DO_KSTATS(un, kstat_runq_back_to_waitq, bp); 21623786Sarutz dcd_handle_tran_busy(bp, dp, un); 21633786Sarutz if (un->un_ncmds > 0) { 21643786Sarutz bp->b_resid = sort_key; 21653786Sarutz } 21663786Sarutz } else { 21673786Sarutz DCD_DO_KSTATS(un, kstat_runq_exit, bp); 21683786Sarutz mutex_exit(DCD_MUTEX); 21693786Sarutz 21703786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 21713786Sarutz "transport rejected (%d)\n", 21723786Sarutz status); 21733786Sarutz SET_BP_ERROR(bp, EIO); 21743786Sarutz bp->b_resid = bp->b_bcount; 21753786Sarutz if (bp != un->un_sbufp) { 21763786Sarutz dcd_destroy_pkt(BP_PKT(bp)); 21773786Sarutz } 21783786Sarutz biodone(bp); 21793786Sarutz 21803786Sarutz mutex_enter(DCD_MUTEX); 21813786Sarutz if (un->un_state == DCD_STATE_SUSPENDED) { 21823786Sarutz cv_broadcast(&un->un_disk_busy_cv); 21833786Sarutz } 21843786Sarutz if ((un->un_ncmds < un->un_throttle) && 21853786Sarutz (dp->b_forw == NULL)) { 21863786Sarutz goto retry; 21873786Sarutz } 21883786Sarutz } 21893786Sarutz } else { 21903786Sarutz mutex_enter(DCD_MUTEX); 21913786Sarutz 21923786Sarutz if (dp->b_actf && BP_HAS_NO_PKT(dp->b_actf)) { 21933786Sarutz struct buf *cmd_bp; 21943786Sarutz 21953786Sarutz cmd_bp = dp->b_actf; 21963786Sarutz cmd_bp->av_back = ALLOCATING_PKT; 21973786Sarutz mutex_exit(DCD_MUTEX); 21983786Sarutz /* 21993786Sarutz * try and map this one 22003786Sarutz */ 22013786Sarutz TRACE_0(TR_FAC_DADA, TR_DCASTART_SMALL_WINDOW_START, 22023786Sarutz "dcdstart_small_window_start"); 22033786Sarutz 22043786Sarutz make_dcd_cmd(un, cmd_bp, NULL_FUNC); 22053786Sarutz 22063786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDSTART_SMALL_WINDOW_END, 22073786Sarutz "dcdstart_small_window_end"); 22083786Sarutz /* 22093786Sarutz * there is a small window where the active cmd 22103786Sarutz * completes before make_dcd_cmd returns. 22113786Sarutz * consequently, this cmd never gets started so 22123786Sarutz * we start it from here 22133786Sarutz */ 22143786Sarutz mutex_enter(DCD_MUTEX); 22153786Sarutz if ((un->un_ncmds < un->un_throttle) && 22163786Sarutz (dp->b_forw == NULL)) { 22173786Sarutz goto retry; 22183786Sarutz } 22193786Sarutz } 22203786Sarutz } 22213786Sarutz 22223786Sarutz done: 22233786Sarutz ASSERT(mutex_owned(DCD_MUTEX)); 22243786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDSTART_END, "dcdstart_end"); 22253786Sarutz } 22263786Sarutz 22273786Sarutz /* 22283786Sarutz * make_dcd_cmd: create a pkt 22293786Sarutz */ 22303786Sarutz static void 22313786Sarutz make_dcd_cmd(struct dcd_disk *un, struct buf *bp, int (*func)()) 22323786Sarutz { 22333786Sarutz auto int count, com, direction; 22343786Sarutz struct dcd_pkt *pkt; 22353786Sarutz int flags, tval; 22363786Sarutz 22373786Sarutz _NOTE(DATA_READABLE_WITHOUT_LOCK(dcd_disk::un_dp)) 22383786Sarutz TRACE_3(TR_FAC_DADA, TR_MAKE_DCD_CMD_START, 22393786Sarutz "make_dcd_cmd_start: un 0x%p bp 0x%p un 0x%p", un, bp, un); 22403786Sarutz 22413786Sarutz 22423786Sarutz flags = un->un_cmd_flags; 22433786Sarutz 22443786Sarutz if (bp != un->un_sbufp) { 22453786Sarutz int partition = DCDPART(bp->b_edev); 22463786Sarutz diskaddr_t p_lblksrt; 22473786Sarutz diskaddr_t lblocks; 22483786Sarutz long secnt; 22493786Sarutz uint32_t blkno; 22503786Sarutz int dkl_nblk, delta; 22513786Sarutz long resid; 22523786Sarutz 22533786Sarutz if (cmlb_partinfo(un->un_dklbhandle, 22543786Sarutz partition, 22553786Sarutz &lblocks, 22563786Sarutz &p_lblksrt, 22573786Sarutz NULL, 22583786Sarutz NULL, 22593786Sarutz 0) != NULL) { 22603786Sarutz lblocks = 0; 22613786Sarutz p_lblksrt = 0; 22623786Sarutz } 22633786Sarutz 22643786Sarutz dkl_nblk = (int)lblocks; 22653786Sarutz 22663786Sarutz /* 22673786Sarutz * Make sure we don't run off the end of a partition. 22683786Sarutz * 22693786Sarutz * Put this test here so that we can adjust b_count 22703786Sarutz * to accurately reflect the actual amount we are 22713786Sarutz * goint to transfer. 22723786Sarutz */ 22733786Sarutz 22743786Sarutz /* 22753786Sarutz * First, compute partition-relative block number 22763786Sarutz */ 22773786Sarutz blkno = dkblock(bp); 22783786Sarutz secnt = (bp->b_bcount + (un->un_secsize - 1)) >> un->un_secdiv; 22793786Sarutz count = MIN(secnt, dkl_nblk - blkno); 22803786Sarutz if (count != secnt) { 22813786Sarutz /* 22823786Sarutz * We have an overrun 22833786Sarutz */ 22843786Sarutz resid = (secnt - count) << un->un_secdiv; 22853786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 22863786Sarutz "overrun by %ld sectors\n", 22873786Sarutz secnt - count); 22883786Sarutz bp->b_bcount -= resid; 22893786Sarutz } else { 22903786Sarutz resid = 0; 22913786Sarutz } 22923786Sarutz 22933786Sarutz /* 22943786Sarutz * Adjust block number to absolute 22953786Sarutz */ 22963786Sarutz delta = (int)p_lblksrt; 22973786Sarutz blkno += delta; 22983786Sarutz 22993786Sarutz mutex_enter(DCD_MUTEX); 23003786Sarutz /* 23013786Sarutz * This is for devices having block size different from 23023786Sarutz * from DEV_BSIZE (e.g. 2K CDROMs). 23033786Sarutz */ 23043786Sarutz if (un->un_lbasize != un->un_secsize) { 23053786Sarutz blkno >>= un->un_blknoshift; 23063786Sarutz count >>= un->un_blknoshift; 23073786Sarutz } 23083786Sarutz mutex_exit(DCD_MUTEX); 23093786Sarutz 23103786Sarutz TRACE_0(TR_FAC_DADA, TR_MAKE_DCD_CMD_INIT_PKT_START, 23113786Sarutz "make_dcd_cmd_init_pkt_call (begin)"); 23123786Sarutz pkt = dcd_init_pkt(ROUTE, NULL, bp, 23133786Sarutz (uint32_t)sizeof (struct dcd_cmd), 23143786Sarutz un->un_cmd_stat_size, PP_LEN, PKT_CONSISTENT, 23153786Sarutz func, (caddr_t)un); 23163786Sarutz TRACE_1(TR_FAC_DADA, TR_MAKE_DCD_CMD_INIT_PKT_END, 23173786Sarutz "make_dcd_cmd_init_pkt_call (end): pkt 0x%p", pkt); 23183786Sarutz if (!pkt) { 23193786Sarutz bp->b_bcount += resid; 23203786Sarutz bp->av_back = NO_PKT_ALLOCATED; 23213786Sarutz TRACE_0(TR_FAC_DADA, 23223786Sarutz TR_MAKE_DCD_CMD_NO_PKT_ALLOCATED1_END, 23233786Sarutz "make_dcd_cmd_end (NO_PKT_ALLOCATED1)"); 23243786Sarutz return; 23253786Sarutz } 23263786Sarutz if (bp->b_flags & B_READ) { 23273786Sarutz if ((un->un_dp->options & DMA_SUPPORTTED) == 23283786Sarutz DMA_SUPPORTTED) { 23293786Sarutz com = ATA_READ_DMA; 23303786Sarutz } else { 23313786Sarutz if (un->un_dp->options & BLOCK_MODE) 23323786Sarutz com = ATA_READ_MULTIPLE; 23333786Sarutz else 23343786Sarutz com = ATA_READ; 23353786Sarutz } 23363786Sarutz direction = DATA_READ; 23373786Sarutz } else { 23383786Sarutz if ((un->un_dp->options & DMA_SUPPORTTED) == 23393786Sarutz DMA_SUPPORTTED) { 23403786Sarutz com = ATA_WRITE_DMA; 23413786Sarutz } else { 23423786Sarutz if (un->un_dp->options & BLOCK_MODE) 23433786Sarutz com = ATA_WRITE_MULTIPLE; 23443786Sarutz else 23453786Sarutz com = ATA_WRITE; 23463786Sarutz } 23473786Sarutz direction = DATA_WRITE; 23483786Sarutz } 23493786Sarutz 23503786Sarutz /* 23513786Sarutz * Save the resid in the packet, temporarily until 23523786Sarutz * we transport the command. 23533786Sarutz */ 23543786Sarutz pkt->pkt_resid = resid; 23553786Sarutz 23563786Sarutz makecommand(pkt, flags, com, blkno, ADD_LBA_MODE, 23573786Sarutz bp->b_bcount, direction, 0); 23583786Sarutz tval = dcd_io_time; 23593786Sarutz } else { 23603786Sarutz 23613786Sarutz struct udcd_cmd *scmd = (struct udcd_cmd *)bp->b_forw; 23623786Sarutz 23633786Sarutz /* 23643786Sarutz * set options 23653786Sarutz */ 23663786Sarutz if ((scmd->udcd_flags & UDCD_SILENT) && !(DEBUGGING)) { 23673786Sarutz flags |= FLAG_SILENT; 23683786Sarutz } 23693786Sarutz if (scmd->udcd_flags & UDCD_DIAGNOSE) 23703786Sarutz flags |= FLAG_DIAGNOSE; 23713786Sarutz 23723786Sarutz if (scmd->udcd_flags & UDCD_NOINTR) 23733786Sarutz flags |= FLAG_NOINTR; 23743786Sarutz 23753786Sarutz pkt = dcd_init_pkt(ROUTE, (struct dcd_pkt *)NULL, 23763786Sarutz (bp->b_bcount)? bp: NULL, 23773786Sarutz (uint32_t)sizeof (struct dcd_cmd), 23783786Sarutz 2, PP_LEN, PKT_CONSISTENT, func, (caddr_t)un); 23793786Sarutz 23803786Sarutz if (!pkt) { 23813786Sarutz bp->av_back = NO_PKT_ALLOCATED; 23823786Sarutz return; 23833786Sarutz } 23843786Sarutz 23853786Sarutz makecommand(pkt, 0, scmd->udcd_cmd->cmd, 23863786Sarutz scmd->udcd_cmd->sector_num.lba_num, 23873786Sarutz scmd->udcd_cmd->address_mode, 23883786Sarutz scmd->udcd_cmd->size, 23893786Sarutz scmd->udcd_cmd->direction, scmd->udcd_cmd->features); 23903786Sarutz 23913786Sarutz pkt->pkt_flags = flags; 23923786Sarutz if (scmd->udcd_timeout == 0) 23933786Sarutz tval = dcd_io_time; 23943786Sarutz else 23953786Sarutz tval = scmd->udcd_timeout; 23963786Sarutz /* UDAD interface should be decided. */ 23973786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 23983786Sarutz "udcd interface\n"); 23993786Sarutz } 24003786Sarutz 24013786Sarutz pkt->pkt_comp = dcdintr; 24023786Sarutz pkt->pkt_time = tval; 24033786Sarutz PKT_SET_BP(pkt, bp); 24043786Sarutz bp->av_back = (struct buf *)pkt; 24053786Sarutz 24063786Sarutz TRACE_0(TR_FAC_DADA, TR_MAKE_DCD_CMD_END, "make_dcd_cmd_end"); 24073786Sarutz } 24083786Sarutz 24093786Sarutz /* 24103786Sarutz * Command completion processing 24113786Sarutz */ 24123786Sarutz static void 24133786Sarutz dcdintr(struct dcd_pkt *pkt) 24143786Sarutz { 24153786Sarutz struct dcd_disk *un; 24163786Sarutz struct buf *bp; 24173786Sarutz int action; 24183786Sarutz int status; 24193786Sarutz 24203786Sarutz bp = PKT_GET_BP(pkt); 24213786Sarutz un = ddi_get_soft_state(dcd_state, DCDUNIT(bp->b_edev)); 24223786Sarutz 24233786Sarutz TRACE_1(TR_FAC_DADA, TR_DCDINTR_START, "dcdintr_start: un 0x%p", un); 24243786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdintr\n"); 24253786Sarutz 24263786Sarutz mutex_enter(DCD_MUTEX); 24273786Sarutz un->un_ncmds--; 24283786Sarutz DCD_DO_KSTATS(un, kstat_runq_exit, bp); 24293786Sarutz ASSERT(un->un_ncmds >= 0); 24303786Sarutz 24313786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 24323786Sarutz "reason %x and Status %x\n", pkt->pkt_reason, SCBP_C(pkt)); 24333786Sarutz 24343786Sarutz /* 24353786Sarutz * do most common case first 24363786Sarutz */ 24373786Sarutz if ((pkt->pkt_reason == CMD_CMPLT) && (SCBP_C(pkt) == 0)) { 24383786Sarutz int com = GETATACMD((struct dcd_cmd *)pkt->pkt_cdbp); 24393786Sarutz 24403786Sarutz if (un->un_state == DCD_STATE_OFFLINE) { 24413786Sarutz un->un_state = un->un_last_state; 24423786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_NOTE, 24433786Sarutz (const char *) diskokay); 24443786Sarutz } 24453786Sarutz /* 24463786Sarutz * If the command is a read or a write, and we have 24473786Sarutz * a non-zero pkt_resid, that is an error. We should 24483786Sarutz * attempt to retry the operation if possible. 24493786Sarutz */ 24503786Sarutz action = COMMAND_DONE; 24513786Sarutz if (pkt->pkt_resid && (com == ATA_READ || com == ATA_WRITE)) { 24523786Sarutz DCD_DO_ERRSTATS(un, dcd_harderrs); 24533786Sarutz if ((int)PKT_GET_RETRY_CNT(pkt) < dcd_retry_count) { 24543786Sarutz PKT_INCR_RETRY_CNT(pkt, 1); 24553786Sarutz action = QUE_COMMAND; 24563786Sarutz } else { 24573786Sarutz /* 24583786Sarutz * if we have exhausted retries 24593786Sarutz * a command with a residual is in error in 24603786Sarutz * this case. 24613786Sarutz */ 24623786Sarutz action = COMMAND_DONE_ERROR; 24633786Sarutz } 24643786Sarutz dcd_log(DCD_DEVINFO, dcd_label, 24653786Sarutz CE_WARN, "incomplete %s- %s\n", 24663786Sarutz (bp->b_flags & B_READ)? "read" : "write", 24673786Sarutz (action == QUE_COMMAND)? "retrying" : 24683786Sarutz "giving up"); 24693786Sarutz } 24703786Sarutz 24713786Sarutz /* 24723786Sarutz * pkt_resid will reflect, at this point, a residual 24733786Sarutz * of how many bytes left to be transferred there were 24743786Sarutz * from the actual scsi command. Add this to b_resid i.e 24753786Sarutz * the amount this driver could not see to transfer, 24763786Sarutz * to get the total number of bytes not transfered. 24773786Sarutz */ 24783786Sarutz if (action != QUE_COMMAND) { 24793786Sarutz bp->b_resid += pkt->pkt_resid; 24803786Sarutz } 24813786Sarutz 24823786Sarutz } else if (pkt->pkt_reason != CMD_CMPLT) { 24833786Sarutz action = dcd_handle_incomplete(un, bp); 24843786Sarutz } 24853786Sarutz 24863786Sarutz /* 24873786Sarutz * If we are in the middle of syncing or dumping, we have got 24883786Sarutz * here because dcd_transport has called us explictly after 24893786Sarutz * completing the command in a polled mode. We don't want to 24903786Sarutz * have a recursive call into dcd_transport again. 24913786Sarutz */ 24923786Sarutz if (ddi_in_panic() && (action == QUE_COMMAND)) { 24933786Sarutz action = COMMAND_DONE_ERROR; 24943786Sarutz } 24953786Sarutz 24963786Sarutz /* 24973786Sarutz * save pkt reason; consecutive failures are not reported unless 24983786Sarutz * fatal 24993786Sarutz * do not reset last_pkt_reason when the cmd was retried and 25003786Sarutz * succeeded because 25013786Sarutz * there maybe more commands comming back with last_pkt_reason 25023786Sarutz */ 25033786Sarutz if ((un->un_last_pkt_reason != pkt->pkt_reason) && 25043786Sarutz ((pkt->pkt_reason != CMD_CMPLT) || 25053786Sarutz (PKT_GET_RETRY_CNT(pkt) == 0))) { 25063786Sarutz un->un_last_pkt_reason = pkt->pkt_reason; 25073786Sarutz } 25083786Sarutz 25093786Sarutz switch (action) { 25103786Sarutz case COMMAND_DONE_ERROR: 25113786Sarutz error: 25123786Sarutz if (bp->b_resid == 0) { 25133786Sarutz bp->b_resid = bp->b_bcount; 25143786Sarutz } 25153786Sarutz if (bp->b_error == 0) { 25163786Sarutz struct dcd_cmd *cdbp = (struct dcd_cmd *)pkt->pkt_cdbp; 25173786Sarutz if (cdbp->cmd == ATA_FLUSH_CACHE && 25183786Sarutz (pkt->pkt_scbp[0] & STATUS_ATA_ERR) && 25193786Sarutz (pkt->pkt_scbp[1] & ERR_ABORT)) { 25203786Sarutz SET_BP_ERROR(bp, ENOTSUP); 25213786Sarutz un->un_flush_not_supported = 1; 25223786Sarutz } else { 25233786Sarutz SET_BP_ERROR(bp, EIO); 25243786Sarutz } 25253786Sarutz } 25263786Sarutz bp->b_flags |= B_ERROR; 25273786Sarutz /*FALLTHROUGH*/ 25283786Sarutz case COMMAND_DONE: 25293786Sarutz dcddone_and_mutex_exit(un, bp); 25303786Sarutz 25313786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDINTR_COMMAND_DONE_END, 25323786Sarutz "dcdintr_end (COMMAND_DONE)"); 25333786Sarutz return; 25343786Sarutz 25353786Sarutz case QUE_COMMAND: 25363786Sarutz if (un->un_ncmds >= un->un_throttle) { 25373786Sarutz struct diskhd *dp = &un->un_utab; 25383786Sarutz 25393786Sarutz bp->b_actf = dp->b_actf; 25403786Sarutz dp->b_actf = bp; 25413786Sarutz 25423786Sarutz DCD_DO_KSTATS(un, kstat_waitq_enter, bp); 25433786Sarutz 25443786Sarutz mutex_exit(DCD_MUTEX); 25453786Sarutz goto exit; 25463786Sarutz } 25473786Sarutz 25483786Sarutz un->un_ncmds++; 25493786Sarutz /* reset the pkt reason again */ 25503786Sarutz pkt->pkt_reason = 0; 25513786Sarutz DCD_DO_KSTATS(un, kstat_runq_enter, bp); 25523786Sarutz mutex_exit(DCD_MUTEX); 25533786Sarutz if ((status = dcd_transport(BP_PKT(bp))) != TRAN_ACCEPT) { 25543786Sarutz struct diskhd *dp = &un->un_utab; 25553786Sarutz 25563786Sarutz mutex_enter(DCD_MUTEX); 25573786Sarutz un->un_ncmds--; 25583786Sarutz if (status == TRAN_BUSY) { 25593786Sarutz DCD_DO_KSTATS(un, kstat_runq_back_to_waitq, bp); 25603786Sarutz dcd_handle_tran_busy(bp, dp, un); 25613786Sarutz mutex_exit(DCD_MUTEX); 25623786Sarutz goto exit; 25633786Sarutz } 25643786Sarutz DCD_DO_ERRSTATS(un, dcd_transerrs); 25653786Sarutz DCD_DO_KSTATS(un, kstat_runq_exit, bp); 25663786Sarutz 25673786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 25683786Sarutz "requeue of command fails (%x)\n", status); 25693786Sarutz SET_BP_ERROR(bp, EIO); 25703786Sarutz bp->b_resid = bp->b_bcount; 25713786Sarutz 25723786Sarutz dcddone_and_mutex_exit(un, bp); 25733786Sarutz goto exit; 25743786Sarutz } 25753786Sarutz break; 25763786Sarutz 25773786Sarutz case JUST_RETURN: 25783786Sarutz default: 25793786Sarutz DCD_DO_KSTATS(un, kstat_waitq_enter, bp); 25803786Sarutz mutex_exit(DCD_MUTEX); 25813786Sarutz break; 25823786Sarutz } 25833786Sarutz 25843786Sarutz exit: 25853786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDINTR_END, "dcdintr_end"); 25863786Sarutz } 25873786Sarutz 25883786Sarutz 25893786Sarutz /* 25903786Sarutz * Done with a command. 25913786Sarutz */ 25923786Sarutz static void 25933786Sarutz dcddone_and_mutex_exit(struct dcd_disk *un, register struct buf *bp) 25943786Sarutz { 25953786Sarutz struct diskhd *dp; 25963786Sarutz 25973786Sarutz TRACE_1(TR_FAC_DADA, TR_DCDONE_START, "dcddone_start: un 0x%p", un); 25983786Sarutz 25993786Sarutz _NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(&un->un_dcd->dcd_mutex)); 26003786Sarutz 26013786Sarutz dp = &un->un_utab; 26023786Sarutz if (bp == dp->b_forw) { 26033786Sarutz dp->b_forw = NULL; 26043786Sarutz } 26053786Sarutz 26063786Sarutz if (un->un_stats) { 26073786Sarutz ulong_t n_done = bp->b_bcount - bp->b_resid; 26083786Sarutz if (bp->b_flags & B_READ) { 26093786Sarutz IOSP->reads++; 26103786Sarutz IOSP->nread += n_done; 26113786Sarutz } else { 26123786Sarutz IOSP->writes++; 26133786Sarutz IOSP->nwritten += n_done; 26143786Sarutz } 26153786Sarutz } 26163786Sarutz if (IO_PARTITION_STATS) { 26173786Sarutz ulong_t n_done = bp->b_bcount - bp->b_resid; 26183786Sarutz if (bp->b_flags & B_READ) { 26193786Sarutz IOSP_PARTITION->reads++; 26203786Sarutz IOSP_PARTITION->nread += n_done; 26213786Sarutz } else { 26223786Sarutz IOSP_PARTITION->writes++; 26233786Sarutz IOSP_PARTITION->nwritten += n_done; 26243786Sarutz } 26253786Sarutz } 26263786Sarutz 26273786Sarutz /* 26283786Sarutz * Start the next one before releasing resources on this one 26293786Sarutz */ 26303786Sarutz if (un->un_state == DCD_STATE_SUSPENDED) { 26313786Sarutz cv_broadcast(&un->un_disk_busy_cv); 26323786Sarutz } else if (dp->b_actf && (un->un_ncmds < un->un_throttle) && 26333786Sarutz (dp->b_forw == NULL && un->un_state != DCD_STATE_SUSPENDED)) { 26343786Sarutz dcdstart(un); 26353786Sarutz } 26363786Sarutz 26373786Sarutz mutex_exit(DCD_MUTEX); 26383786Sarutz 26393786Sarutz if (bp != un->un_sbufp) { 26403786Sarutz dcd_destroy_pkt(BP_PKT(bp)); 26413786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 26423786Sarutz "regular done: resid %ld\n", bp->b_resid); 26433786Sarutz } else { 26443786Sarutz ASSERT(un->un_sbuf_busy); 26453786Sarutz } 26463786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDDONE_BIODONE_CALL, "dcddone_biodone_call"); 26473786Sarutz 26483786Sarutz biodone(bp); 26493786Sarutz 26503786Sarutz (void) pm_idle_component(DCD_DEVINFO, 0); 26513786Sarutz 26523786Sarutz TRACE_0(TR_FAC_DADA, TR_DCDDONE_END, "dcddone end"); 26533786Sarutz } 26543786Sarutz 26553786Sarutz 26563786Sarutz /* 26573786Sarutz * reset the disk unless the transport layer has already 26583786Sarutz * cleared the problem 26593786Sarutz */ 26603786Sarutz #define C1 (STAT_ATA_BUS_RESET|STAT_ATA_DEV_RESET|STAT_ATA_ABORTED) 26613786Sarutz static void 26623786Sarutz dcd_reset_disk(struct dcd_disk *un, struct dcd_pkt *pkt) 26633786Sarutz { 26643786Sarutz 26653786Sarutz if ((pkt->pkt_statistics & C1) == 0) { 26663786Sarutz mutex_exit(DCD_MUTEX); 26673786Sarutz if (!dcd_reset(ROUTE, RESET_ALL)) { 26683786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 26693786Sarutz "Reset failed"); 26703786Sarutz } 26713786Sarutz mutex_enter(DCD_MUTEX); 26723786Sarutz } 26733786Sarutz } 26743786Sarutz 26753786Sarutz static int 26763786Sarutz dcd_handle_incomplete(struct dcd_disk *un, struct buf *bp) 26773786Sarutz { 26783786Sarutz static char *fail = "ATA transport failed: reason '%s': %s\n"; 26793786Sarutz static char *notresp = "disk not responding to selection\n"; 26803786Sarutz int rval = COMMAND_DONE_ERROR; 26813786Sarutz int action = COMMAND_SOFT_ERROR; 26823786Sarutz struct dcd_pkt *pkt = BP_PKT(bp); 26833786Sarutz int be_chatty = (un->un_state != DCD_STATE_SUSPENDED) && 26843786Sarutz (bp != un->un_sbufp || !(pkt->pkt_flags & FLAG_SILENT)); 26853786Sarutz 26863786Sarutz ASSERT(mutex_owned(DCD_MUTEX)); 26873786Sarutz 26883786Sarutz switch (pkt->pkt_reason) { 26893786Sarutz 26903786Sarutz case CMD_TIMEOUT: 26913786Sarutz /* 26923786Sarutz * This Indicates the already the HBA would have reset 26933786Sarutz * so Just indicate to retry the command 26943786Sarutz */ 26953786Sarutz break; 26963786Sarutz 26973786Sarutz case CMD_INCOMPLETE: 26983786Sarutz action = dcd_check_error(un, bp); 26993786Sarutz DCD_DO_ERRSTATS(un, dcd_transerrs); 27004137Skc28005 if (action == COMMAND_HARD_ERROR) { 27014137Skc28005 (void) dcd_reset_disk(un, pkt); 27024137Skc28005 } 27033786Sarutz break; 27043786Sarutz 27053786Sarutz case CMD_FATAL: 27063786Sarutz /* 27073786Sarutz * Something drastic has gone wrong 27083786Sarutz */ 27093786Sarutz break; 27103786Sarutz case CMD_DMA_DERR: 27113786Sarutz case CMD_DATA_OVR: 27123786Sarutz /* FALLTHROUGH */ 27133786Sarutz 27143786Sarutz default: 27153786Sarutz /* 27163786Sarutz * the target may still be running the command, 27173786Sarutz * so we should try and reset that target. 27183786Sarutz */ 27193786Sarutz DCD_DO_ERRSTATS(un, dcd_transerrs); 27203786Sarutz if ((pkt->pkt_reason != CMD_RESET) && 27217224Scth (pkt->pkt_reason != CMD_ABORTED)) { 27223786Sarutz (void) dcd_reset_disk(un, pkt); 27233786Sarutz } 27243786Sarutz break; 27253786Sarutz } 27263786Sarutz 27273786Sarutz /* 27283786Sarutz * If pkt_reason is CMD_RESET/ABORTED, chances are that this pkt got 27293786Sarutz * reset/aborted because another disk on this bus caused it. 27303786Sarutz * The disk that caused it, should get CMD_TIMEOUT with pkt_statistics 27313786Sarutz * of STAT_TIMEOUT/STAT_DEV_RESET 27323786Sarutz */ 27333786Sarutz if ((pkt->pkt_reason == CMD_RESET) ||(pkt->pkt_reason == CMD_ABORTED)) { 27343786Sarutz /* To be written : XXX */ 27353786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 27363786Sarutz "Command aborted\n"); 27373786Sarutz } 27383786Sarutz 27393786Sarutz if (bp == un->un_sbufp && (pkt->pkt_flags & FLAG_DIAGNOSE)) { 27403786Sarutz rval = COMMAND_DONE_ERROR; 27413786Sarutz } else { 27423786Sarutz if ((rval == COMMAND_DONE_ERROR) && 27433786Sarutz (action == COMMAND_SOFT_ERROR) && 27443786Sarutz ((int)PKT_GET_RETRY_CNT(pkt) < dcd_retry_count)) { 27453786Sarutz PKT_INCR_RETRY_CNT(pkt, 1); 27463786Sarutz rval = QUE_COMMAND; 27473786Sarutz } 27483786Sarutz } 27493786Sarutz 27503786Sarutz if (pkt->pkt_reason == CMD_INCOMPLETE && rval == COMMAND_DONE_ERROR) { 27513786Sarutz /* 27523786Sarutz * Looks like someone turned off this shoebox. 27533786Sarutz */ 27543786Sarutz if (un->un_state != DCD_STATE_OFFLINE) { 27553786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 27567224Scth (const char *) notresp); 27573786Sarutz New_state(un, DCD_STATE_OFFLINE); 27583786Sarutz } 27593786Sarutz } else if (pkt->pkt_reason == CMD_FATAL) { 27603786Sarutz /* 27613786Sarutz * Suppressing the following message for the time being 27623786Sarutz * dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 27633786Sarutz * (const char *) notresp); 27643786Sarutz */ 27653786Sarutz PKT_INCR_RETRY_CNT(pkt, 6); 27663786Sarutz rval = COMMAND_DONE_ERROR; 27673786Sarutz New_state(un, DCD_STATE_FATAL); 27683786Sarutz } else if (be_chatty) { 27693786Sarutz int in_panic = ddi_in_panic(); 27703786Sarutz if (!in_panic || (rval == COMMAND_DONE_ERROR)) { 27713786Sarutz if (((pkt->pkt_reason != un->un_last_pkt_reason) && 27723786Sarutz (pkt->pkt_reason != CMD_RESET)) || 27733786Sarutz (rval == COMMAND_DONE_ERROR) || 27743786Sarutz (dcd_error_level == DCD_ERR_ALL)) { 27753786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 27763786Sarutz fail, dcd_rname(pkt->pkt_reason), 27773786Sarutz (rval == COMMAND_DONE_ERROR) ? 27783786Sarutz "giving up": "retrying command"); 27793786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 27803786Sarutz "retrycount=%x\n", 27813786Sarutz PKT_GET_RETRY_CNT(pkt)); 27823786Sarutz } 27833786Sarutz } 27843786Sarutz } 27853786Sarutz error: 27863786Sarutz return (rval); 27873786Sarutz } 27883786Sarutz 27893786Sarutz static int 27903786Sarutz dcd_check_error(struct dcd_disk *un, struct buf *bp) 27913786Sarutz { 27923786Sarutz struct diskhd *dp = &un->un_utab; 27933786Sarutz struct dcd_pkt *pkt = BP_PKT(bp); 27943786Sarutz int rval = 0; 27953786Sarutz unsigned char status; 27963786Sarutz unsigned char error; 27973786Sarutz 27983786Sarutz TRACE_0(TR_FAC_DADA, TR_DCD_CHECK_ERROR_START, "dcd_check_error_start"); 27993786Sarutz ASSERT(mutex_owned(DCD_MUTEX)); 28003786Sarutz 28013786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 28023786Sarutz "Pkt: 0x%p dp: 0x%p\n", (void *)pkt, (void *)dp); 28033786Sarutz 28043786Sarutz /* 28053786Sarutz * Here we need to check status first and then if error is indicated 28063786Sarutz * Then the error register. 28073786Sarutz */ 28083786Sarutz 28093786Sarutz status = (pkt->pkt_scbp)[0]; 28103786Sarutz if ((status & STATUS_ATA_DWF) == STATUS_ATA_DWF) { 28113786Sarutz /* 28123786Sarutz * There has been a Device Fault - reason for such error 28133786Sarutz * is vendor specific 28143786Sarutz * Action to be taken is - Indicate error and reset device. 28153786Sarutz */ 28163786Sarutz 28173786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, "Device Fault\n"); 28183786Sarutz rval = COMMAND_HARD_ERROR; 28193786Sarutz } else if ((status & STATUS_ATA_CORR) == STATUS_ATA_CORR) { 28203786Sarutz 28213786Sarutz /* 28223786Sarutz * The sector read or written is marginal and hence ECC 28233786Sarutz * Correction has been applied. Indicate to repair 28243786Sarutz * Here we need to probably re-assign based on the badblock 28253786Sarutz * mapping. 28263786Sarutz */ 28273786Sarutz 28283786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 28293786Sarutz "Soft Error on block %x\n", 28303786Sarutz ((struct dcd_cmd *)pkt->pkt_cdbp)->sector_num.lba_num); 28313786Sarutz rval = COMMAND_SOFT_ERROR; 28323786Sarutz } else if ((status & STATUS_ATA_ERR) == STATUS_ATA_ERR) { 28333786Sarutz error = pkt->pkt_scbp[1]; 28343786Sarutz 28353786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 28363786Sarutz "Command:0x%x,Error:0x%x,Status:0x%x\n", 28373786Sarutz GETATACMD((struct dcd_cmd *)pkt->pkt_cdbp), 28383786Sarutz error, status); 28393786Sarutz if ((error & ERR_AMNF) == ERR_AMNF) { 28403786Sarutz /* Address make not found */ 28413786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 28423786Sarutz "Address Mark Not Found"); 28433786Sarutz } else if ((error & ERR_TKONF) == ERR_TKONF) { 28443786Sarutz /* Track 0 Not found */ 28453786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 28463786Sarutz "Track 0 Not found \n"); 28473786Sarutz } else if ((error & ERR_IDNF) == ERR_IDNF) { 28483786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 28493786Sarutz " ID not found \n"); 28503786Sarutz } else if ((error & ERR_UNC) == ERR_UNC) { 28513786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 28523786Sarutz "Uncorrectable data Error: Block %x\n", 28537224Scth ((struct dcd_cmd *)pkt->pkt_cdbp)-> 28547224Scth sector_num.lba_num); 28553786Sarutz } else if ((error & ERR_BBK) == ERR_BBK) { 28563786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 28573786Sarutz "Bad block detected: Block %x\n", 28587224Scth ((struct dcd_cmd *)pkt->pkt_cdbp)-> 28597224Scth sector_num.lba_num); 28603786Sarutz } else if ((error & ERR_ABORT) == ERR_ABORT) { 28613786Sarutz /* Aborted Command */ 28623786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 28633786Sarutz " Aborted Command \n"); 28643786Sarutz } 28653786Sarutz /* 28663786Sarutz * Return the soft error so that the command 28673786Sarutz * will be retried. 28683786Sarutz */ 28693786Sarutz rval = COMMAND_SOFT_ERROR; 28703786Sarutz } 28713786Sarutz 28723786Sarutz TRACE_0(TR_FAC_DADA, TR_DCD_CHECK_ERROR_END, "dcd_check_error_end"); 28733786Sarutz return (rval); 28743786Sarutz } 28753786Sarutz 28763786Sarutz 28773786Sarutz /* 28783786Sarutz * System Crash Dump routine 28793786Sarutz */ 28803786Sarutz 28813786Sarutz #define NDUMP_RETRIES 5 28823786Sarutz 28833786Sarutz static int 28843786Sarutz dcddump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) 28853786Sarutz { 28863786Sarutz struct dcd_pkt *pkt; 28873786Sarutz int i; 28883786Sarutz struct buf local, *bp; 28893786Sarutz int err; 28903786Sarutz unsigned char com; 28913786Sarutz diskaddr_t p_lblksrt; 28923786Sarutz diskaddr_t lblocks; 28933786Sarutz 28943786Sarutz GET_SOFT_STATE(dev); 28953786Sarutz #ifdef lint 28963786Sarutz part = part; 28973786Sarutz #endif /* lint */ 28983786Sarutz 28993786Sarutz _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*un)) 29003786Sarutz 29013786Sarutz if ((un->un_state & DCD_STATE_FATAL) == DCD_STATE_FATAL) 29023786Sarutz return (ENXIO); 29033786Sarutz 29043786Sarutz if (cmlb_partinfo(un->un_dklbhandle, DCDPART(dev), 29053786Sarutz &lblocks, &p_lblksrt, NULL, NULL, 0)) 29063786Sarutz return (ENXIO); 29073786Sarutz 29083786Sarutz if (blkno+nblk > lblocks) { 29093786Sarutz return (EINVAL); 29103786Sarutz } 29113786Sarutz 29123786Sarutz 29133786Sarutz if ((un->un_state == DCD_STATE_SUSPENDED) || 29143786Sarutz (un->un_state == DCD_STATE_PM_SUSPENDED)) { 29153786Sarutz if (pm_raise_power(DCD_DEVINFO, 0, 29163786Sarutz DCD_DEVICE_ACTIVE) != DDI_SUCCESS) { 29173786Sarutz return (EIO); 29183786Sarutz } 29193786Sarutz } 29203786Sarutz 29213786Sarutz /* 29223786Sarutz * When cpr calls dcddump, we know that dad is in a 29233786Sarutz * a good state, so no bus reset is required 29243786Sarutz */ 29253786Sarutz un->un_throttle = 0; 29263786Sarutz 29273786Sarutz if ((un->un_state != DCD_STATE_SUSPENDED) && 29283786Sarutz (un->un_state != DCD_STATE_DUMPING)) { 29293786Sarutz 29303786Sarutz New_state(un, DCD_STATE_DUMPING); 29313786Sarutz 29323786Sarutz /* 29333786Sarutz * Reset the bus. I'd like to not have to do this, 29343786Sarutz * but this is the safest thing to do... 29353786Sarutz */ 29363786Sarutz 29373786Sarutz if (dcd_reset(ROUTE, RESET_ALL) == 0) { 29383786Sarutz return (EIO); 29393786Sarutz } 29403786Sarutz 29413786Sarutz } 29423786Sarutz 29433786Sarutz blkno += p_lblksrt; 29443786Sarutz 29453786Sarutz /* 29463786Sarutz * It should be safe to call the allocator here without 29473786Sarutz * worrying about being locked for DVMA mapping because 29483786Sarutz * the address we're passed is already a DVMA mapping 29493786Sarutz * 29503786Sarutz * We are also not going to worry about semaphore ownership 29513786Sarutz * in the dump buffer. Dumping is single threaded at present. 29523786Sarutz */ 29533786Sarutz 29543786Sarutz bp = &local; 29553786Sarutz bzero((caddr_t)bp, sizeof (*bp)); 29563786Sarutz bp->b_flags = B_BUSY; 29573786Sarutz bp->b_un.b_addr = addr; 29583786Sarutz bp->b_bcount = nblk << DEV_BSHIFT; 29593786Sarutz bp->b_resid = 0; 29603786Sarutz 29613786Sarutz for (i = 0; i < NDUMP_RETRIES; i++) { 29623786Sarutz bp->b_flags &= ~B_ERROR; 29633786Sarutz if ((pkt = dcd_init_pkt(ROUTE, NULL, bp, 29643786Sarutz (uint32_t)sizeof (struct dcd_cmd), 2, PP_LEN, 29653786Sarutz PKT_CONSISTENT, NULL_FUNC, NULL)) != NULL) { 29663786Sarutz break; 29673786Sarutz } 29683786Sarutz if (i == 0) { 29693786Sarutz if (bp->b_flags & B_ERROR) { 29703786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 29713786Sarutz "no resources for dumping; " 29723786Sarutz "error code: 0x%x, retrying", 29733786Sarutz geterror(bp)); 29743786Sarutz } else { 29753786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 29763786Sarutz "no resources for dumping; retrying"); 29773786Sarutz } 29783786Sarutz } else if (i != (NDUMP_RETRIES - 1)) { 29793786Sarutz if (bp->b_flags & B_ERROR) { 29803786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_CONT, "no " 29813786Sarutz "resources for dumping; error code: 0x%x, " 29823786Sarutz "retrying\n", geterror(bp)); 29833786Sarutz } 29843786Sarutz } else { 29853786Sarutz if (bp->b_flags & B_ERROR) { 29863786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_CONT, 29873786Sarutz "no resources for dumping; " 29883786Sarutz "error code: 0x%x, retries failed, " 29893786Sarutz "giving up.\n", geterror(bp)); 29903786Sarutz } else { 29913786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_CONT, 29923786Sarutz "no resources for dumping; " 29933786Sarutz "retries failed, giving up.\n"); 29943786Sarutz } 29953786Sarutz return (EIO); 29963786Sarutz } 29973786Sarutz delay(10); 29983786Sarutz } 29993786Sarutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) { 30003786Sarutz com = ATA_WRITE_DMA; 30013786Sarutz } else { 30023786Sarutz if (un->un_dp->options & BLOCK_MODE) 30033786Sarutz com = ATA_WRITE_MULTIPLE; 30043786Sarutz else 30053786Sarutz com = ATA_WRITE; 30063786Sarutz } 30073786Sarutz 30083786Sarutz makecommand(pkt, 0, com, blkno, ADD_LBA_MODE, 30093786Sarutz (int)nblk*un->un_secsize, DATA_WRITE, 0); 30103786Sarutz 30113786Sarutz for (err = EIO, i = 0; i < NDUMP_RETRIES && err == EIO; i++) { 30123786Sarutz 30133786Sarutz if (dcd_poll(pkt) == 0) { 30143786Sarutz switch (SCBP_C(pkt)) { 30153786Sarutz case STATUS_GOOD: 30163786Sarutz if (pkt->pkt_resid == 0) { 30173786Sarutz err = 0; 30183786Sarutz } 30193786Sarutz break; 30203786Sarutz case STATUS_ATA_BUSY: 30213786Sarutz (void) dcd_reset(ROUTE, RESET_TARGET); 30223786Sarutz break; 30233786Sarutz default: 30243786Sarutz mutex_enter(DCD_MUTEX); 30253786Sarutz (void) dcd_reset_disk(un, pkt); 30263786Sarutz mutex_exit(DCD_MUTEX); 30273786Sarutz break; 30283786Sarutz } 30293786Sarutz } else if (i > NDUMP_RETRIES/2) { 30303786Sarutz (void) dcd_reset(ROUTE, RESET_ALL); 30313786Sarutz } 30323786Sarutz 30333786Sarutz } 30343786Sarutz dcd_destroy_pkt(pkt); 30353786Sarutz return (err); 30363786Sarutz } 30373786Sarutz 30383786Sarutz /* 30393786Sarutz * This routine implements the ioctl calls. It is called 30403786Sarutz * from the device switch at normal priority. 30413786Sarutz */ 30423786Sarutz /* ARGSUSED3 */ 30433786Sarutz static int 30443786Sarutz dcdioctl(dev_t dev, int cmd, intptr_t arg, int flag, 30453786Sarutz cred_t *cred_p, int *rval_p) 30463786Sarutz { 30473786Sarutz auto int32_t data[512 / (sizeof (int32_t))]; 30483786Sarutz struct dk_cinfo *info; 30493786Sarutz struct dk_minfo media_info; 30503786Sarutz struct udcd_cmd *scmd; 30513786Sarutz int i, err; 30523786Sarutz enum uio_seg uioseg = 0; 30533786Sarutz enum dkio_state state = 0; 30543786Sarutz #ifdef _MULTI_DATAMODEL 30553786Sarutz struct dadkio_rwcmd rwcmd; 30563786Sarutz #endif 30573786Sarutz struct dadkio_rwcmd32 rwcmd32; 30583786Sarutz struct dcd_cmd dcdcmd; 30593786Sarutz 30603786Sarutz GET_SOFT_STATE(dev); 30613786Sarutz #ifdef lint 30623786Sarutz part = part; 30633786Sarutz state = state; 30643786Sarutz uioseg = uioseg; 30653786Sarutz #endif /* lint */ 30663786Sarutz 30673786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 30683786Sarutz "dcd_ioctl : cmd %x, arg %lx\n", cmd, arg); 30693786Sarutz 30703786Sarutz bzero((caddr_t)data, sizeof (data)); 30713786Sarutz 30723786Sarutz switch (cmd) { 30733786Sarutz 30743786Sarutz #ifdef DCDDEBUG 30753786Sarutz /* 30763786Sarutz * Following ioctl are for testing RESET/ABORTS 30773786Sarutz */ 30783786Sarutz #define DKIOCRESET (DKIOC|14) 30793786Sarutz #define DKIOCABORT (DKIOC|15) 30803786Sarutz 30813786Sarutz case DKIOCRESET: 30823786Sarutz if (ddi_copyin((caddr_t)arg, (caddr_t)data, 4, flag)) 30833786Sarutz return (EFAULT); 30843786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 30853786Sarutz "DKIOCRESET: data = 0x%x\n", data[0]); 30863786Sarutz if (dcd_reset(ROUTE, data[0])) { 30873786Sarutz return (0); 30883786Sarutz } else { 30893786Sarutz return (EIO); 30903786Sarutz } 30913786Sarutz case DKIOCABORT: 30923786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 30933786Sarutz "DKIOCABORT:\n"); 30943786Sarutz if (dcd_abort(ROUTE, (struct dcd_pkt *)0)) { 30953786Sarutz return (0); 30963786Sarutz } else { 30973786Sarutz return (EIO); 30983786Sarutz } 30993786Sarutz #endif 31003786Sarutz 31013786Sarutz case DKIOCINFO: 31023786Sarutz /* 31033786Sarutz * Controller Information 31043786Sarutz */ 31053786Sarutz info = (struct dk_cinfo *)data; 31063786Sarutz 31073786Sarutz mutex_enter(DCD_MUTEX); 31083786Sarutz switch (un->un_dp->ctype) { 31093786Sarutz default: 31103786Sarutz info->dki_ctype = DKC_DIRECT; 31113786Sarutz break; 31123786Sarutz } 31133786Sarutz mutex_exit(DCD_MUTEX); 31143786Sarutz info->dki_cnum = ddi_get_instance(ddi_get_parent(DCD_DEVINFO)); 31153786Sarutz (void) strcpy(info->dki_cname, 31163786Sarutz ddi_get_name(ddi_get_parent(DCD_DEVINFO))); 31173786Sarutz /* 31183786Sarutz * Unit Information 31193786Sarutz */ 31203786Sarutz info->dki_unit = ddi_get_instance(DCD_DEVINFO); 31213786Sarutz info->dki_slave = (Tgt(DCD_DCD_DEVP)<<3); 31223786Sarutz (void) strcpy(info->dki_dname, ddi_driver_name(DCD_DEVINFO)); 31233786Sarutz info->dki_flags = DKI_FMTVOL; 31243786Sarutz info->dki_partition = DCDPART(dev); 31253786Sarutz 31263786Sarutz /* 31273786Sarutz * Max Transfer size of this device in blocks 31283786Sarutz */ 31293786Sarutz info->dki_maxtransfer = un->un_max_xfer_size / DEV_BSIZE; 31303786Sarutz 31313786Sarutz /* 31323786Sarutz * We can't get from here to there yet 31333786Sarutz */ 31343786Sarutz info->dki_addr = 0; 31353786Sarutz info->dki_space = 0; 31363786Sarutz info->dki_prio = 0; 31373786Sarutz info->dki_vec = 0; 31383786Sarutz 31393786Sarutz i = sizeof (struct dk_cinfo); 31403786Sarutz if (ddi_copyout((caddr_t)data, (caddr_t)arg, i, flag)) 31413786Sarutz return (EFAULT); 31423786Sarutz else 31433786Sarutz return (0); 31443786Sarutz 31453786Sarutz case DKIOCGMEDIAINFO: 31463786Sarutz /* 31473786Sarutz * As dad target driver is used for IDE disks only 31483786Sarutz * Can keep the return value hardcoded to FIXED_DISK 31493786Sarutz */ 31503786Sarutz media_info.dki_media_type = DK_FIXED_DISK; 31513786Sarutz 31523786Sarutz mutex_enter(DCD_MUTEX); 31533786Sarutz media_info.dki_lbsize = un->un_lbasize; 31543786Sarutz media_info.dki_capacity = un->un_diskcapacity; 31553786Sarutz mutex_exit(DCD_MUTEX); 31563786Sarutz 31573786Sarutz if (ddi_copyout(&media_info, (caddr_t)arg, 31583786Sarutz sizeof (struct dk_minfo), flag)) 31593786Sarutz return (EFAULT); 31603786Sarutz else 31613786Sarutz return (0); 31623786Sarutz 31633786Sarutz case DKIOCGGEOM: 31643786Sarutz case DKIOCGVTOC: 31653786Sarutz case DKIOCGETEFI: 31663786Sarutz 31673786Sarutz mutex_enter(DCD_MUTEX); 31683786Sarutz if (un->un_ncmds == 0) { 31693786Sarutz if ((err = dcd_unit_ready(dev)) != 0) { 31703786Sarutz mutex_exit(DCD_MUTEX); 31713786Sarutz return (err); 31723786Sarutz } 31733786Sarutz } 31743786Sarutz 31753786Sarutz mutex_exit(DCD_MUTEX); 31763786Sarutz err = cmlb_ioctl(un->un_dklbhandle, dev, cmd, 31773786Sarutz arg, flag, cred_p, rval_p, 0); 31783786Sarutz return (err); 31793786Sarutz 31803786Sarutz case DKIOCGAPART: 31813786Sarutz case DKIOCSAPART: 31823786Sarutz case DKIOCSGEOM: 31833786Sarutz case DKIOCSVTOC: 31843786Sarutz case DKIOCSETEFI: 31853786Sarutz case DKIOCPARTITION: 31863786Sarutz case DKIOCPARTINFO: 31873786Sarutz case DKIOCGMBOOT: 31883786Sarutz case DKIOCSMBOOT: 31893786Sarutz 31903786Sarutz err = cmlb_ioctl(un->un_dklbhandle, dev, cmd, 31913786Sarutz arg, flag, cred_p, rval_p, 0); 31923786Sarutz return (err); 31933786Sarutz 31943786Sarutz case DIOCTL_RWCMD: 31953786Sarutz if (drv_priv(cred_p) != 0) { 31963786Sarutz return (EPERM); 31973786Sarutz } 31983786Sarutz 31993786Sarutz #ifdef _MULTI_DATAMODEL 32003786Sarutz switch (ddi_model_convert_from(flag & FMODELS)) { 32013786Sarutz case DDI_MODEL_NONE: 32023786Sarutz if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd, 32033786Sarutz sizeof (struct dadkio_rwcmd), flag)) { 32043786Sarutz return (EFAULT); 32053786Sarutz } 32063786Sarutz rwcmd32.cmd = rwcmd.cmd; 32073786Sarutz rwcmd32.flags = rwcmd.flags; 32083786Sarutz rwcmd32.blkaddr = rwcmd.blkaddr; 32093786Sarutz rwcmd32.buflen = rwcmd.buflen; 32103786Sarutz rwcmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmd.bufaddr; 32113786Sarutz break; 32123786Sarutz case DDI_MODEL_ILP32: 32133786Sarutz if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd32, 32143786Sarutz sizeof (struct dadkio_rwcmd32), flag)) { 32153786Sarutz return (EFAULT); 32163786Sarutz } 32173786Sarutz break; 32183786Sarutz } 32193786Sarutz #else 32203786Sarutz if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd32, 32213786Sarutz sizeof (struct dadkio_rwcmd32), flag)) { 32223786Sarutz return (EFAULT); 32233786Sarutz } 32243786Sarutz #endif 32253786Sarutz mutex_enter(DCD_MUTEX); 32263786Sarutz 32273786Sarutz uioseg = UIO_SYSSPACE; 32283786Sarutz scmd = (struct udcd_cmd *)data; 32293786Sarutz scmd->udcd_cmd = &dcdcmd; 32303786Sarutz /* 32313786Sarutz * Convert the dadkio_rwcmd structure to udcd_cmd so that 32323786Sarutz * it can take the normal path to get the io done 32333786Sarutz */ 32343786Sarutz if (rwcmd32.cmd == DADKIO_RWCMD_READ) { 32353786Sarutz if ((un->un_dp->options & DMA_SUPPORTTED) == 32363786Sarutz DMA_SUPPORTTED) 32373786Sarutz scmd->udcd_cmd->cmd = ATA_READ_DMA; 32383786Sarutz else 32393786Sarutz scmd->udcd_cmd->cmd = ATA_READ; 32403786Sarutz scmd->udcd_cmd->address_mode = ADD_LBA_MODE; 32413786Sarutz scmd->udcd_cmd->direction = DATA_READ; 32423786Sarutz scmd->udcd_flags |= UDCD_READ|UDCD_SILENT; 32433786Sarutz } else if (rwcmd32.cmd == DADKIO_RWCMD_WRITE) { 32443786Sarutz if ((un->un_dp->options & DMA_SUPPORTTED) == 32453786Sarutz DMA_SUPPORTTED) 32463786Sarutz scmd->udcd_cmd->cmd = ATA_WRITE_DMA; 32473786Sarutz else 32483786Sarutz scmd->udcd_cmd->cmd = ATA_WRITE; 32493786Sarutz scmd->udcd_cmd->direction = DATA_WRITE; 32503786Sarutz scmd->udcd_flags |= UDCD_WRITE|UDCD_SILENT; 32513786Sarutz } else { 32523786Sarutz mutex_exit(DCD_MUTEX); 32533786Sarutz return (EINVAL); 32543786Sarutz } 32553786Sarutz 32563786Sarutz scmd->udcd_cmd->address_mode = ADD_LBA_MODE; 32573786Sarutz scmd->udcd_cmd->features = 0; 32583786Sarutz scmd->udcd_cmd->size = rwcmd32.buflen; 32593786Sarutz scmd->udcd_cmd->sector_num.lba_num = rwcmd32.blkaddr; 32603786Sarutz scmd->udcd_bufaddr = (caddr_t)(uintptr_t)rwcmd32.bufaddr; 32613786Sarutz scmd->udcd_buflen = rwcmd32.buflen; 32623786Sarutz scmd->udcd_timeout = (ushort_t)dcd_io_time; 32633786Sarutz scmd->udcd_resid = 0ULL; 32643786Sarutz scmd->udcd_status = 0; 32653786Sarutz scmd->udcd_error_reg = 0; 32663786Sarutz scmd->udcd_status_reg = 0; 32673786Sarutz 32683786Sarutz mutex_exit(DCD_MUTEX); 32693786Sarutz 32703786Sarutz i = dcdioctl_cmd(dev, scmd, UIO_SYSSPACE, UIO_USERSPACE); 32713786Sarutz mutex_enter(DCD_MUTEX); 32723786Sarutz /* 32733786Sarutz * After return convert the status from scmd to 32743786Sarutz * dadkio_status 32753786Sarutz */ 32763786Sarutz (void) dcd_translate(&(rwcmd32.status), scmd); 32773786Sarutz rwcmd32.status.resid = scmd->udcd_resid; 32783786Sarutz mutex_exit(DCD_MUTEX); 32793786Sarutz 32803786Sarutz #ifdef _MULTI_DATAMODEL 32813786Sarutz switch (ddi_model_convert_from(flag & FMODELS)) { 32823786Sarutz case DDI_MODEL_NONE: { 32833786Sarutz int counter; 32843786Sarutz rwcmd.status.status = rwcmd32.status.status; 32853786Sarutz rwcmd.status.resid = rwcmd32.status.resid; 32863786Sarutz rwcmd.status.failed_blk_is_valid = 32873786Sarutz rwcmd32.status.failed_blk_is_valid; 32883786Sarutz rwcmd.status.failed_blk = rwcmd32.status.failed_blk; 32893786Sarutz rwcmd.status.fru_code_is_valid = 32903786Sarutz rwcmd32.status.fru_code_is_valid; 32913786Sarutz rwcmd.status.fru_code = rwcmd32.status.fru_code; 32923786Sarutz for (counter = 0; 32933786Sarutz counter < DADKIO_ERROR_INFO_LEN; counter++) 32943786Sarutz rwcmd.status.add_error_info[counter] = 32953786Sarutz rwcmd32.status.add_error_info[counter]; 32963786Sarutz } 32973786Sarutz /* Copy out the result back to the user program */ 32983786Sarutz if (ddi_copyout((caddr_t)&rwcmd, (caddr_t)arg, 32993786Sarutz sizeof (struct dadkio_rwcmd), flag)) { 33003786Sarutz if (i != 0) { 33013786Sarutz i = EFAULT; 33023786Sarutz } 33033786Sarutz } 33043786Sarutz break; 33053786Sarutz case DDI_MODEL_ILP32: 33063786Sarutz /* Copy out the result back to the user program */ 33073786Sarutz if (ddi_copyout((caddr_t)&rwcmd32, (caddr_t)arg, 33083786Sarutz sizeof (struct dadkio_rwcmd32), flag)) { 33093786Sarutz if (i != 0) { 33103786Sarutz i = EFAULT; 33113786Sarutz } 33123786Sarutz } 33133786Sarutz break; 33143786Sarutz } 33153786Sarutz #else 33163786Sarutz /* Copy out the result back to the user program */ 33173786Sarutz if (ddi_copyout((caddr_t)&rwcmd32, (caddr_t)arg, 33183786Sarutz sizeof (struct dadkio_rwcmd32), flag)) { 33193786Sarutz if (i != 0) 33203786Sarutz i = EFAULT; 33213786Sarutz } 33223786Sarutz #endif 33233786Sarutz return (i); 33243786Sarutz 33253786Sarutz case UDCDCMD: { 33263786Sarutz #ifdef _MULTI_DATAMODEL 33273786Sarutz /* 33283786Sarutz * For use when a 32 bit app makes a call into a 33293786Sarutz * 64 bit ioctl 33303786Sarutz */ 33313786Sarutz struct udcd_cmd32 udcd_cmd_32_for_64; 33323786Sarutz struct udcd_cmd32 *ucmd32 = &udcd_cmd_32_for_64; 33333786Sarutz model_t model; 33343786Sarutz #endif /* _MULTI_DATAMODEL */ 33353786Sarutz 33363786Sarutz if (drv_priv(cred_p) != 0) { 33373786Sarutz return (EPERM); 33383786Sarutz } 33393786Sarutz 33403786Sarutz scmd = (struct udcd_cmd *)data; 33413786Sarutz 33423786Sarutz #ifdef _MULTI_DATAMODEL 33433786Sarutz switch (model = ddi_model_convert_from(flag & FMODELS)) { 33443786Sarutz case DDI_MODEL_ILP32: 33453786Sarutz if (ddi_copyin((caddr_t)arg, ucmd32, 33463786Sarutz sizeof (struct udcd_cmd32), flag)) { 33473786Sarutz return (EFAULT); 33483786Sarutz } 33493786Sarutz /* 33503786Sarutz * Convert the ILP32 uscsi data from the 33513786Sarutz * application to LP64 for internal use. 33523786Sarutz */ 33533786Sarutz udcd_cmd32toudcd_cmd(ucmd32, scmd); 33543786Sarutz break; 33553786Sarutz case DDI_MODEL_NONE: 33563786Sarutz if (ddi_copyin((caddr_t)arg, scmd, sizeof (*scmd), 33573786Sarutz flag)) { 33583786Sarutz return (EFAULT); 33593786Sarutz } 33603786Sarutz break; 33613786Sarutz } 33623786Sarutz #else /* ! _MULTI_DATAMODEL */ 33633786Sarutz if (ddi_copyin((caddr_t)arg, (caddr_t)scmd, 33643786Sarutz sizeof (*scmd), flag)) { 33653786Sarutz return (EFAULT); 33663786Sarutz } 33673786Sarutz #endif /* ! _MULTI_DATAMODEL */ 33683786Sarutz 33693786Sarutz scmd->udcd_flags &= ~UDCD_NOINTR; 33703786Sarutz uioseg = (flag & FKIOCTL)? UIO_SYSSPACE: UIO_USERSPACE; 33713786Sarutz 33723786Sarutz i = dcdioctl_cmd(dev, scmd, uioseg, uioseg); 33733786Sarutz #ifdef _MULTI_DATAMODEL 33743786Sarutz switch (model) { 33753786Sarutz case DDI_MODEL_ILP32: 33763786Sarutz /* 33773786Sarutz * Convert back to ILP32 before copyout to the 33783786Sarutz * application 33793786Sarutz */ 33803786Sarutz udcd_cmdtoudcd_cmd32(scmd, ucmd32); 33813786Sarutz if (ddi_copyout(ucmd32, (caddr_t)arg, 33823786Sarutz sizeof (*ucmd32), flag)) { 33833786Sarutz if (i != 0) 33843786Sarutz i = EFAULT; 33853786Sarutz } 33863786Sarutz break; 33873786Sarutz case DDI_MODEL_NONE: 33883786Sarutz if (ddi_copyout(scmd, (caddr_t)arg, sizeof (*scmd), 33893786Sarutz flag)) { 33903786Sarutz if (i != 0) 33913786Sarutz i = EFAULT; 33923786Sarutz } 33933786Sarutz break; 33943786Sarutz } 33953786Sarutz #else /* ! _MULTI_DATAMODE */ 33963786Sarutz if (ddi_copyout((caddr_t)scmd, (caddr_t)arg, 33973786Sarutz sizeof (*scmd), flag)) { 33983786Sarutz if (i != 0) 33993786Sarutz i = EFAULT; 34003786Sarutz } 34013786Sarutz #endif 34023786Sarutz return (i); 34033786Sarutz } 34043786Sarutz case DKIOCFLUSHWRITECACHE: { 34053786Sarutz struct dk_callback *dkc = (struct dk_callback *)arg; 34063786Sarutz struct dcd_pkt *pkt; 34073786Sarutz struct buf *bp; 34083786Sarutz int is_sync = 1; 34093786Sarutz 34103786Sarutz mutex_enter(DCD_MUTEX); 34113786Sarutz if (un->un_flush_not_supported || 34123786Sarutz ! un->un_write_cache_enabled) { 34133786Sarutz i = un->un_flush_not_supported ? ENOTSUP : 0; 34143786Sarutz mutex_exit(DCD_MUTEX); 34153786Sarutz /* 34163786Sarutz * If a callback was requested: a callback will 34173786Sarutz * always be done if the caller saw the 34183786Sarutz * DKIOCFLUSHWRITECACHE ioctl return 0, and 34193786Sarutz * never done if the caller saw the ioctl return 34203786Sarutz * an error. 34213786Sarutz */ 34223786Sarutz if ((flag & FKIOCTL) && dkc != NULL && 34233786Sarutz dkc->dkc_callback != NULL) { 34243786Sarutz (*dkc->dkc_callback)(dkc->dkc_cookie, i); 34253786Sarutz /* 34263786Sarutz * Did callback and reported error. 34273786Sarutz * Since we did a callback, ioctl 34283786Sarutz * should return 0. 34293786Sarutz */ 34303786Sarutz i = 0; 34313786Sarutz } 34323786Sarutz return (i); 34333786Sarutz } 34343786Sarutz 34353786Sarutz /* 34363786Sarutz * Get the special buffer 34373786Sarutz */ 34383786Sarutz while (un->un_sbuf_busy) { 34393786Sarutz cv_wait(&un->un_sbuf_cv, DCD_MUTEX); 34403786Sarutz } 34413786Sarutz un->un_sbuf_busy = 1; 34423786Sarutz bp = un->un_sbufp; 34433786Sarutz mutex_exit(DCD_MUTEX); 34443786Sarutz 34453786Sarutz pkt = dcd_init_pkt(ROUTE, (struct dcd_pkt *)NULL, 34463786Sarutz NULL, (uint32_t)sizeof (struct dcd_cmd), 34473786Sarutz 2, PP_LEN, PKT_CONSISTENT, SLEEP_FUNC, (caddr_t)un); 34483786Sarutz ASSERT(pkt != NULL); 34493786Sarutz 34503786Sarutz makecommand(pkt, un->un_cmd_flags | FLAG_SILENT, 34513786Sarutz ATA_FLUSH_CACHE, 0, ADD_LBA_MODE, 0, NO_DATA_XFER, 0); 34523786Sarutz 34533786Sarutz pkt->pkt_comp = dcdintr; 34543786Sarutz pkt->pkt_time = DCD_FLUSH_TIME; 34553786Sarutz PKT_SET_BP(pkt, bp); 34563786Sarutz 34573786Sarutz bp->av_back = (struct buf *)pkt; 34583786Sarutz bp->b_forw = NULL; 34593786Sarutz bp->b_flags = B_BUSY; 34603786Sarutz bp->b_error = 0; 34613786Sarutz bp->b_edev = dev; 34623786Sarutz bp->b_dev = cmpdev(dev); 34633786Sarutz bp->b_bcount = 0; 34643786Sarutz bp->b_blkno = 0; 34653786Sarutz bp->b_un.b_addr = 0; 34663786Sarutz bp->b_iodone = NULL; 34673786Sarutz bp->b_list = NULL; 34683786Sarutz 34693786Sarutz if ((flag & FKIOCTL) && dkc != NULL && 34703786Sarutz dkc->dkc_callback != NULL) { 34713786Sarutz struct dk_callback *dkc2 = (struct dk_callback *) 34723786Sarutz kmem_zalloc(sizeof (*dkc2), KM_SLEEP); 34733786Sarutz bcopy(dkc, dkc2, sizeof (*dkc2)); 34743786Sarutz 34753786Sarutz bp->b_list = (struct buf *)dkc2; 34763786Sarutz bp->b_iodone = dcdflushdone; 34773786Sarutz is_sync = 0; 34783786Sarutz } 34793786Sarutz 34803786Sarutz (void) dcdstrategy(bp); 34813786Sarutz 34823786Sarutz i = 0; 34833786Sarutz if (is_sync) { 34843786Sarutz i = biowait(bp); 34853786Sarutz (void) dcdflushdone(bp); 34863786Sarutz } 34873786Sarutz 34883786Sarutz return (i); 34893786Sarutz } 34903786Sarutz default: 34913786Sarutz break; 34923786Sarutz } 34933786Sarutz return (ENOTTY); 34943786Sarutz } 34953786Sarutz 34963786Sarutz 34973786Sarutz static int 34983786Sarutz dcdflushdone(struct buf *bp) 34993786Sarutz { 35003786Sarutz struct dcd_disk *un = ddi_get_soft_state(dcd_state, 35013786Sarutz DCDUNIT(bp->b_edev)); 35023786Sarutz struct dcd_pkt *pkt = BP_PKT(bp); 35033786Sarutz struct dk_callback *dkc = (struct dk_callback *)bp->b_list; 35043786Sarutz 35053786Sarutz ASSERT(un != NULL); 35063786Sarutz ASSERT(bp == un->un_sbufp); 35073786Sarutz ASSERT(pkt != NULL); 35083786Sarutz 35093786Sarutz dcd_destroy_pkt(pkt); 35103786Sarutz bp->av_back = NO_PKT_ALLOCATED; 35113786Sarutz 35123786Sarutz if (dkc != NULL) { 35133786Sarutz ASSERT(bp->b_iodone != NULL); 35143786Sarutz (*dkc->dkc_callback)(dkc->dkc_cookie, geterror(bp)); 35153786Sarutz kmem_free(dkc, sizeof (*dkc)); 35163786Sarutz bp->b_iodone = NULL; 35173786Sarutz bp->b_list = NULL; 35183786Sarutz } 35193786Sarutz 35203786Sarutz /* 35213786Sarutz * Tell anybody who cares that the buffer is now free 35223786Sarutz */ 35233786Sarutz mutex_enter(DCD_MUTEX); 35243786Sarutz un->un_sbuf_busy = 0; 35253786Sarutz cv_signal(&un->un_sbuf_cv); 35263786Sarutz mutex_exit(DCD_MUTEX); 35273786Sarutz return (0); 35283786Sarutz } 35293786Sarutz 35303786Sarutz /* 35313786Sarutz * dcdrunout: 35323786Sarutz * the callback function for resource allocation 35333786Sarutz * 35343786Sarutz * XXX it would be preferable that dcdrunout() scans the whole 35353786Sarutz * list for possible candidates for dcdstart(); this avoids 35363786Sarutz * that a bp at the head of the list whose request cannot be 35373786Sarutz * satisfied is retried again and again 35383786Sarutz */ 35393786Sarutz /*ARGSUSED*/ 35403786Sarutz static int 35413786Sarutz dcdrunout(caddr_t arg) 35423786Sarutz { 35433786Sarutz int serviced; 35443786Sarutz struct dcd_disk *un; 35453786Sarutz struct diskhd *dp; 35463786Sarutz 35473786Sarutz TRACE_1(TR_FAC_DADA, TR_DCDRUNOUT_START, "dcdrunout_start: arg 0x%p", 35483786Sarutz arg); 35493786Sarutz serviced = 1; 35503786Sarutz 35513786Sarutz un = (struct dcd_disk *)arg; 35523786Sarutz dp = &un->un_utab; 35533786Sarutz 35543786Sarutz /* 35553786Sarutz * We now support passing a structure to the callback 35563786Sarutz * routine. 35573786Sarutz */ 35583786Sarutz ASSERT(un != NULL); 35593786Sarutz mutex_enter(DCD_MUTEX); 35603786Sarutz if ((un->un_ncmds < un->un_throttle) && (dp->b_forw == NULL)) { 35613786Sarutz dcdstart(un); 35623786Sarutz } 35633786Sarutz if (un->un_state == DCD_STATE_RWAIT) { 35643786Sarutz serviced = 0; 35653786Sarutz } 35663786Sarutz mutex_exit(DCD_MUTEX); 35673786Sarutz TRACE_1(TR_FAC_DADA, TR_DCDRUNOUT_END, 35683786Sarutz "dcdrunout_end: serviced %d", serviced); 35693786Sarutz return (serviced); 35703786Sarutz } 35713786Sarutz 35723786Sarutz 35733786Sarutz /* 35743786Sarutz * This routine called to see whether unit is (still) there. Must not 35753786Sarutz * be called when un->un_sbufp is in use, and must not be called with 35763786Sarutz * an unattached disk. Soft state of disk is restored to what it was 35773786Sarutz * upon entry- up to caller to set the correct state. 35783786Sarutz * 35793786Sarutz * We enter with the disk mutex held. 35803786Sarutz */ 35813786Sarutz 35823786Sarutz /* ARGSUSED0 */ 35833786Sarutz static int 35843786Sarutz dcd_unit_ready(dev_t dev) 35853786Sarutz { 35863786Sarutz #ifndef lint 35873786Sarutz auto struct udcd_cmd dcmd, *com = &dcmd; 35883786Sarutz auto struct dcd_cmd cmdblk; 35893786Sarutz #endif 35903786Sarutz int error; 35913786Sarutz #ifndef lint 35923786Sarutz GET_SOFT_STATE(dev); 35933786Sarutz #endif 35943786Sarutz 35953786Sarutz /* 35963786Sarutz * Now that we protect the special buffer with 35973786Sarutz * a mutex, we could probably do a mutex_tryenter 35983786Sarutz * on it here and return failure if it were held... 35993786Sarutz */ 36003786Sarutz 36013786Sarutz error = 0; 36023786Sarutz return (error); 36033786Sarutz } 36043786Sarutz 36053786Sarutz /* ARGSUSED0 */ 36063786Sarutz int 36073786Sarutz dcdioctl_cmd(dev_t devp, struct udcd_cmd *in, enum uio_seg cdbspace, 36083786Sarutz enum uio_seg dataspace) 36093786Sarutz { 36103786Sarutz 36113786Sarutz struct buf *bp; 36123786Sarutz struct udcd_cmd *scmd; 36133786Sarutz struct dcd_pkt *pkt; 36143786Sarutz int err, rw; 36153786Sarutz caddr_t cdb; 36163786Sarutz int flags = 0; 36173786Sarutz 36183786Sarutz GET_SOFT_STATE(devp); 36193786Sarutz 36203786Sarutz #ifdef lint 36213786Sarutz part = part; 36223786Sarutz #endif 36233786Sarutz 36243786Sarutz /* 36253786Sarutz * Is this a request to reset the bus? 36263786Sarutz * if so, we need to do reseting. 36273786Sarutz */ 36283786Sarutz 36293786Sarutz if (in->udcd_flags & UDCD_RESET) { 36303786Sarutz int flag = RESET_TARGET; 36313786Sarutz err = dcd_reset(ROUTE, flag) ? 0: EIO; 36323786Sarutz return (err); 36333786Sarutz } 36343786Sarutz 36353786Sarutz scmd = in; 36363786Sarutz 36373786Sarutz 36383786Sarutz /* Do some sanity checks */ 36393786Sarutz if (scmd->udcd_buflen <= 0) { 36403786Sarutz if (scmd->udcd_flags & (UDCD_READ | UDCD_WRITE)) { 36413786Sarutz return (EINVAL); 36423786Sarutz } else { 36433786Sarutz scmd->udcd_buflen = 0; 36443786Sarutz } 36453786Sarutz } 36463786Sarutz 36473786Sarutz /* Make a copy of the dcd_cmd passed */ 36483786Sarutz cdb = kmem_zalloc(sizeof (struct dcd_cmd), KM_SLEEP); 36493786Sarutz if (cdbspace == UIO_SYSSPACE) { 36503786Sarutz flags |= FKIOCTL; 36513786Sarutz } 36523786Sarutz 36533786Sarutz if (ddi_copyin((void *)scmd->udcd_cmd, cdb, sizeof (struct dcd_cmd), 36543786Sarutz flags)) { 36553786Sarutz kmem_free(cdb, sizeof (struct dcd_cmd)); 36563786Sarutz return (EFAULT); 36573786Sarutz } 36583786Sarutz scmd = (struct udcd_cmd *)kmem_alloc(sizeof (*scmd), KM_SLEEP); 36593786Sarutz bcopy((caddr_t)in, (caddr_t)scmd, sizeof (*scmd)); 36603786Sarutz scmd->udcd_cmd = (struct dcd_cmd *)cdb; 36613786Sarutz rw = (scmd->udcd_flags & UDCD_READ) ? B_READ: B_WRITE; 36623786Sarutz 36633786Sarutz 36643786Sarutz /* 36653786Sarutz * Get the special buffer 36663786Sarutz */ 36673786Sarutz 36683786Sarutz mutex_enter(DCD_MUTEX); 36693786Sarutz while (un->un_sbuf_busy) { 36703786Sarutz if (cv_wait_sig(&un->un_sbuf_cv, DCD_MUTEX) == 0) { 36713786Sarutz kmem_free(scmd->udcd_cmd, sizeof (struct dcd_cmd)); 36723786Sarutz kmem_free((caddr_t)scmd, sizeof (*scmd)); 36733786Sarutz mutex_exit(DCD_MUTEX); 36743786Sarutz return (EINTR); 36753786Sarutz } 36763786Sarutz } 36773786Sarutz 36783786Sarutz un->un_sbuf_busy = 1; 36793786Sarutz bp = un->un_sbufp; 36803786Sarutz mutex_exit(DCD_MUTEX); 36813786Sarutz 36823786Sarutz 36833786Sarutz /* 36843786Sarutz * If we are going to do actual I/O, let physio do all the 36853786Sarutz * things 36863786Sarutz */ 36873786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 36883786Sarutz "dcdioctl_cmd : buflen %x\n", scmd->udcd_buflen); 36893786Sarutz 36903786Sarutz if (scmd->udcd_buflen) { 36913786Sarutz auto struct iovec aiov; 36923786Sarutz auto struct uio auio; 36933786Sarutz struct uio *uio = &auio; 36943786Sarutz 36953786Sarutz bzero((caddr_t)&auio, sizeof (struct uio)); 36963786Sarutz bzero((caddr_t)&aiov, sizeof (struct iovec)); 36973786Sarutz 36983786Sarutz aiov.iov_base = scmd->udcd_bufaddr; 36993786Sarutz aiov.iov_len = scmd->udcd_buflen; 37003786Sarutz 37013786Sarutz uio->uio_iov = &aiov; 37023786Sarutz uio->uio_iovcnt = 1; 37033786Sarutz uio->uio_resid = scmd->udcd_buflen; 37043786Sarutz uio->uio_segflg = dataspace; 37053786Sarutz 37063786Sarutz /* 37073786Sarutz * Let physio do the rest... 37083786Sarutz */ 37093786Sarutz bp->av_back = NO_PKT_ALLOCATED; 37103786Sarutz bp->b_forw = (struct buf *)scmd; 37113786Sarutz err = physio(dcdstrategy, bp, devp, rw, dcdudcdmin, uio); 37123786Sarutz } else { 37133786Sarutz /* 37143786Sarutz * We have to mimic what physio would do here. 37153786Sarutz */ 37163786Sarutz bp->av_back = NO_PKT_ALLOCATED; 37173786Sarutz bp->b_forw = (struct buf *)scmd; 37183786Sarutz bp->b_flags = B_BUSY | rw; 37193786Sarutz bp->b_edev = devp; 37203786Sarutz bp->b_dev = cmpdev(devp); 37213786Sarutz bp->b_bcount = bp->b_blkno = 0; 37223786Sarutz (void) dcdstrategy(bp); 37233786Sarutz err = biowait(bp); 37243786Sarutz } 37253786Sarutz 37263786Sarutz done: 37273786Sarutz if ((pkt = BP_PKT(bp)) != NULL) { 37283786Sarutz bp->av_back = NO_PKT_ALLOCATED; 37293786Sarutz /* we need to update the completion status of udcd command */ 37303786Sarutz in->udcd_resid = bp->b_resid; 37313786Sarutz in->udcd_status_reg = SCBP_C(pkt); 37323786Sarutz /* XXX: we need to give error_reg also */ 37333786Sarutz dcd_destroy_pkt(pkt); 37343786Sarutz } 37353786Sarutz /* 37363786Sarutz * Tell anybody who cares that the buffer is now free 37373786Sarutz */ 37383786Sarutz mutex_enter(DCD_MUTEX); 37393786Sarutz un->un_sbuf_busy = 0; 37403786Sarutz cv_signal(&un->un_sbuf_cv); 37413786Sarutz mutex_exit(DCD_MUTEX); 37423786Sarutz 37433786Sarutz kmem_free(scmd->udcd_cmd, sizeof (struct dcd_cmd)); 37443786Sarutz kmem_free((caddr_t)scmd, sizeof (*scmd)); 37453786Sarutz return (err); 37463786Sarutz } 37473786Sarutz 37483786Sarutz static void 37493786Sarutz dcdudcdmin(struct buf *bp) 37503786Sarutz { 37513786Sarutz 37523786Sarutz #ifdef lint 37533786Sarutz bp = bp; 37543786Sarutz #endif 37553786Sarutz 37563786Sarutz } 37573786Sarutz 37583786Sarutz /* 37593786Sarutz * restart a cmd from timeout() context 37603786Sarutz * 37613786Sarutz * the cmd is expected to be in un_utab.b_forw. If this pointer is non-zero 37623786Sarutz * a restart timeout request has been issued and no new timeouts should 37633786Sarutz * be requested. b_forw is reset when the cmd eventually completes in 37643786Sarutz * dcddone_and_mutex_exit() 37653786Sarutz */ 37663786Sarutz void 37673786Sarutz dcdrestart(void *arg) 37683786Sarutz { 37693786Sarutz struct dcd_disk *un = (struct dcd_disk *)arg; 37703786Sarutz struct buf *bp; 37713786Sarutz int status; 37723786Sarutz 37733786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdrestart\n"); 37743786Sarutz 37753786Sarutz mutex_enter(DCD_MUTEX); 37763786Sarutz bp = un->un_utab.b_forw; 37773786Sarutz if (bp) { 37783786Sarutz un->un_ncmds++; 37793786Sarutz DCD_DO_KSTATS(un, kstat_waitq_to_runq, bp); 37803786Sarutz } 37813786Sarutz 37823786Sarutz 37833786Sarutz if (bp) { 37843786Sarutz struct dcd_pkt *pkt = BP_PKT(bp); 37853786Sarutz 37863786Sarutz mutex_exit(DCD_MUTEX); 37873786Sarutz 37883786Sarutz pkt->pkt_flags = 0; 37893786Sarutz 37903786Sarutz if ((status = dcd_transport(pkt)) != TRAN_ACCEPT) { 37913786Sarutz mutex_enter(DCD_MUTEX); 37923786Sarutz DCD_DO_KSTATS(un, kstat_runq_back_to_waitq, bp); 37933786Sarutz un->un_ncmds--; 37943786Sarutz if (status == TRAN_BUSY) { 37953786Sarutz /* XXX : To be checked */ 37963786Sarutz /* 37973786Sarutz * if (un->un_throttle > 1) { 37983786Sarutz * ASSERT(un->un_ncmds >= 0); 37993786Sarutz * un->un_throttle = un->un_ncmds; 38003786Sarutz * } 38013786Sarutz */ 38023786Sarutz un->un_reissued_timeid = 38037224Scth timeout(dcdrestart, (caddr_t)un, 38043786Sarutz DCD_BSY_TIMEOUT/500); 38053786Sarutz mutex_exit(DCD_MUTEX); 38063786Sarutz return; 38073786Sarutz } 38083786Sarutz DCD_DO_ERRSTATS(un, dcd_transerrs); 38093786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 38103786Sarutz "dcdrestart transport failed (%x)\n", status); 38113786Sarutz bp->b_resid = bp->b_bcount; 38123786Sarutz SET_BP_ERROR(bp, EIO); 38133786Sarutz 38143786Sarutz DCD_DO_KSTATS(un, kstat_waitq_exit, bp); 38153786Sarutz un->un_reissued_timeid = 0L; 38163786Sarutz dcddone_and_mutex_exit(un, bp); 38173786Sarutz return; 38183786Sarutz } 38193786Sarutz mutex_enter(DCD_MUTEX); 38203786Sarutz } 38213786Sarutz un->un_reissued_timeid = 0L; 38223786Sarutz mutex_exit(DCD_MUTEX); 38233786Sarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdrestart done\n"); 38243786Sarutz } 38253786Sarutz 38263786Sarutz /* 38273786Sarutz * This routine gets called to reset the throttle to its saved 38283786Sarutz * value wheneven we lower the throttle. 38293786Sarutz */ 38303786Sarutz void 38313786Sarutz dcd_reset_throttle(caddr_t arg) 38323786Sarutz { 38333786Sarutz struct dcd_disk *un = (struct dcd_disk *)arg; 38343786Sarutz struct diskhd *dp; 38353786Sarutz 38363786Sarutz mutex_enter(DCD_MUTEX); 38373786Sarutz dp = &un->un_utab; 38383786Sarutz 38393786Sarutz /* 38403786Sarutz * start any commands that didn't start while throttling. 38413786Sarutz */ 38423786Sarutz if (dp->b_actf && (un->un_ncmds < un->un_throttle) && 38433786Sarutz (dp->b_forw == NULL)) { 38443786Sarutz dcdstart(un); 38453786Sarutz } 38463786Sarutz mutex_exit(DCD_MUTEX); 38473786Sarutz } 38483786Sarutz 38493786Sarutz 38503786Sarutz /* 38513786Sarutz * This routine handles the case when a TRAN_BUSY is 38523786Sarutz * returned by HBA. 38533786Sarutz * 38543786Sarutz * If there are some commands already in the transport, the 38553786Sarutz * bp can be put back on queue and it will 38563786Sarutz * be retried when the queue is emptied after command 38573786Sarutz * completes. But if there is no command in the tranport 38583786Sarutz * and it still return busy, we have to retry the command 38593786Sarutz * after some time like 10ms. 38603786Sarutz */ 38613786Sarutz /* ARGSUSED0 */ 38623786Sarutz static void 38633786Sarutz dcd_handle_tran_busy(struct buf *bp, struct diskhd *dp, struct dcd_disk *un) 38643786Sarutz { 38653786Sarutz ASSERT(mutex_owned(DCD_MUTEX)); 38663786Sarutz 38673786Sarutz 38683786Sarutz if (dp->b_forw == NULL || dp->b_forw == bp) { 38693786Sarutz dp->b_forw = bp; 38703786Sarutz } else if (dp->b_forw != bp) { 38713786Sarutz bp->b_actf = dp->b_actf; 38723786Sarutz dp->b_actf = bp; 38733786Sarutz 38743786Sarutz } 38753786Sarutz if (!un->un_reissued_timeid) { 38763786Sarutz un->un_reissued_timeid = 38777224Scth timeout(dcdrestart, (caddr_t)un, DCD_BSY_TIMEOUT/500); 38783786Sarutz } 38793786Sarutz } 38803786Sarutz 38813786Sarutz static int 38823786Sarutz dcd_write_deviceid(struct dcd_disk *un) 38833786Sarutz { 38843786Sarutz 38853786Sarutz int status; 38863786Sarutz diskaddr_t blk; 38873786Sarutz struct udcd_cmd ucmd; 38883786Sarutz struct dcd_cmd cdb; 38893786Sarutz struct dk_devid *dkdevid; 38903786Sarutz uint_t *ip, chksum; 38913786Sarutz int i; 38923786Sarutz dev_t dev; 38933786Sarutz 38943786Sarutz mutex_exit(DCD_MUTEX); 38953786Sarutz if (cmlb_get_devid_block(un->un_dklbhandle, &blk, 0)) { 38963786Sarutz mutex_enter(DCD_MUTEX); 38973786Sarutz return (EINVAL); 38983786Sarutz } 38993786Sarutz mutex_enter(DCD_MUTEX); 39003786Sarutz 39013786Sarutz /* Allocate the buffer */ 39023786Sarutz dkdevid = kmem_zalloc(un->un_secsize, KM_SLEEP); 39033786Sarutz 39043786Sarutz /* Fill in the revision */ 39053786Sarutz dkdevid->dkd_rev_hi = DK_DEVID_REV_MSB; 39063786Sarutz dkdevid->dkd_rev_lo = DK_DEVID_REV_LSB; 39073786Sarutz 39083786Sarutz /* Copy in the device id */ 39093786Sarutz bcopy(un->un_devid, &dkdevid->dkd_devid, 39103786Sarutz ddi_devid_sizeof(un->un_devid)); 39113786Sarutz 39123786Sarutz /* Calculate the chksum */ 39133786Sarutz chksum = 0; 39143786Sarutz ip = (uint_t *)dkdevid; 39153786Sarutz for (i = 0; i < ((un->un_secsize - sizeof (int))/sizeof (int)); i++) 39163786Sarutz chksum ^= ip[i]; 39173786Sarutz 39183786Sarutz /* Fill in the checksum */ 39193786Sarutz DKD_FORMCHKSUM(chksum, dkdevid); 39203786Sarutz 39213786Sarutz (void) bzero((caddr_t)&ucmd, sizeof (ucmd)); 39223786Sarutz (void) bzero((caddr_t)&cdb, sizeof (struct dcd_cmd)); 39233786Sarutz 39243786Sarutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) { 39253786Sarutz cdb.cmd = ATA_WRITE_DMA; 39263786Sarutz } else { 39273786Sarutz if (un->un_dp->options & BLOCK_MODE) 39283786Sarutz cdb.cmd = ATA_WRITE_MULTIPLE; 39293786Sarutz else 39303786Sarutz cdb.cmd = ATA_WRITE; 39313786Sarutz } 39323786Sarutz cdb.size = un->un_secsize; 39333786Sarutz cdb.sector_num.lba_num = blk; 39343786Sarutz cdb.address_mode = ADD_LBA_MODE; 39353786Sarutz cdb.direction = DATA_WRITE; 39363786Sarutz 39373786Sarutz ucmd.udcd_flags = UDCD_WRITE; 39383786Sarutz ucmd.udcd_cmd = &cdb; 39393786Sarutz ucmd.udcd_bufaddr = (caddr_t)dkdevid; 39403786Sarutz ucmd.udcd_buflen = un->un_secsize; 39413786Sarutz ucmd.udcd_flags |= UDCD_SILENT; 39423786Sarutz dev = makedevice(ddi_driver_major(DCD_DEVINFO), 39433786Sarutz ddi_get_instance(DCD_DEVINFO) << DCDUNIT_SHIFT); 39443786Sarutz mutex_exit(DCD_MUTEX); 39453786Sarutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE); 39463786Sarutz mutex_enter(DCD_MUTEX); 39473786Sarutz 39483786Sarutz kmem_free(dkdevid, un->un_secsize); 39493786Sarutz return (status); 39503786Sarutz } 39513786Sarutz 39523786Sarutz static int 39533786Sarutz dcd_read_deviceid(struct dcd_disk *un) 39543786Sarutz { 39553786Sarutz int status; 39563786Sarutz diskaddr_t blk; 39573786Sarutz struct udcd_cmd ucmd; 39583786Sarutz struct dcd_cmd cdb; 39593786Sarutz struct dk_devid *dkdevid; 39603786Sarutz uint_t *ip; 39613786Sarutz int chksum; 39623786Sarutz int i, sz; 39633786Sarutz dev_t dev; 39643786Sarutz 39653786Sarutz mutex_exit(DCD_MUTEX); 39663786Sarutz if (cmlb_get_devid_block(un->un_dklbhandle, &blk, 0)) { 39673786Sarutz mutex_enter(DCD_MUTEX); 39683786Sarutz return (EINVAL); 39693786Sarutz } 39703786Sarutz mutex_enter(DCD_MUTEX); 39713786Sarutz 39723786Sarutz dkdevid = kmem_alloc(un->un_secsize, KM_SLEEP); 39733786Sarutz 39743786Sarutz (void) bzero((caddr_t)&ucmd, sizeof (ucmd)); 39753786Sarutz (void) bzero((caddr_t)&cdb, sizeof (cdb)); 39763786Sarutz 39773786Sarutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) { 39783786Sarutz cdb.cmd = ATA_READ_DMA; 39793786Sarutz } else { 39803786Sarutz if (un->un_dp->options & BLOCK_MODE) 39813786Sarutz cdb.cmd = ATA_READ_MULTIPLE; 39823786Sarutz else 39833786Sarutz cdb.cmd = ATA_READ; 39843786Sarutz } 39853786Sarutz cdb.size = un->un_secsize; 39863786Sarutz cdb.sector_num.lba_num = blk; 39873786Sarutz cdb.address_mode = ADD_LBA_MODE; 39883786Sarutz cdb.direction = DATA_READ; 39893786Sarutz 39903786Sarutz ucmd.udcd_flags = UDCD_READ; 39913786Sarutz ucmd.udcd_cmd = &cdb; 39923786Sarutz ucmd.udcd_bufaddr = (caddr_t)dkdevid; 39933786Sarutz ucmd.udcd_buflen = un->un_secsize; 39943786Sarutz ucmd.udcd_flags |= UDCD_SILENT; 39953786Sarutz dev = makedevice(ddi_driver_major(DCD_DEVINFO), 39963786Sarutz ddi_get_instance(DCD_DEVINFO) << DCDUNIT_SHIFT); 39973786Sarutz mutex_exit(DCD_MUTEX); 39983786Sarutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE); 39993786Sarutz mutex_enter(DCD_MUTEX); 40003786Sarutz 40013786Sarutz if (status != 0) { 40023786Sarutz kmem_free((caddr_t)dkdevid, un->un_secsize); 40033786Sarutz return (status); 40043786Sarutz } 40053786Sarutz 40063786Sarutz /* Validate the revision */ 40073786Sarutz 40083786Sarutz if ((dkdevid->dkd_rev_hi != DK_DEVID_REV_MSB) || 40093786Sarutz (dkdevid->dkd_rev_lo != DK_DEVID_REV_LSB)) { 40103786Sarutz kmem_free((caddr_t)dkdevid, un->un_secsize); 40113786Sarutz return (EINVAL); 40123786Sarutz } 40133786Sarutz 40143786Sarutz /* Calculate the checksum */ 40153786Sarutz chksum = 0; 40163786Sarutz ip = (uint_t *)dkdevid; 40173786Sarutz for (i = 0; i < ((un->un_secsize - sizeof (int))/sizeof (int)); i++) 40183786Sarutz chksum ^= ip[i]; 40193786Sarutz 40203786Sarutz /* Compare the checksums */ 40213786Sarutz 40223786Sarutz if (DKD_GETCHKSUM(dkdevid) != chksum) { 40233786Sarutz kmem_free((caddr_t)dkdevid, un->un_secsize); 40243786Sarutz return (EINVAL); 40253786Sarutz } 40263786Sarutz 40273786Sarutz /* VAlidate the device id */ 40283786Sarutz if (ddi_devid_valid((ddi_devid_t)&dkdevid->dkd_devid) != DDI_SUCCESS) { 40293786Sarutz kmem_free((caddr_t)dkdevid, un->un_secsize); 40303786Sarutz return (EINVAL); 40313786Sarutz } 40323786Sarutz 40333786Sarutz /* return a copy of the device id */ 40343786Sarutz sz = ddi_devid_sizeof((ddi_devid_t)&dkdevid->dkd_devid); 40353786Sarutz un->un_devid = (ddi_devid_t)kmem_alloc(sz, KM_SLEEP); 40363786Sarutz bcopy(&dkdevid->dkd_devid, un->un_devid, sz); 40373786Sarutz kmem_free((caddr_t)dkdevid, un->un_secsize); 40383786Sarutz 40393786Sarutz return (0); 40403786Sarutz } 40413786Sarutz 40423786Sarutz /* 40433786Sarutz * Return the device id for the device. 40443786Sarutz * 1. If the device ID exists then just return it - nothing to do in that case. 40453786Sarutz * 2. Build one from the drives model number and serial number. 40463786Sarutz * 3. If there is a problem in building it from serial/model #, then try 40473786Sarutz * to read it from the acyl region of the disk. 40483786Sarutz * Note: If this function is unable to return a valid ID then the calling 40493786Sarutz * point will invoke the routine to create a fabricated ID ans stor it on the 40503786Sarutz * acyl region of the disk. 40513786Sarutz */ 40523786Sarutz static ddi_devid_t 40533786Sarutz dcd_get_devid(struct dcd_disk *un) 40543786Sarutz { 40553786Sarutz int rc; 40563786Sarutz 40573786Sarutz /* If already registered, return that value */ 40583786Sarutz if (un->un_devid != NULL) 40593786Sarutz return (un->un_devid); 40603786Sarutz 40613786Sarutz /* Build a devid from model and serial number, if present */ 40623786Sarutz rc = dcd_make_devid_from_serial(un); 40633786Sarutz 40643786Sarutz if (rc != DDI_SUCCESS) { 40653786Sarutz /* Read the devid from the disk. */ 40663786Sarutz if (dcd_read_deviceid(un)) 40673786Sarutz return (NULL); 40683786Sarutz } 40693786Sarutz 40703786Sarutz (void) ddi_devid_register(DCD_DEVINFO, un->un_devid); 40713786Sarutz return (un->un_devid); 40723786Sarutz } 40733786Sarutz 40743786Sarutz 40753786Sarutz static ddi_devid_t 40763786Sarutz dcd_create_devid(struct dcd_disk *un) 40773786Sarutz { 40783786Sarutz if (ddi_devid_init(DCD_DEVINFO, DEVID_FAB, 0, NULL, (ddi_devid_t *) 40793786Sarutz &un->un_devid) == DDI_FAILURE) 40803786Sarutz return (NULL); 40813786Sarutz 40823786Sarutz if (dcd_write_deviceid(un)) { 40833786Sarutz ddi_devid_free(un->un_devid); 40843786Sarutz un->un_devid = NULL; 40853786Sarutz return (NULL); 40863786Sarutz } 40873786Sarutz 40883786Sarutz (void) ddi_devid_register(DCD_DEVINFO, un->un_devid); 40893786Sarutz return (un->un_devid); 40903786Sarutz } 40913786Sarutz 40923786Sarutz /* 40933786Sarutz * Build a devid from the model and serial number, if present 40943786Sarutz * Return DDI_SUCCESS or DDI_FAILURE. 40953786Sarutz */ 40963786Sarutz static int 40973786Sarutz dcd_make_devid_from_serial(struct dcd_disk *un) 40983786Sarutz { 40993786Sarutz int rc = DDI_SUCCESS; 41003786Sarutz char *hwid; 41013786Sarutz char *model; 41023786Sarutz int model_len; 41033786Sarutz char *serno; 41043786Sarutz int serno_len; 41053786Sarutz int total_len; 41063786Sarutz 41073786Sarutz /* initialize the model and serial number information */ 41083786Sarutz model = un->un_dcd->dcd_ident->dcd_model; 41093786Sarutz model_len = DCD_MODEL_NUMBER_LENGTH; 41103786Sarutz serno = un->un_dcd->dcd_ident->dcd_drvser; 41113786Sarutz serno_len = DCD_SERIAL_NUMBER_LENGTH; 41123786Sarutz 41133786Sarutz /* Verify the model and serial number */ 41143786Sarutz dcd_validate_model_serial(model, &model_len, model_len); 41153786Sarutz if (model_len == 0) { 41163786Sarutz rc = DDI_FAILURE; 41173786Sarutz goto out; 41183786Sarutz } 41193786Sarutz dcd_validate_model_serial(serno, &serno_len, serno_len); 41203786Sarutz if (serno_len == 0) { 41213786Sarutz rc = DDI_FAILURE; 41223786Sarutz goto out; 41233786Sarutz } 41243786Sarutz 41253786Sarutz /* 41263786Sarutz * The device ID will be concatenation of the model number, 41273786Sarutz * the '=' separator, the serial number. Allocate 41283786Sarutz * the string and concatenate the components. 41293786Sarutz */ 41303786Sarutz total_len = model_len + 1 + serno_len; 41313786Sarutz hwid = kmem_alloc(total_len, KM_SLEEP); 41323786Sarutz bcopy((caddr_t)model, (caddr_t)hwid, model_len); 41333786Sarutz bcopy((caddr_t)"=", (caddr_t)&hwid[model_len], 1); 41343786Sarutz bcopy((caddr_t)serno, (caddr_t)&hwid[model_len + 1], serno_len); 41353786Sarutz 41363786Sarutz /* Initialize the device ID, trailing NULL not included */ 41373786Sarutz rc = ddi_devid_init(DCD_DEVINFO, DEVID_ATA_SERIAL, total_len, 41383786Sarutz hwid, (ddi_devid_t *)&un->un_devid); 41393786Sarutz 41403786Sarutz /* Free the allocated string */ 41413786Sarutz kmem_free(hwid, total_len); 41423786Sarutz 41433786Sarutz out: return (rc); 41443786Sarutz } 41453786Sarutz 41463786Sarutz /* 41473786Sarutz * Test for a valid model or serial number. Assume that a valid representation 41483786Sarutz * contains at least one character that is neither a space, 0 digit, or NULL. 41493786Sarutz * Trim trailing blanks and NULLS from returned length. 41503786Sarutz */ 41513786Sarutz static void 41523786Sarutz dcd_validate_model_serial(char *str, int *retlen, int totallen) 41533786Sarutz { 41543786Sarutz char ch; 41553786Sarutz boolean_t ret = B_FALSE; 41563786Sarutz int i; 41573786Sarutz int tb; 41583786Sarutz 41593786Sarutz for (i = 0, tb = 0; i < totallen; i++) { 41603786Sarutz ch = *str++; 41613786Sarutz if ((ch != ' ') && (ch != '\0') && (ch != '0')) 41623786Sarutz ret = B_TRUE; 41633786Sarutz if ((ch == ' ') || (ch == '\0')) 41643786Sarutz tb++; 41653786Sarutz else 41663786Sarutz tb = 0; 41673786Sarutz } 41683786Sarutz 41693786Sarutz if (ret == B_TRUE) { 41703786Sarutz /* Atleast one non 0 or blank character. */ 41713786Sarutz *retlen = totallen - tb; 41723786Sarutz } else { 41733786Sarutz *retlen = 0; 41743786Sarutz } 41753786Sarutz } 41763786Sarutz 41773786Sarutz #ifndef lint 41783786Sarutz void 41793786Sarutz clean_print(dev_info_t *dev, char *label, uint_t level, 41803786Sarutz char *title, char *data, int len) 41813786Sarutz { 41823786Sarutz int i; 41833786Sarutz char buf[256]; 41843786Sarutz 41853786Sarutz (void) sprintf(buf, "%s:", title); 41863786Sarutz for (i = 0; i < len; i++) { 41873786Sarutz (void) sprintf(&buf[strlen(buf)], "0x%x ", (data[i] & 0xff)); 41883786Sarutz } 41893786Sarutz (void) sprintf(&buf[strlen(buf)], "\n"); 41903786Sarutz 41913786Sarutz dcd_log(dev, label, level, "%s", buf); 41923786Sarutz } 41933786Sarutz #endif /* Not lint */ 41943786Sarutz 41953786Sarutz #ifndef lint 41963786Sarutz /* 41973786Sarutz * Print a piece of inquiry data- cleaned up for non-printable characters 41983786Sarutz * and stopping at the first space character after the beginning of the 41993786Sarutz * passed string; 42003786Sarutz */ 42013786Sarutz 42023786Sarutz void 42033786Sarutz inq_fill(char *p, int l, char *s) 42043786Sarutz { 42053786Sarutz unsigned i = 0; 42063786Sarutz char c; 42073786Sarutz 42083786Sarutz while (i++ < l) { 42093786Sarutz if ((c = *p++) < ' ' || c >= 0177) { 42103786Sarutz c = '*'; 42113786Sarutz } else if (i != 1 && c == ' ') { 42123786Sarutz break; 42133786Sarutz } 42143786Sarutz *s++ = c; 42153786Sarutz } 42163786Sarutz *s++ = 0; 42173786Sarutz } 42183786Sarutz #endif /* Not lint */ 42193786Sarutz 42203786Sarutz char * 42213786Sarutz dcd_sname(uchar_t status) 42223786Sarutz { 42233786Sarutz switch (status & STATUS_ATA_MASK) { 42243786Sarutz case STATUS_GOOD: 42253786Sarutz return ("good status"); 42263786Sarutz 42273786Sarutz case STATUS_ATA_BUSY: 42283786Sarutz return ("busy"); 42293786Sarutz 42303786Sarutz default: 42313786Sarutz return ("<unknown status>"); 42323786Sarutz } 42333786Sarutz } 42343786Sarutz 42353786Sarutz /* ARGSUSED0 */ 42363786Sarutz char * 42373786Sarutz dcd_rname(int reason) 42383786Sarutz { 42393786Sarutz static char *rnames[] = { 42403786Sarutz "cmplt", 42413786Sarutz "incomplete", 42423786Sarutz "dma_derr", 42433786Sarutz "tran_err", 42443786Sarutz "reset", 42453786Sarutz "aborted", 42463786Sarutz "timeout", 42473786Sarutz "data_ovr", 42483786Sarutz }; 42493786Sarutz if (reason > CMD_DATA_OVR) { 42503786Sarutz return ("<unknown reason>"); 42513786Sarutz } else { 42523786Sarutz return (rnames[reason]); 42533786Sarutz } 42543786Sarutz } 42553786Sarutz 42563786Sarutz 42573786Sarutz 42583786Sarutz /* ARGSUSED0 */ 42593786Sarutz int 42603786Sarutz dcd_check_wp(dev_t dev) 42613786Sarutz { 42623786Sarutz 42633786Sarutz return (0); 42643786Sarutz } 42653786Sarutz 42663786Sarutz /* 42673786Sarutz * Create device error kstats 42683786Sarutz */ 42693786Sarutz static int 42703786Sarutz dcd_create_errstats(struct dcd_disk *un, int instance) 42713786Sarutz { 42723786Sarutz 42733786Sarutz char kstatname[KSTAT_STRLEN]; 42743786Sarutz 42753786Sarutz if (un->un_errstats == (kstat_t *)0) { 42763786Sarutz (void) sprintf(kstatname, "dad%d,error", instance); 42773786Sarutz un->un_errstats = kstat_create("daderror", instance, kstatname, 42783786Sarutz "device_error", KSTAT_TYPE_NAMED, 42793786Sarutz sizeof (struct dcd_errstats)/ sizeof (kstat_named_t), 42803786Sarutz KSTAT_FLAG_PERSISTENT); 42813786Sarutz 42823786Sarutz if (un->un_errstats) { 42833786Sarutz struct dcd_errstats *dtp; 42843786Sarutz 42853786Sarutz dtp = (struct dcd_errstats *)un->un_errstats->ks_data; 42863786Sarutz kstat_named_init(&dtp->dcd_softerrs, "Soft Errors", 42873786Sarutz KSTAT_DATA_UINT32); 42883786Sarutz kstat_named_init(&dtp->dcd_harderrs, "Hard Errors", 42893786Sarutz KSTAT_DATA_UINT32); 42903786Sarutz kstat_named_init(&dtp->dcd_transerrs, 42913786Sarutz "Transport Errors", KSTAT_DATA_UINT32); 42923786Sarutz kstat_named_init(&dtp->dcd_model, "Model", 42933786Sarutz KSTAT_DATA_CHAR); 42943786Sarutz kstat_named_init(&dtp->dcd_revision, "Revision", 42953786Sarutz KSTAT_DATA_CHAR); 42963786Sarutz kstat_named_init(&dtp->dcd_serial, "Serial No", 42973786Sarutz KSTAT_DATA_CHAR); 42983786Sarutz kstat_named_init(&dtp->dcd_capacity, "Size", 42993786Sarutz KSTAT_DATA_ULONGLONG); 43003786Sarutz kstat_named_init(&dtp->dcd_rq_media_err, "Media Error", 43013786Sarutz KSTAT_DATA_UINT32); 43023786Sarutz kstat_named_init(&dtp->dcd_rq_ntrdy_err, 43033786Sarutz "Device Not Ready", KSTAT_DATA_UINT32); 43043786Sarutz kstat_named_init(&dtp->dcd_rq_nodev_err, " No Device", 43053786Sarutz KSTAT_DATA_UINT32); 43063786Sarutz kstat_named_init(&dtp->dcd_rq_recov_err, "Recoverable", 43073786Sarutz KSTAT_DATA_UINT32); 43083786Sarutz kstat_named_init(&dtp->dcd_rq_illrq_err, 43093786Sarutz "Illegal Request", KSTAT_DATA_UINT32); 43103786Sarutz 43113786Sarutz un->un_errstats->ks_private = un; 43123786Sarutz un->un_errstats->ks_update = nulldev; 43133786Sarutz kstat_install(un->un_errstats); 43143786Sarutz 43153786Sarutz (void) strncpy(&dtp->dcd_model.value.c[0], 43163786Sarutz un->un_dcd->dcd_ident->dcd_model, 16); 43173786Sarutz (void) strncpy(&dtp->dcd_serial.value.c[0], 43183786Sarutz un->un_dcd->dcd_ident->dcd_drvser, 16); 43193786Sarutz (void) strncpy(&dtp->dcd_revision.value.c[0], 43203786Sarutz un->un_dcd->dcd_ident->dcd_fw, 8); 43213786Sarutz dtp->dcd_capacity.value.ui64 = 43223786Sarutz (uint64_t)((uint64_t)un->un_diskcapacity * 43233786Sarutz (uint64_t)un->un_lbasize); 43243786Sarutz } 43253786Sarutz } 43263786Sarutz return (0); 43273786Sarutz } 43283786Sarutz 43293786Sarutz 43303786Sarutz /* 43313786Sarutz * This has been moved from DADA layer as this does not do anything other than 43323786Sarutz * retrying the command when it is busy or it does not complete 43333786Sarutz */ 43343786Sarutz int 43353786Sarutz dcd_poll(struct dcd_pkt *pkt) 43363786Sarutz { 43373786Sarutz int busy_count, rval = -1, savef; 43383786Sarutz clock_t savet; 43393786Sarutz void (*savec)(); 43403786Sarutz 43413786Sarutz 43423786Sarutz /* 43433786Sarutz * Save old flags 43443786Sarutz */ 43453786Sarutz savef = pkt->pkt_flags; 43463786Sarutz savec = pkt->pkt_comp; 43473786Sarutz savet = pkt->pkt_time; 43483786Sarutz 43493786Sarutz pkt->pkt_flags |= FLAG_NOINTR; 43503786Sarutz 43513786Sarutz 43523786Sarutz /* 43533786Sarutz * Set the Pkt_comp to NULL 43543786Sarutz */ 43553786Sarutz 43563786Sarutz pkt->pkt_comp = 0; 43573786Sarutz 43583786Sarutz /* 43593786Sarutz * Set the Pkt time for the polled command 43603786Sarutz */ 43613786Sarutz if (pkt->pkt_time == 0) { 43623786Sarutz pkt->pkt_time = DCD_POLL_TIMEOUT; 43633786Sarutz } 43643786Sarutz 43653786Sarutz 43663786Sarutz /* Now transport the command */ 43673786Sarutz for (busy_count = 0; busy_count < dcd_poll_busycnt; busy_count++) { 43683786Sarutz if ((rval = dcd_transport(pkt)) == TRAN_ACCEPT) { 43693786Sarutz if (pkt->pkt_reason == CMD_INCOMPLETE && 43703786Sarutz pkt->pkt_state == 0) { 43713786Sarutz delay(100); 43723786Sarutz } else if (pkt->pkt_reason == CMD_CMPLT) { 43733786Sarutz rval = 0; 43743786Sarutz break; 43753786Sarutz } 43763786Sarutz } 43773786Sarutz if (rval == TRAN_BUSY) { 43783786Sarutz delay(100); 43793786Sarutz continue; 43803786Sarutz } 43813786Sarutz } 43823786Sarutz 43833786Sarutz pkt->pkt_flags = savef; 43843786Sarutz pkt->pkt_comp = savec; 43853786Sarutz pkt->pkt_time = savet; 43863786Sarutz return (rval); 43873786Sarutz } 43883786Sarutz 43893786Sarutz 43903786Sarutz void 43913786Sarutz dcd_translate(struct dadkio_status32 *statp, struct udcd_cmd *cmdp) 43923786Sarutz { 43933786Sarutz if (cmdp->udcd_status_reg & STATUS_ATA_BUSY) 43943786Sarutz statp->status = DADKIO_STAT_NOT_READY; 43953786Sarutz else if (cmdp->udcd_status_reg & STATUS_ATA_DWF) 43963786Sarutz statp->status = DADKIO_STAT_HARDWARE_ERROR; 43973786Sarutz else if (cmdp->udcd_status_reg & STATUS_ATA_CORR) 43983786Sarutz statp->status = DADKIO_STAT_SOFT_ERROR; 43993786Sarutz else if (cmdp->udcd_status_reg & STATUS_ATA_ERR) { 44003786Sarutz /* 44013786Sarutz * The error register is valid only when BSY and DRQ not set 44023786Sarutz * Assumed that HBA has checked this before it gives the data 44033786Sarutz */ 44043786Sarutz if (cmdp->udcd_error_reg & ERR_AMNF) 44053786Sarutz statp->status = DADKIO_STAT_NOT_FORMATTED; 44063786Sarutz else if (cmdp->udcd_error_reg & ERR_TKONF) 44073786Sarutz statp->status = DADKIO_STAT_NOT_FORMATTED; 44083786Sarutz else if (cmdp->udcd_error_reg & ERR_ABORT) 44093786Sarutz statp->status = DADKIO_STAT_ILLEGAL_REQUEST; 44103786Sarutz else if (cmdp->udcd_error_reg & ERR_IDNF) 44113786Sarutz statp->status = DADKIO_STAT_NOT_FORMATTED; 44123786Sarutz else if (cmdp->udcd_error_reg & ERR_UNC) 44133786Sarutz statp->status = DADKIO_STAT_BUS_ERROR; 44143786Sarutz else if (cmdp->udcd_error_reg & ERR_BBK) 44153786Sarutz statp->status = DADKIO_STAT_MEDIUM_ERROR; 44163786Sarutz } else 44173786Sarutz statp->status = DADKIO_STAT_NO_ERROR; 44183786Sarutz } 44193786Sarutz 44203786Sarutz static void 44213786Sarutz dcd_flush_cache(struct dcd_disk *un) 44223786Sarutz { 44233786Sarutz struct dcd_pkt *pkt; 44243786Sarutz int retry_count; 44253786Sarutz 44263786Sarutz 44273786Sarutz if ((pkt = dcd_init_pkt(ROUTE, NULL, NULL, 44283786Sarutz (uint32_t)sizeof (struct dcd_cmd), 2, PP_LEN, 44293786Sarutz PKT_CONSISTENT, NULL_FUNC, NULL)) == NULL) { 44303786Sarutz return; 44313786Sarutz } 44323786Sarutz 44333786Sarutz makecommand(pkt, 0, ATA_FLUSH_CACHE, 0, ADD_LBA_MODE, 0, 44343786Sarutz NO_DATA_XFER, 0); 44353786Sarutz 44363786Sarutz /* 44373786Sarutz * Send the command. There are chances it might fail on some 44383786Sarutz * disks since it is not a mandatory command as per ata-4. Try 44393786Sarutz * 3 times if it fails. The retry count has been randomly selected. 44403786Sarutz * There is a need for retry since as per the spec FLUSH CACHE can fail 44413786Sarutz * as a result of unrecoverable error encountered during execution 44423786Sarutz * of writing data and subsequent command should continue flushing 44433786Sarutz * cache. 44443786Sarutz */ 44453786Sarutz for (retry_count = 0; retry_count < 3; retry_count++) { 44463786Sarutz /* 44473786Sarutz * Set the packet fields. 44483786Sarutz */ 44493786Sarutz pkt->pkt_comp = 0; 44503786Sarutz pkt->pkt_time = DCD_POLL_TIMEOUT; 44513786Sarutz pkt->pkt_flags |= FLAG_FORCENOINTR; 44523786Sarutz pkt->pkt_flags |= FLAG_NOINTR; 44533786Sarutz if (dcd_transport(pkt) == TRAN_ACCEPT) { 44543786Sarutz if (pkt->pkt_reason == CMD_CMPLT) { 44553786Sarutz break; 44563786Sarutz } 44573786Sarutz } 44583786Sarutz /* 44593786Sarutz * Note the wait time value of 100ms is same as in the 44603786Sarutz * dcd_poll routine. 44613786Sarutz */ 44623786Sarutz drv_usecwait(1000000); 44633786Sarutz } 44643786Sarutz (void) dcd_destroy_pkt(pkt); 44653786Sarutz } 44663786Sarutz 44673786Sarutz static int 44683786Sarutz dcd_send_lb_rw_cmd(dev_info_t *devi, void *bufaddr, 44693786Sarutz diskaddr_t start_block, size_t reqlength, uchar_t cmd) 44703786Sarutz { 44713786Sarutz struct dcd_pkt *pkt; 44723786Sarutz struct buf *bp; 44733786Sarutz diskaddr_t real_addr = start_block; 44743786Sarutz size_t buffer_size = reqlength; 44753786Sarutz uchar_t command, tmp; 44763786Sarutz int i, rval = 0; 44773786Sarutz struct dcd_disk *un; 44783786Sarutz 44793786Sarutz un = ddi_get_soft_state(dcd_state, ddi_get_instance(devi)); 44803786Sarutz if (un == NULL) 44813786Sarutz return (ENXIO); 44823786Sarutz 44833786Sarutz bp = dcd_alloc_consistent_buf(ROUTE, (struct buf *)NULL, 44843786Sarutz buffer_size, B_READ, NULL_FUNC, NULL); 44853786Sarutz if (!bp) { 44863786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 44873786Sarutz "no bp for disk label\n"); 44883786Sarutz return (ENOMEM); 44893786Sarutz } 44903786Sarutz 44913786Sarutz pkt = dcd_init_pkt(ROUTE, (struct dcd_pkt *)NULL, 44923786Sarutz bp, (uint32_t)sizeof (struct dcd_cmd), 2, PP_LEN, 44933786Sarutz PKT_CONSISTENT, NULL_FUNC, NULL); 44943786Sarutz 44953786Sarutz if (!pkt) { 44963786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 44973786Sarutz "no memory for disk label\n"); 44983786Sarutz dcd_free_consistent_buf(bp); 44993786Sarutz return (ENOMEM); 45003786Sarutz } 45013786Sarutz 45023786Sarutz if (cmd == TG_READ) { 45033786Sarutz bzero(bp->b_un.b_addr, buffer_size); 45043786Sarutz tmp = DATA_READ; 45053786Sarutz } else { 45063786Sarutz bcopy((caddr_t)bufaddr, bp->b_un.b_addr, buffer_size); 45073786Sarutz tmp = DATA_WRITE; 45083786Sarutz } 45093786Sarutz 45103786Sarutz mutex_enter(DCD_MUTEX); 45113786Sarutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) { 45123786Sarutz if (cmd == TG_READ) { 45133786Sarutz command = ATA_READ_DMA; 45143786Sarutz } else { 45153786Sarutz command = ATA_WRITE_DMA; 45163786Sarutz } 45173786Sarutz } else { 45183786Sarutz if (cmd == TG_READ) { 45193786Sarutz if (un->un_dp->options & BLOCK_MODE) 45203786Sarutz command = ATA_READ_MULTIPLE; 45213786Sarutz else 45223786Sarutz command = ATA_READ; 45233786Sarutz } else { 45243786Sarutz if (un->un_dp->options & BLOCK_MODE) 45253786Sarutz command = ATA_READ_MULTIPLE; 45263786Sarutz else 45273786Sarutz command = ATA_WRITE; 45283786Sarutz } 45293786Sarutz } 45303786Sarutz mutex_exit(DCD_MUTEX); 45313786Sarutz (void) makecommand(pkt, 0, command, real_addr, ADD_LBA_MODE, 45323786Sarutz buffer_size, tmp, 0); 45333786Sarutz 45343786Sarutz for (i = 0; i < 3; i++) { 45353786Sarutz if (dcd_poll(pkt) || SCBP_C(pkt) != STATUS_GOOD || 45363786Sarutz (pkt->pkt_state & STATE_XFERRED_DATA) == 0 || 45373786Sarutz (pkt->pkt_resid != 0)) { 45383786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 45393786Sarutz "Status %x, state %x, resid %lx\n", 45403786Sarutz SCBP_C(pkt), pkt->pkt_state, pkt->pkt_resid); 45413786Sarutz rval = EIO; 45423786Sarutz } else { 45433786Sarutz break; 45443786Sarutz } 45453786Sarutz } 45463786Sarutz 45473786Sarutz if (rval != 0) { 45483786Sarutz dcd_destroy_pkt(pkt); 45493786Sarutz dcd_free_consistent_buf(bp); 45503786Sarutz return (EIO); 45513786Sarutz } 45523786Sarutz 45533786Sarutz if (cmd == TG_READ) { 45543786Sarutz bcopy(bp->b_un.b_addr, bufaddr, reqlength); 45553786Sarutz rval = 0; 45563786Sarutz } 45573786Sarutz 45583786Sarutz dcd_destroy_pkt(pkt); 45593786Sarutz dcd_free_consistent_buf(bp); 45603786Sarutz return (rval); 45613786Sarutz } 45623786Sarutz 45633786Sarutz static int dcd_compute_dk_capacity(struct dcd_device *devp, 45643786Sarutz diskaddr_t *capacity) 45653786Sarutz { 45663786Sarutz diskaddr_t cap; 45673786Sarutz diskaddr_t no_of_lbasec; 45683786Sarutz 45693786Sarutz cap = devp->dcd_ident->dcd_fixcyls * 45703786Sarutz devp->dcd_ident->dcd_heads * 45713786Sarutz devp->dcd_ident->dcd_sectors; 45723786Sarutz no_of_lbasec = devp->dcd_ident->dcd_addrsec[1]; 45733786Sarutz no_of_lbasec = no_of_lbasec << 16; 45743786Sarutz no_of_lbasec = no_of_lbasec | devp->dcd_ident->dcd_addrsec[0]; 45753786Sarutz 45763786Sarutz if (no_of_lbasec > cap) { 45773786Sarutz cap = no_of_lbasec; 45783786Sarutz } 45793786Sarutz 45803786Sarutz if (cap != ((uint32_t)-1)) 45813786Sarutz *capacity = cap; 45823786Sarutz else 45833786Sarutz return (EINVAL); 45843786Sarutz return (0); 45853786Sarutz } 45863786Sarutz 45873786Sarutz /*ARGSUSED5*/ 45883786Sarutz static int 45893786Sarutz dcd_lb_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr, 45903786Sarutz diskaddr_t start_block, size_t reqlength, void *tg_cookie) 45913786Sarutz { 45923786Sarutz if (cmd != TG_READ && cmd != TG_WRITE) 45933786Sarutz return (EINVAL); 45943786Sarutz 45953786Sarutz return (dcd_send_lb_rw_cmd(devi, bufaddr, start_block, 45963786Sarutz reqlength, cmd)); 45973786Sarutz } 45983786Sarutz 45993786Sarutz static int 46003786Sarutz dcd_lb_getphygeom(dev_info_t *devi, cmlb_geom_t *phygeomp) 46013786Sarutz { 46023786Sarutz struct dcd_device *devp; 46033786Sarutz uint32_t no_of_lbasec, capacity, calculated_cylinders; 46043786Sarutz 46053786Sarutz devp = ddi_get_driver_private(devi); 46063786Sarutz 46073786Sarutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) { 46083786Sarutz if (devp->dcd_ident->dcd_config & ATANON_REMOVABLE) { 46093786Sarutz phygeomp->g_ncyl = devp->dcd_ident->dcd_fixcyls - 2; 46103786Sarutz phygeomp->g_acyl = 2; 46113786Sarutz phygeomp->g_nhead = devp->dcd_ident->dcd_heads; 46123786Sarutz phygeomp->g_nsect = devp->dcd_ident->dcd_sectors; 46133786Sarutz 46143786Sarutz no_of_lbasec = devp->dcd_ident->dcd_addrsec[1]; 46153786Sarutz no_of_lbasec = no_of_lbasec << 16; 46163786Sarutz no_of_lbasec = no_of_lbasec | 46173786Sarutz devp->dcd_ident->dcd_addrsec[0]; 46183786Sarutz capacity = devp->dcd_ident->dcd_fixcyls * 46193786Sarutz devp->dcd_ident->dcd_heads * 46203786Sarutz devp->dcd_ident->dcd_sectors; 46213786Sarutz if (no_of_lbasec > capacity) { 46223786Sarutz capacity = no_of_lbasec; 46233786Sarutz if (capacity > NUM_SECTORS_32G) { 46243786Sarutz /* 46253786Sarutz * if the capacity is greater than 32G, 46263786Sarutz * then 255 is the sectors per track. 46273786Sarutz * This should be good until 128G disk 46283786Sarutz * capacity, which is the current ATA-4 46293786Sarutz * limitation. 46303786Sarutz */ 46313786Sarutz phygeomp->g_nsect = 255; 46323786Sarutz } 46333786Sarutz 46343786Sarutz /* 46353786Sarutz * If the disk capacity is >= 128GB then no. of 46363786Sarutz * addressable sectors will be set to 0xfffffff 46373786Sarutz * in the IDENTIFY info. In that case set the 46383786Sarutz * no. of pcyl to the Max. 16bit value. 46393786Sarutz */ 46403786Sarutz 46413786Sarutz calculated_cylinders = (capacity) / 46423786Sarutz (phygeomp->g_nhead * phygeomp->g_nsect); 46433786Sarutz if (calculated_cylinders >= USHRT_MAX) { 46443786Sarutz phygeomp->g_ncyl = USHRT_MAX - 2; 46453786Sarutz } else { 46463786Sarutz phygeomp->g_ncyl = 46473786Sarutz calculated_cylinders - 2; 46483786Sarutz } 46493786Sarutz } 46503786Sarutz 46513786Sarutz phygeomp->g_capacity = capacity; 46523786Sarutz phygeomp->g_intrlv = 0; 46533786Sarutz phygeomp->g_rpm = 5400; 46543786Sarutz phygeomp->g_secsize = devp->dcd_ident->dcd_secsiz; 46553786Sarutz 46563786Sarutz return (0); 46573786Sarutz } else 46583786Sarutz return (ENOTSUP); 46593786Sarutz } else { 46603786Sarutz return (EINVAL); 46613786Sarutz } 46623786Sarutz } 46633786Sarutz 46643786Sarutz 46653786Sarutz /*ARGSUSED3*/ 46663786Sarutz static int 46673786Sarutz dcd_lb_getinfo(dev_info_t *devi, int cmd, void *arg, void *tg_cookie) 46683786Sarutz { 46693786Sarutz struct dcd_disk *un; 46703786Sarutz 46713786Sarutz un = ddi_get_soft_state(dcd_state, ddi_get_instance(devi)); 46723786Sarutz 46733786Sarutz if (un == NULL) 46743786Sarutz return (ENXIO); 46753786Sarutz 46763786Sarutz switch (cmd) { 46773786Sarutz case TG_GETPHYGEOM: 46783786Sarutz return (dcd_lb_getphygeom(devi, (cmlb_geom_t *)arg)); 46793786Sarutz 46803786Sarutz case TG_GETVIRTGEOM: 46813786Sarutz return (-1); 46823786Sarutz 46833786Sarutz case TG_GETCAPACITY: 46843786Sarutz case TG_GETBLOCKSIZE: 46853786Sarutz mutex_enter(DCD_MUTEX); 46863786Sarutz if (un->un_diskcapacity <= 0) { 46873786Sarutz mutex_exit(DCD_MUTEX); 46883786Sarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 46897224Scth "invalid disk capacity\n"); 46903786Sarutz return (EIO); 46913786Sarutz } 46923786Sarutz if (cmd == TG_GETCAPACITY) 46933786Sarutz *(diskaddr_t *)arg = un->un_diskcapacity; 46943786Sarutz else 46953786Sarutz *(uint32_t *)arg = DEV_BSIZE; 46963786Sarutz 46973786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "capacity %x\n", 46983786Sarutz un->un_diskcapacity); 46993786Sarutz mutex_exit(DCD_MUTEX); 47003786Sarutz return (0); 47013786Sarutz 47023786Sarutz case TG_GETATTR: 47033786Sarutz mutex_enter(DCD_MUTEX); 47043786Sarutz *(tg_attribute_t *)arg = un->un_tgattribute; 47053786Sarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 47063786Sarutz "media_is_writable %x\n", 47073786Sarutz un->un_tgattribute.media_is_writable); 47083786Sarutz mutex_exit(DCD_MUTEX); 47093786Sarutz return (0); 47103786Sarutz default: 47113786Sarutz return (ENOTTY); 47123786Sarutz } 47133786Sarutz } 4714