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