1a4aa671eSarutz /* 2a4aa671eSarutz * CDDL HEADER START 3a4aa671eSarutz * 4a4aa671eSarutz * The contents of this file are subject to the terms of the 5a4aa671eSarutz * Common Development and Distribution License (the "License"). 6a4aa671eSarutz * You may not use this file except in compliance with the License. 7a4aa671eSarutz * 8a4aa671eSarutz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9a4aa671eSarutz * or http://www.opensolaris.org/os/licensing. 10a4aa671eSarutz * See the License for the specific language governing permissions 11a4aa671eSarutz * and limitations under the License. 12a4aa671eSarutz * 13a4aa671eSarutz * When distributing Covered Code, include this CDDL HEADER in each 14a4aa671eSarutz * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15a4aa671eSarutz * If applicable, add the following below this CDDL HEADER, with the 16a4aa671eSarutz * fields enclosed by brackets "[]" replaced with your own identifying 17a4aa671eSarutz * information: Portions Copyright [yyyy] [name of copyright owner] 18a4aa671eSarutz * 19a4aa671eSarutz * CDDL HEADER END 20a4aa671eSarutz */ 21a4aa671eSarutz 22a4aa671eSarutz /* 23*744947dcSTom Erickson * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 24a4aa671eSarutz */ 25a4aa671eSarutz 26a4aa671eSarutz 27a4aa671eSarutz /* 28a4aa671eSarutz * Direct Attached disk driver for SPARC machines. 29a4aa671eSarutz */ 30a4aa671eSarutz 31a4aa671eSarutz /* 32a4aa671eSarutz * Includes, Declarations and Local Data 33a4aa671eSarutz */ 34a4aa671eSarutz #include <sys/dada/dada.h> 35a4aa671eSarutz #include <sys/dkbad.h> 36a4aa671eSarutz #include <sys/dklabel.h> 37a4aa671eSarutz #include <sys/dkio.h> 38a4aa671eSarutz #include <sys/cdio.h> 39a4aa671eSarutz #include <sys/vtoc.h> 40a4aa671eSarutz #include <sys/dada/targets/daddef.h> 41a4aa671eSarutz #include <sys/dada/targets/dadpriv.h> 42a4aa671eSarutz #include <sys/file.h> 43a4aa671eSarutz #include <sys/stat.h> 44a4aa671eSarutz #include <sys/kstat.h> 45a4aa671eSarutz #include <sys/vtrace.h> 46a4aa671eSarutz #include <sys/aio_req.h> 47a4aa671eSarutz #include <sys/note.h> 48a4aa671eSarutz #include <sys/cmlb.h> 49a4aa671eSarutz 50a4aa671eSarutz /* 51a4aa671eSarutz * Global Error Levels for Error Reporting 52a4aa671eSarutz */ 53a4aa671eSarutz int dcd_error_level = DCD_ERR_RETRYABLE; 54a4aa671eSarutz /* 55a4aa671eSarutz * Local Static Data 56a4aa671eSarutz */ 57a4aa671eSarutz 58a4aa671eSarutz static int dcd_io_time = DCD_IO_TIME; 59a4aa671eSarutz static int dcd_retry_count = DCD_RETRY_COUNT; 60a4aa671eSarutz #ifndef lint 61a4aa671eSarutz static int dcd_report_pfa = 1; 62a4aa671eSarutz #endif 63a4aa671eSarutz static int dcd_rot_delay = 4; 64a4aa671eSarutz static int dcd_poll_busycnt = DCD_POLL_TIMEOUT; 65a4aa671eSarutz 66a4aa671eSarutz /* 67a4aa671eSarutz * Local Function Prototypes 68a4aa671eSarutz */ 69a4aa671eSarutz 70a4aa671eSarutz static int dcdopen(dev_t *dev_p, int flag, int otyp, cred_t *cred_p); 71a4aa671eSarutz static int dcdclose(dev_t dev, int flag, int otyp, cred_t *cred_p); 72a4aa671eSarutz static int dcdstrategy(struct buf *bp); 73a4aa671eSarutz static int dcddump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk); 74a4aa671eSarutz static int dcdioctl(dev_t, int, intptr_t, int, cred_t *, int *); 75a4aa671eSarutz static int dcdread(dev_t dev, struct uio *uio, cred_t *cred_p); 76a4aa671eSarutz static int dcdwrite(dev_t dev, struct uio *uio, cred_t *cred_p); 77a4aa671eSarutz static int dcd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, 78a4aa671eSarutz char *, caddr_t, int *); 79a4aa671eSarutz static int dcdaread(dev_t dev, struct aio_req *aio, cred_t *cred_p); 80a4aa671eSarutz static int dcdawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p); 81a4aa671eSarutz 82a4aa671eSarutz 83a4aa671eSarutz static void dcd_free_softstate(struct dcd_disk *un, dev_info_t *devi); 84a4aa671eSarutz static int dcd_doattach(dev_info_t *devi, int (*f)()); 85a4aa671eSarutz static int dcd_validate_geometry(struct dcd_disk *un); 86a4aa671eSarutz static ddi_devid_t dcd_get_devid(struct dcd_disk *un); 87a4aa671eSarutz static ddi_devid_t dcd_create_devid(struct dcd_disk *un); 88a4aa671eSarutz static int dcd_make_devid_from_serial(struct dcd_disk *un); 89a4aa671eSarutz static void dcd_validate_model_serial(char *str, int *retlen, int totallen); 90a4aa671eSarutz static int dcd_read_deviceid(struct dcd_disk *un); 91a4aa671eSarutz static int dcd_write_deviceid(struct dcd_disk *un); 92a4aa671eSarutz static int dcd_poll(struct dcd_pkt *pkt); 93a4aa671eSarutz static char *dcd_rname(int reason); 94a4aa671eSarutz static void dcd_flush_cache(struct dcd_disk *un); 95a4aa671eSarutz 96a4aa671eSarutz static int dcd_compute_dk_capacity(struct dcd_device *devp, 97a4aa671eSarutz diskaddr_t *capacity); 98a4aa671eSarutz static int dcd_send_lb_rw_cmd(dev_info_t *devinfo, void *bufaddr, 99a4aa671eSarutz diskaddr_t start_block, size_t reqlength, uchar_t cmd); 100a4aa671eSarutz 101a4aa671eSarutz static void dcdmin(struct buf *bp); 102a4aa671eSarutz 103a4aa671eSarutz static int dcdioctl_cmd(dev_t, struct udcd_cmd *, 104a4aa671eSarutz enum uio_seg, enum uio_seg); 105a4aa671eSarutz 106a4aa671eSarutz static void dcdstart(struct dcd_disk *un); 107a4aa671eSarutz static void dcddone_and_mutex_exit(struct dcd_disk *un, struct buf *bp); 108a4aa671eSarutz static void make_dcd_cmd(struct dcd_disk *un, struct buf *bp, int (*f)()); 109a4aa671eSarutz static void dcdudcdmin(struct buf *bp); 110a4aa671eSarutz 111a4aa671eSarutz static int dcdrunout(caddr_t); 112a4aa671eSarutz static int dcd_check_wp(dev_t dev); 113a4aa671eSarutz static int dcd_unit_ready(dev_t dev); 114a4aa671eSarutz static void dcd_handle_tran_busy(struct buf *bp, struct diskhd *dp, 115a4aa671eSarutz struct dcd_disk *un); 116a4aa671eSarutz static void dcdintr(struct dcd_pkt *pkt); 117a4aa671eSarutz static int dcd_handle_incomplete(struct dcd_disk *un, struct buf *bp); 118a4aa671eSarutz static void dcd_offline(struct dcd_disk *un, int bechatty); 119a4aa671eSarutz static int dcd_ready_and_valid(dev_t dev, struct dcd_disk *un); 120a4aa671eSarutz static void dcd_reset_disk(struct dcd_disk *un, struct dcd_pkt *pkt); 121a4aa671eSarutz static void dcd_translate(struct dadkio_status32 *statp, struct udcd_cmd *cmdp); 122a4aa671eSarutz static int dcdflushdone(struct buf *bp); 123a4aa671eSarutz 124a4aa671eSarutz /* Function prototypes for cmlb */ 125a4aa671eSarutz 126a4aa671eSarutz static int dcd_lb_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr, 127a4aa671eSarutz diskaddr_t start_block, size_t reqlength, void *tg_cookie); 128a4aa671eSarutz 129a4aa671eSarutz static int dcd_lb_getphygeom(dev_info_t *devi, cmlb_geom_t *phygeomp); 130a4aa671eSarutz static int dcd_lb_getinfo(dev_info_t *devi, int cmd, void *arg, 131a4aa671eSarutz void *tg_cookie); 132a4aa671eSarutz 133a4aa671eSarutz 134a4aa671eSarutz static cmlb_tg_ops_t dcd_lb_ops = { 135a4aa671eSarutz TG_DK_OPS_VERSION_1, 136a4aa671eSarutz dcd_lb_rdwr, 137a4aa671eSarutz dcd_lb_getinfo 138a4aa671eSarutz }; 139a4aa671eSarutz 140a4aa671eSarutz /* 141a4aa671eSarutz * Error and Logging Functions 142a4aa671eSarutz */ 143a4aa671eSarutz #ifndef lint 144a4aa671eSarutz static void clean_print(dev_info_t *dev, char *label, uint_t level, 145a4aa671eSarutz char *title, char *data, int len); 146a4aa671eSarutz static void dcdrestart(void *arg); 147a4aa671eSarutz #endif /* lint */ 148a4aa671eSarutz 149a4aa671eSarutz static int dcd_check_error(struct dcd_disk *un, struct buf *bp); 150a4aa671eSarutz 151a4aa671eSarutz /* 152a4aa671eSarutz * Error statistics create/update functions 153a4aa671eSarutz */ 154a4aa671eSarutz static int dcd_create_errstats(struct dcd_disk *, int); 155a4aa671eSarutz 156a4aa671eSarutz 157a4aa671eSarutz 158a4aa671eSarutz /*PRINTFLIKE4*/ 159a4aa671eSarutz extern void dcd_log(dev_info_t *, char *, uint_t, const char *, ...) 160a4aa671eSarutz __KPRINTFLIKE(4); 161a4aa671eSarutz extern void makecommand(struct dcd_pkt *, int, uchar_t, uint32_t, 162a4aa671eSarutz uchar_t, uint32_t, uchar_t, uchar_t); 163a4aa671eSarutz 164a4aa671eSarutz 165a4aa671eSarutz /* 166a4aa671eSarutz * Configuration Routines 167a4aa671eSarutz */ 168a4aa671eSarutz static int dcdinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 169a4aa671eSarutz void **result); 170a4aa671eSarutz static int dcdprobe(dev_info_t *devi); 171a4aa671eSarutz static int dcdattach(dev_info_t *devi, ddi_attach_cmd_t cmd); 172a4aa671eSarutz static int dcddetach(dev_info_t *devi, ddi_detach_cmd_t cmd); 173a4aa671eSarutz static int dcdreset(dev_info_t *dip, ddi_reset_cmd_t cmd); 174a4aa671eSarutz static int dcd_dr_detach(dev_info_t *devi); 175a4aa671eSarutz static int dcdpower(dev_info_t *devi, int component, int level); 176a4aa671eSarutz 177a4aa671eSarutz static void *dcd_state; 178a4aa671eSarutz static int dcd_max_instance; 179a4aa671eSarutz static char *dcd_label = "dad"; 180a4aa671eSarutz 181a4aa671eSarutz static char *diskokay = "disk okay\n"; 182a4aa671eSarutz 183a4aa671eSarutz #if DEBUG || lint 184a4aa671eSarutz #define DCDDEBUG 185a4aa671eSarutz #endif 186a4aa671eSarutz 187a4aa671eSarutz int dcd_test_flag = 0; 188a4aa671eSarutz /* 189a4aa671eSarutz * Debugging macros 190a4aa671eSarutz */ 191a4aa671eSarutz #ifdef DCDDEBUG 192a4aa671eSarutz static int dcddebug = 0; 193a4aa671eSarutz #define DEBUGGING (dcddebug > 1) 194a4aa671eSarutz #define DAD_DEBUG if (dcddebug == 1) dcd_log 195a4aa671eSarutz #define DAD_DEBUG2 if (dcddebug > 1) dcd_log 196a4aa671eSarutz #else /* DCDDEBUG */ 197a4aa671eSarutz #define dcddebug (0) 198a4aa671eSarutz #define DEBUGGING (0) 199a4aa671eSarutz #define DAD_DEBUG if (0) dcd_log 200a4aa671eSarutz #define DAD_DEBUG2 if (0) dcd_log 201a4aa671eSarutz #endif 202a4aa671eSarutz 203a4aa671eSarutz /* 204a4aa671eSarutz * we use pkt_private area for storing bp and retry_count 205a4aa671eSarutz * XXX: Really is this usefull. 206a4aa671eSarutz */ 207a4aa671eSarutz struct dcd_pkt_private { 208a4aa671eSarutz struct buf *dcdpp_bp; 209a4aa671eSarutz short dcdpp_retry_count; 210a4aa671eSarutz short dcdpp_victim_retry_count; 211a4aa671eSarutz }; 212a4aa671eSarutz 213a4aa671eSarutz 214a4aa671eSarutz _NOTE(SCHEME_PROTECTS_DATA("Unique per pkt", dcd_pkt_private buf)) 215a4aa671eSarutz 216a4aa671eSarutz #define PP_LEN (sizeof (struct dcd_pkt_private)) 217a4aa671eSarutz 218a4aa671eSarutz #define PKT_SET_BP(pkt, bp) \ 219a4aa671eSarutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_bp = bp 220a4aa671eSarutz #define PKT_GET_BP(pkt) \ 221a4aa671eSarutz (((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_bp) 222a4aa671eSarutz 223a4aa671eSarutz 224a4aa671eSarutz #define PKT_SET_RETRY_CNT(pkt, n) \ 225a4aa671eSarutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_retry_count = n 226a4aa671eSarutz 227a4aa671eSarutz #define PKT_GET_RETRY_CNT(pkt) \ 228a4aa671eSarutz (((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_retry_count) 229a4aa671eSarutz 230a4aa671eSarutz #define PKT_INCR_RETRY_CNT(pkt, n) \ 231a4aa671eSarutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_retry_count += n 232a4aa671eSarutz 233a4aa671eSarutz #define PKT_SET_VICTIM_RETRY_CNT(pkt, n) \ 234a4aa671eSarutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_victim_retry_count \ 235a4aa671eSarutz = n 236a4aa671eSarutz 237a4aa671eSarutz #define PKT_GET_VICTIM_RETRY_CNT(pkt) \ 238a4aa671eSarutz (((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_victim_retry_count) 239a4aa671eSarutz #define PKT_INCR_VICTIM_RETRY_CNT(pkt, n) \ 240a4aa671eSarutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_victim_retry_count \ 241a4aa671eSarutz += n 242a4aa671eSarutz 243a4aa671eSarutz #define DISK_NOT_READY_RETRY_COUNT (dcd_retry_count / 2) 244a4aa671eSarutz 245a4aa671eSarutz 246a4aa671eSarutz /* 247a4aa671eSarutz * Urk! 248a4aa671eSarutz */ 249a4aa671eSarutz #define SET_BP_ERROR(bp, err) \ 250a4aa671eSarutz bioerror(bp, err); 251a4aa671eSarutz 252a4aa671eSarutz #define IOSP KSTAT_IO_PTR(un->un_stats) 253a4aa671eSarutz #define IO_PARTITION_STATS un->un_pstats[DCDPART(bp->b_edev)] 254a4aa671eSarutz #define IOSP_PARTITION KSTAT_IO_PTR(IO_PARTITION_STATS) 255a4aa671eSarutz 256a4aa671eSarutz #define DCD_DO_KSTATS(un, kstat_function, bp) \ 257a4aa671eSarutz ASSERT(mutex_owned(DCD_MUTEX)); \ 258a4aa671eSarutz if (bp != un->un_sbufp) { \ 259a4aa671eSarutz if (un->un_stats) { \ 260a4aa671eSarutz kstat_function(IOSP); \ 261a4aa671eSarutz } \ 262a4aa671eSarutz if (IO_PARTITION_STATS) { \ 263a4aa671eSarutz kstat_function(IOSP_PARTITION); \ 264a4aa671eSarutz } \ 265a4aa671eSarutz } 266a4aa671eSarutz 267a4aa671eSarutz #define DCD_DO_ERRSTATS(un, x) \ 268a4aa671eSarutz if (un->un_errstats) { \ 269a4aa671eSarutz struct dcd_errstats *dtp; \ 270a4aa671eSarutz dtp = (struct dcd_errstats *)un->un_errstats->ks_data; \ 271a4aa671eSarutz dtp->x.value.ui32++; \ 272a4aa671eSarutz } 273a4aa671eSarutz 274a4aa671eSarutz #define GET_SOFT_STATE(dev) \ 275a4aa671eSarutz struct dcd_disk *un; \ 276a4aa671eSarutz int instance, part; \ 277a4aa671eSarutz minor_t minor = getminor(dev); \ 278a4aa671eSarutz \ 279a4aa671eSarutz part = minor & DCDPART_MASK; \ 280a4aa671eSarutz instance = minor >> DCDUNIT_SHIFT; \ 281a4aa671eSarutz if ((un = ddi_get_soft_state(dcd_state, instance)) == NULL) \ 282a4aa671eSarutz return (ENXIO); 283a4aa671eSarutz 284a4aa671eSarutz #define LOGICAL_BLOCK_ALIGN(blkno, blknoshift) \ 285a4aa671eSarutz (((blkno) & ((1 << (blknoshift)) - 1)) == 0) 286a4aa671eSarutz 287a4aa671eSarutz /* 288a4aa671eSarutz * After the following number of sectors, the cylinder number spills over 289a4aa671eSarutz * 0xFFFF if sectors = 63 and heads = 16. 290a4aa671eSarutz */ 291a4aa671eSarutz #define NUM_SECTORS_32G 0x3EFFC10 292a4aa671eSarutz 293a4aa671eSarutz /* 294a4aa671eSarutz * Configuration Data 295a4aa671eSarutz */ 296a4aa671eSarutz 297a4aa671eSarutz /* 298a4aa671eSarutz * Device driver ops vector 299a4aa671eSarutz */ 300a4aa671eSarutz 301a4aa671eSarutz static struct cb_ops dcd_cb_ops = { 302a4aa671eSarutz dcdopen, /* open */ 303a4aa671eSarutz dcdclose, /* close */ 304a4aa671eSarutz dcdstrategy, /* strategy */ 305a4aa671eSarutz nodev, /* print */ 306a4aa671eSarutz dcddump, /* dump */ 307a4aa671eSarutz dcdread, /* read */ 308a4aa671eSarutz dcdwrite, /* write */ 309a4aa671eSarutz dcdioctl, /* ioctl */ 310a4aa671eSarutz nodev, /* devmap */ 311a4aa671eSarutz nodev, /* mmap */ 312a4aa671eSarutz nodev, /* segmap */ 313a4aa671eSarutz nochpoll, /* poll */ 314a4aa671eSarutz dcd_prop_op, /* cb_prop_op */ 315a4aa671eSarutz 0, /* streamtab */ 316a4aa671eSarutz D_64BIT | D_MP | D_NEW, /* Driver compatibility flag */ 317a4aa671eSarutz CB_REV, /* cb_rev */ 318a4aa671eSarutz dcdaread, /* async I/O read entry point */ 319a4aa671eSarutz dcdawrite /* async I/O write entry point */ 320a4aa671eSarutz }; 321a4aa671eSarutz 322a4aa671eSarutz static struct dev_ops dcd_ops = { 323a4aa671eSarutz DEVO_REV, /* devo_rev, */ 324a4aa671eSarutz 0, /* refcnt */ 325a4aa671eSarutz dcdinfo, /* info */ 326a4aa671eSarutz nulldev, /* identify */ 327a4aa671eSarutz dcdprobe, /* probe */ 328a4aa671eSarutz dcdattach, /* attach */ 329a4aa671eSarutz dcddetach, /* detach */ 330a4aa671eSarutz dcdreset, /* reset */ 331a4aa671eSarutz &dcd_cb_ops, /* driver operations */ 332a4aa671eSarutz (struct bus_ops *)0, /* bus operations */ 33319397407SSherry Moore dcdpower, /* power */ 33419397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 335a4aa671eSarutz }; 336a4aa671eSarutz 337a4aa671eSarutz 338a4aa671eSarutz /* 339a4aa671eSarutz * This is the loadable module wrapper. 340a4aa671eSarutz */ 341a4aa671eSarutz #include <sys/modctl.h> 342a4aa671eSarutz 343a4aa671eSarutz static struct modldrv modldrv = { 344a4aa671eSarutz &mod_driverops, /* Type of module. This one is a driver */ 34519397407SSherry Moore "DAD Disk Driver", /* Name of the module. */ 346a4aa671eSarutz &dcd_ops, /* driver ops */ 347a4aa671eSarutz }; 348a4aa671eSarutz 349a4aa671eSarutz 350a4aa671eSarutz 351a4aa671eSarutz static struct modlinkage modlinkage = { 352a4aa671eSarutz MODREV_1, &modldrv, NULL 353a4aa671eSarutz }; 354a4aa671eSarutz 355a4aa671eSarutz /* 356a4aa671eSarutz * the dcd_attach_mutex only protects dcd_max_instance in multi-threaded 357a4aa671eSarutz * attach situations 358a4aa671eSarutz */ 359a4aa671eSarutz static kmutex_t dcd_attach_mutex; 360a4aa671eSarutz 361a4aa671eSarutz int 362a4aa671eSarutz _init(void) 363a4aa671eSarutz { 364a4aa671eSarutz int e; 365a4aa671eSarutz 366a4aa671eSarutz if ((e = ddi_soft_state_init(&dcd_state, sizeof (struct dcd_disk), 367a4aa671eSarutz DCD_MAXUNIT)) != 0) 368a4aa671eSarutz return (e); 369a4aa671eSarutz 370a4aa671eSarutz mutex_init(&dcd_attach_mutex, NULL, MUTEX_DRIVER, NULL); 371a4aa671eSarutz e = mod_install(&modlinkage); 372a4aa671eSarutz if (e != 0) { 373a4aa671eSarutz mutex_destroy(&dcd_attach_mutex); 374a4aa671eSarutz ddi_soft_state_fini(&dcd_state); 375a4aa671eSarutz return (e); 376a4aa671eSarutz } 377a4aa671eSarutz 378a4aa671eSarutz return (e); 379a4aa671eSarutz } 380a4aa671eSarutz 381a4aa671eSarutz int 382a4aa671eSarutz _fini(void) 383a4aa671eSarutz { 384a4aa671eSarutz int e; 385a4aa671eSarutz 386a4aa671eSarutz if ((e = mod_remove(&modlinkage)) != 0) 387a4aa671eSarutz return (e); 388a4aa671eSarutz 389a4aa671eSarutz ddi_soft_state_fini(&dcd_state); 390a4aa671eSarutz mutex_destroy(&dcd_attach_mutex); 391a4aa671eSarutz 392a4aa671eSarutz return (e); 393a4aa671eSarutz } 394a4aa671eSarutz 395a4aa671eSarutz int 396a4aa671eSarutz _info(struct modinfo *modinfop) 397a4aa671eSarutz { 398a4aa671eSarutz 399a4aa671eSarutz return (mod_info(&modlinkage, modinfop)); 400a4aa671eSarutz } 401a4aa671eSarutz 402a4aa671eSarutz static int 403a4aa671eSarutz dcdprobe(dev_info_t *devi) 404a4aa671eSarutz { 405a4aa671eSarutz struct dcd_device *devp; 406a4aa671eSarutz int rval = DDI_PROBE_PARTIAL; 407a4aa671eSarutz int instance; 408a4aa671eSarutz 409a4aa671eSarutz devp = ddi_get_driver_private(devi); 410a4aa671eSarutz instance = ddi_get_instance(devi); 411a4aa671eSarutz 412a4aa671eSarutz /* 413a4aa671eSarutz * Keep a count of how many disks (ie. highest instance no) we have 414a4aa671eSarutz * XXX currently not used but maybe useful later again 415a4aa671eSarutz */ 416a4aa671eSarutz mutex_enter(&dcd_attach_mutex); 417a4aa671eSarutz if (instance > dcd_max_instance) 418a4aa671eSarutz dcd_max_instance = instance; 419a4aa671eSarutz mutex_exit(&dcd_attach_mutex); 420a4aa671eSarutz 421b9ccdc5aScth DAD_DEBUG2(devp->dcd_dev, dcd_label, DCD_DEBUG, "dcdprobe:\n"); 422a4aa671eSarutz 423a4aa671eSarutz if (ddi_get_soft_state(dcd_state, instance) != NULL) 424a4aa671eSarutz return (DDI_PROBE_PARTIAL); 425a4aa671eSarutz 426a4aa671eSarutz /* 427a4aa671eSarutz * Turn around and call utility probe routine 428a4aa671eSarutz * to see whether we actually have a disk at 429a4aa671eSarutz */ 430a4aa671eSarutz 431a4aa671eSarutz DAD_DEBUG2(devp->dcd_dev, dcd_label, DCD_DEBUG, 432a4aa671eSarutz "dcdprobe: %x\n", dcd_probe(devp, NULL_FUNC)); 433a4aa671eSarutz 434a4aa671eSarutz switch (dcd_probe(devp, NULL_FUNC)) { 435a4aa671eSarutz default: 436a4aa671eSarutz case DCDPROBE_NORESP: 437a4aa671eSarutz case DCDPROBE_NONCCS: 438a4aa671eSarutz case DCDPROBE_NOMEM: 439a4aa671eSarutz case DCDPROBE_FAILURE: 440a4aa671eSarutz case DCDPROBE_BUSY: 441a4aa671eSarutz break; 442a4aa671eSarutz 443a4aa671eSarutz case DCDPROBE_EXISTS: 444a4aa671eSarutz /* 445a4aa671eSarutz * Check whether it is a ATA device and then 446a4aa671eSarutz * return SUCCESS. 447a4aa671eSarutz */ 448a4aa671eSarutz DAD_DEBUG2(devp->dcd_dev, dcd_label, DCD_DEBUG, 449a4aa671eSarutz "config %x\n", devp->dcd_ident->dcd_config); 450a4aa671eSarutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) { 451a4aa671eSarutz if (devp->dcd_ident->dcd_config & ATANON_REMOVABLE) { 452a4aa671eSarutz rval = DDI_PROBE_SUCCESS; 453a4aa671eSarutz } else 454a4aa671eSarutz rval = DDI_PROBE_FAILURE; 455a4aa671eSarutz } else { 456a4aa671eSarutz rval = DDI_PROBE_FAILURE; 457a4aa671eSarutz } 458a4aa671eSarutz break; 459a4aa671eSarutz } 460a4aa671eSarutz dcd_unprobe(devp); 461a4aa671eSarutz 462a4aa671eSarutz DAD_DEBUG2(devp->dcd_dev, dcd_label, DCD_DEBUG, 463a4aa671eSarutz "dcdprobe returns %x\n", rval); 464a4aa671eSarutz 465a4aa671eSarutz return (rval); 466a4aa671eSarutz } 467a4aa671eSarutz 468a4aa671eSarutz 469a4aa671eSarutz /*ARGSUSED*/ 470a4aa671eSarutz static int 471a4aa671eSarutz dcdattach(dev_info_t *devi, ddi_attach_cmd_t cmd) 472a4aa671eSarutz { 473a4aa671eSarutz int instance, rval; 474a4aa671eSarutz struct dcd_device *devp; 475a4aa671eSarutz struct dcd_disk *un; 476a4aa671eSarutz struct diskhd *dp; 477a4aa671eSarutz char *pm_comp[] = 478a4aa671eSarutz { "NAME=ide-disk", "0=standby", "1=idle", "2=active" }; 479a4aa671eSarutz 480a4aa671eSarutz /* CONSTCOND */ 481a4aa671eSarutz ASSERT(NO_COMPETING_THREADS); 482a4aa671eSarutz 483a4aa671eSarutz 484a4aa671eSarutz devp = ddi_get_driver_private(devi); 485a4aa671eSarutz instance = ddi_get_instance(devi); 486a4aa671eSarutz DAD_DEBUG2(devp->dcd_dev, dcd_label, DCD_DEBUG, "Attach Started\n"); 487a4aa671eSarutz 488a4aa671eSarutz switch (cmd) { 489a4aa671eSarutz case DDI_ATTACH: 490a4aa671eSarutz break; 491a4aa671eSarutz 492a4aa671eSarutz case DDI_RESUME: 493a4aa671eSarutz if (!(un = ddi_get_soft_state(dcd_state, instance))) 494a4aa671eSarutz return (DDI_FAILURE); 495a4aa671eSarutz mutex_enter(DCD_MUTEX); 496a4aa671eSarutz Restore_state(un); 497a4aa671eSarutz /* 498a4aa671eSarutz * Restore the state which was saved to give the 499a4aa671eSarutz * the right state in un_last_state 500a4aa671eSarutz */ 501a4aa671eSarutz un->un_last_state = un->un_save_state; 502a4aa671eSarutz un->un_throttle = 2; 503a4aa671eSarutz cv_broadcast(&un->un_suspend_cv); 504a4aa671eSarutz /* 505a4aa671eSarutz * Raise the power level of the device to active. 506a4aa671eSarutz */ 507a4aa671eSarutz mutex_exit(DCD_MUTEX); 508a4aa671eSarutz (void) pm_raise_power(DCD_DEVINFO, 0, DCD_DEVICE_ACTIVE); 509a4aa671eSarutz mutex_enter(DCD_MUTEX); 510a4aa671eSarutz 511a4aa671eSarutz /* 512a4aa671eSarutz * start unit - if this is a low-activity device 513a4aa671eSarutz * commands in queue will have to wait until new 514a4aa671eSarutz * commands come in, which may take awhile. 515a4aa671eSarutz * Also, we specifically don't check un_ncmds 516a4aa671eSarutz * because we know that there really are no 517a4aa671eSarutz * commands in progress after the unit was suspended 518a4aa671eSarutz * and we could have reached the throttle level, been 519a4aa671eSarutz * suspended, and have no new commands coming in for 520a4aa671eSarutz * awhile. Highly unlikely, but so is the low- 521a4aa671eSarutz * activity disk scenario. 522a4aa671eSarutz */ 523a4aa671eSarutz dp = &un->un_utab; 524a4aa671eSarutz if (dp->b_actf && (dp->b_forw == NULL)) { 525a4aa671eSarutz dcdstart(un); 526a4aa671eSarutz } 527a4aa671eSarutz 528a4aa671eSarutz mutex_exit(DCD_MUTEX); 529a4aa671eSarutz return (DDI_SUCCESS); 530a4aa671eSarutz 531a4aa671eSarutz default: 532a4aa671eSarutz return (DDI_FAILURE); 533a4aa671eSarutz } 534a4aa671eSarutz 535a4aa671eSarutz if (dcd_doattach(devi, SLEEP_FUNC) == DDI_FAILURE) { 536a4aa671eSarutz return (DDI_FAILURE); 537a4aa671eSarutz } 538a4aa671eSarutz 539a4aa671eSarutz if (!(un = (struct dcd_disk *) 540a4aa671eSarutz ddi_get_soft_state(dcd_state, instance))) { 541a4aa671eSarutz return (DDI_FAILURE); 542a4aa671eSarutz } 543a4aa671eSarutz devp->dcd_private = (ataopaque_t)un; 544a4aa671eSarutz 545a4aa671eSarutz /* 546a4aa671eSarutz * Add a zero-length attribute to tell the world we support 547a4aa671eSarutz * kernel ioctls (for layered drivers) 548a4aa671eSarutz */ 549a4aa671eSarutz (void) ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP, 550a4aa671eSarutz DDI_KERNEL_IOCTL, NULL, 0); 551a4aa671eSarutz 552a4aa671eSarutz /* 553a4aa671eSarutz * Since the dad device does not have the 'reg' property, 554a4aa671eSarutz * cpr will not call its DDI_SUSPEND/DDI_RESUME entries. 555a4aa671eSarutz * The following code is to tell cpr that this device 556a4aa671eSarutz * does need to be suspended and resumed. 557a4aa671eSarutz */ 558a4aa671eSarutz (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, 559a4aa671eSarutz "pm-hardware-state", (caddr_t)"needs-suspend-resume"); 560a4aa671eSarutz 561a4aa671eSarutz /* 562a4aa671eSarutz * Initialize power management bookkeeping; 563a4aa671eSarutz * Create components - In IDE case there are 3 levels and one 564a4aa671eSarutz * component. The levels being - active, idle, standby. 565a4aa671eSarutz */ 566a4aa671eSarutz 567a4aa671eSarutz rval = ddi_prop_update_string_array(DDI_DEV_T_NONE, 568a4aa671eSarutz devi, "pm-components", pm_comp, 4); 569a4aa671eSarutz if (rval == DDI_PROP_SUCCESS) { 570a4aa671eSarutz /* 571a4aa671eSarutz * Ignore the return value of pm_raise_power 572a4aa671eSarutz * Even if we check the return values and 573a4aa671eSarutz * remove the property created above, PM 574a4aa671eSarutz * framework will not honour the change after 575a4aa671eSarutz * first call to pm_raise_power. Hence, the 576a4aa671eSarutz * removal of that property does not help if 577a4aa671eSarutz * pm_raise_power fails. 578a4aa671eSarutz */ 579a4aa671eSarutz (void) pm_raise_power(DCD_DEVINFO, 0, DCD_DEVICE_ACTIVE); 580a4aa671eSarutz } 581a4aa671eSarutz 582a4aa671eSarutz ddi_report_dev(devi); 583a4aa671eSarutz 584a4aa671eSarutz cmlb_alloc_handle(&un->un_dklbhandle); 585a4aa671eSarutz 586a4aa671eSarutz if (cmlb_attach(devi, 587a4aa671eSarutz &dcd_lb_ops, 588a4aa671eSarutz 0, 5897f0b8309SEdward Pilatowicz B_FALSE, 5907f0b8309SEdward Pilatowicz B_FALSE, 591a4aa671eSarutz DDI_NT_BLOCK_CHAN, 592a4aa671eSarutz CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8, 593a4aa671eSarutz un->un_dklbhandle, 594a4aa671eSarutz 0) != 0) { 595a4aa671eSarutz cmlb_free_handle(&un->un_dklbhandle); 596a4aa671eSarutz dcd_free_softstate(un, devi); 597a4aa671eSarutz return (DDI_FAILURE); 598a4aa671eSarutz } 599a4aa671eSarutz 600a4aa671eSarutz mutex_enter(DCD_MUTEX); 601a4aa671eSarutz (void) dcd_validate_geometry(un); 602a4aa671eSarutz 603a4aa671eSarutz /* Get devid; create a devid ONLY IF could not get ID */ 604a4aa671eSarutz if (dcd_get_devid(un) == NULL) { 605a4aa671eSarutz /* Create the fab'd devid */ 606a4aa671eSarutz (void) dcd_create_devid(un); 607a4aa671eSarutz } 608a4aa671eSarutz mutex_exit(DCD_MUTEX); 609a4aa671eSarutz 610a4aa671eSarutz return (DDI_SUCCESS); 611a4aa671eSarutz } 612a4aa671eSarutz 613a4aa671eSarutz static void 614a4aa671eSarutz dcd_free_softstate(struct dcd_disk *un, dev_info_t *devi) 615a4aa671eSarutz { 616a4aa671eSarutz struct dcd_device *devp; 617a4aa671eSarutz int instance = ddi_get_instance(devi); 618a4aa671eSarutz 619a4aa671eSarutz devp = ddi_get_driver_private(devi); 620a4aa671eSarutz 621a4aa671eSarutz if (un) { 622a4aa671eSarutz sema_destroy(&un->un_semoclose); 623a4aa671eSarutz cv_destroy(&un->un_sbuf_cv); 624a4aa671eSarutz cv_destroy(&un->un_state_cv); 625a4aa671eSarutz cv_destroy(&un->un_disk_busy_cv); 626a4aa671eSarutz cv_destroy(&un->un_suspend_cv); 627a4aa671eSarutz 628a4aa671eSarutz /* 629a4aa671eSarutz * Deallocate command packet resources. 630a4aa671eSarutz */ 631a4aa671eSarutz if (un->un_sbufp) 632a4aa671eSarutz freerbuf(un->un_sbufp); 633a4aa671eSarutz if (un->un_dp) { 634a4aa671eSarutz kmem_free((caddr_t)un->un_dp, sizeof (*un->un_dp)); 635a4aa671eSarutz } 636a4aa671eSarutz /* 637a4aa671eSarutz * Unregister the devid and free devid resources allocated 638a4aa671eSarutz */ 639a4aa671eSarutz ddi_devid_unregister(DCD_DEVINFO); 640a4aa671eSarutz if (un->un_devid) { 641a4aa671eSarutz ddi_devid_free(un->un_devid); 642a4aa671eSarutz un->un_devid = NULL; 643a4aa671eSarutz } 644a4aa671eSarutz 645a4aa671eSarutz /* 646a4aa671eSarutz * Delete kstats. Kstats for non CD devices are deleted 647a4aa671eSarutz * in dcdclose. 648a4aa671eSarutz */ 649a4aa671eSarutz if (un->un_stats) { 650a4aa671eSarutz kstat_delete(un->un_stats); 651a4aa671eSarutz } 652a4aa671eSarutz 653a4aa671eSarutz } 654a4aa671eSarutz 655a4aa671eSarutz /* 656a4aa671eSarutz * Cleanup scsi_device resources. 657a4aa671eSarutz */ 658a4aa671eSarutz ddi_soft_state_free(dcd_state, instance); 659a4aa671eSarutz devp->dcd_private = (ataopaque_t)0; 660a4aa671eSarutz /* unprobe scsi device */ 661a4aa671eSarutz dcd_unprobe(devp); 662a4aa671eSarutz 663a4aa671eSarutz /* Remove properties created during attach */ 664a4aa671eSarutz ddi_prop_remove_all(devi); 665a4aa671eSarutz } 666a4aa671eSarutz 667a4aa671eSarutz static int 668a4aa671eSarutz dcddetach(dev_info_t *devi, ddi_detach_cmd_t cmd) 669a4aa671eSarutz { 670a4aa671eSarutz int instance; 671a4aa671eSarutz struct dcd_disk *un; 672a4aa671eSarutz clock_t wait_cmds_complete; 673a4aa671eSarutz instance = ddi_get_instance(devi); 674a4aa671eSarutz 675a4aa671eSarutz if (!(un = ddi_get_soft_state(dcd_state, instance))) 676a4aa671eSarutz return (DDI_FAILURE); 677a4aa671eSarutz 678a4aa671eSarutz switch (cmd) { 679a4aa671eSarutz case DDI_DETACH: 680a4aa671eSarutz return (dcd_dr_detach(devi)); 681a4aa671eSarutz 682a4aa671eSarutz case DDI_SUSPEND: 683a4aa671eSarutz mutex_enter(DCD_MUTEX); 684a4aa671eSarutz if (un->un_state == DCD_STATE_SUSPENDED) { 685a4aa671eSarutz mutex_exit(DCD_MUTEX); 686a4aa671eSarutz return (DDI_SUCCESS); 687a4aa671eSarutz } 688a4aa671eSarutz un->un_throttle = 0; 689a4aa671eSarutz /* 690a4aa671eSarutz * Save the last state first 691a4aa671eSarutz */ 692a4aa671eSarutz un->un_save_state = un->un_last_state; 693a4aa671eSarutz 694a4aa671eSarutz New_state(un, DCD_STATE_SUSPENDED); 695a4aa671eSarutz 696a4aa671eSarutz /* 697a4aa671eSarutz * wait till current operation completed. If we are 698a4aa671eSarutz * in the resource wait state (with an intr outstanding) 699a4aa671eSarutz * then we need to wait till the intr completes and 700a4aa671eSarutz * starts the next cmd. We wait for 701a4aa671eSarutz * DCD_WAIT_CMDS_COMPLETE seconds before failing the 702a4aa671eSarutz * DDI_SUSPEND. 703a4aa671eSarutz */ 704a4aa671eSarutz wait_cmds_complete = ddi_get_lbolt(); 705a4aa671eSarutz wait_cmds_complete += 706a4aa671eSarutz DCD_WAIT_CMDS_COMPLETE * drv_usectohz(1000000); 707a4aa671eSarutz 708a4aa671eSarutz while (un->un_ncmds) { 709a4aa671eSarutz if (cv_timedwait(&un->un_disk_busy_cv, 710a4aa671eSarutz DCD_MUTEX, wait_cmds_complete) == -1) { 711a4aa671eSarutz /* 712a4aa671eSarutz * commands Didn't finish in the 713a4aa671eSarutz * specified time, fail the DDI_SUSPEND. 714a4aa671eSarutz */ 715a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, 716a4aa671eSarutz DCD_DEBUG, "dcddetach: SUSPEND " 717a4aa671eSarutz "failed due to outstanding cmds\n"); 718a4aa671eSarutz Restore_state(un); 719a4aa671eSarutz mutex_exit(DCD_MUTEX); 720a4aa671eSarutz return (DDI_FAILURE); 721a4aa671eSarutz } 722a4aa671eSarutz } 723a4aa671eSarutz mutex_exit(DCD_MUTEX); 724a4aa671eSarutz return (DDI_SUCCESS); 725a4aa671eSarutz } 726a4aa671eSarutz return (DDI_FAILURE); 727a4aa671eSarutz } 728a4aa671eSarutz 729a4aa671eSarutz /* 730a4aa671eSarutz * The reset entry point gets invoked at the system shutdown time or through 731a4aa671eSarutz * CPR code at system suspend. 732a4aa671eSarutz * Will be flushing the cache and expect this to be last I/O operation to the 733a4aa671eSarutz * disk before system reset/power off. 734a4aa671eSarutz */ 735a4aa671eSarutz /*ARGSUSED*/ 736a4aa671eSarutz static int 737a4aa671eSarutz dcdreset(dev_info_t *dip, ddi_reset_cmd_t cmd) 738a4aa671eSarutz { 739a4aa671eSarutz struct dcd_disk *un; 740a4aa671eSarutz int instance; 741a4aa671eSarutz 742a4aa671eSarutz instance = ddi_get_instance(dip); 743a4aa671eSarutz 744a4aa671eSarutz if (!(un = ddi_get_soft_state(dcd_state, instance))) 745a4aa671eSarutz return (DDI_FAILURE); 746a4aa671eSarutz 747a4aa671eSarutz dcd_flush_cache(un); 748a4aa671eSarutz 749a4aa671eSarutz return (DDI_SUCCESS); 750a4aa671eSarutz } 751a4aa671eSarutz 752a4aa671eSarutz 753a4aa671eSarutz static int 754a4aa671eSarutz dcd_dr_detach(dev_info_t *devi) 755a4aa671eSarutz { 756a4aa671eSarutz struct dcd_device *devp; 757a4aa671eSarutz struct dcd_disk *un; 758a4aa671eSarutz 759a4aa671eSarutz /* 760a4aa671eSarutz * Get scsi_device structure for this instance. 761a4aa671eSarutz */ 762a4aa671eSarutz if ((devp = ddi_get_driver_private(devi)) == NULL) 763a4aa671eSarutz return (DDI_FAILURE); 764a4aa671eSarutz 765a4aa671eSarutz /* 766a4aa671eSarutz * Get dcd_disk structure containing target 'private' information 767a4aa671eSarutz */ 768a4aa671eSarutz un = (struct dcd_disk *)devp->dcd_private; 769a4aa671eSarutz 770a4aa671eSarutz /* 771a4aa671eSarutz * Verify there are NO outstanding commands issued to this device. 772a4aa671eSarutz * ie, un_ncmds == 0. 773a4aa671eSarutz * It's possible to have outstanding commands through the physio 774a4aa671eSarutz * code path, even though everything's closed. 775a4aa671eSarutz */ 776a4aa671eSarutz #ifndef lint 777a4aa671eSarutz _NOTE(COMPETING_THREADS_NOW); 778a4aa671eSarutz #endif 779a4aa671eSarutz mutex_enter(DCD_MUTEX); 780a4aa671eSarutz if (un->un_ncmds) { 781a4aa671eSarutz mutex_exit(DCD_MUTEX); 782a4aa671eSarutz _NOTE(NO_COMPETING_THREADS_NOW); 783a4aa671eSarutz return (DDI_FAILURE); 784a4aa671eSarutz } 785a4aa671eSarutz 786a4aa671eSarutz mutex_exit(DCD_MUTEX); 787a4aa671eSarutz 788a4aa671eSarutz cmlb_detach(un->un_dklbhandle, 0); 789a4aa671eSarutz cmlb_free_handle(&un->un_dklbhandle); 790a4aa671eSarutz 791a4aa671eSarutz 792a4aa671eSarutz /* 793a4aa671eSarutz * Lower the power state of the device 794a4aa671eSarutz * i.e. the minimum power consumption state - sleep. 795a4aa671eSarutz */ 796a4aa671eSarutz (void) pm_lower_power(DCD_DEVINFO, 0, DCD_DEVICE_STANDBY); 797a4aa671eSarutz 798a4aa671eSarutz _NOTE(NO_COMPETING_THREADS_NOW); 799a4aa671eSarutz 800a4aa671eSarutz /* 801a4aa671eSarutz * at this point there are no competing threads anymore 802a4aa671eSarutz * release active MT locks and all device resources. 803a4aa671eSarutz */ 804a4aa671eSarutz dcd_free_softstate(un, devi); 805a4aa671eSarutz 806a4aa671eSarutz return (DDI_SUCCESS); 807a4aa671eSarutz } 808a4aa671eSarutz 809a4aa671eSarutz static int 810a4aa671eSarutz dcdpower(dev_info_t *devi, int component, int level) 811a4aa671eSarutz { 812a4aa671eSarutz struct dcd_pkt *pkt; 813a4aa671eSarutz struct dcd_disk *un; 814a4aa671eSarutz int instance; 815a4aa671eSarutz uchar_t cmd; 816a4aa671eSarutz 817a4aa671eSarutz 818a4aa671eSarutz instance = ddi_get_instance(devi); 819a4aa671eSarutz 820a4aa671eSarutz if (!(un = ddi_get_soft_state(dcd_state, instance)) || 821a4aa671eSarutz (DCD_DEVICE_STANDBY > level) || (level > DCD_DEVICE_ACTIVE) || 822a4aa671eSarutz component != 0) { 823a4aa671eSarutz return (DDI_FAILURE); 824a4aa671eSarutz } 825a4aa671eSarutz 826a4aa671eSarutz mutex_enter(DCD_MUTEX); 827a4aa671eSarutz /* 828a4aa671eSarutz * if there are active commands for the device or device will be 829a4aa671eSarutz * active soon. At the same time there is request to lower power 830a4aa671eSarutz * return failure. 831a4aa671eSarutz */ 832a4aa671eSarutz if ((un->un_ncmds) && (level != DCD_DEVICE_ACTIVE)) { 833a4aa671eSarutz mutex_exit(DCD_MUTEX); 834a4aa671eSarutz return (DDI_FAILURE); 835a4aa671eSarutz } 836a4aa671eSarutz 837a4aa671eSarutz if ((un->un_state == DCD_STATE_OFFLINE) || 838a4aa671eSarutz (un->un_state == DCD_STATE_FATAL)) { 839a4aa671eSarutz mutex_exit(DCD_MUTEX); 840a4aa671eSarutz return (DDI_FAILURE); 841a4aa671eSarutz } 842a4aa671eSarutz 843a4aa671eSarutz if (level == DCD_DEVICE_ACTIVE) { 844a4aa671eSarutz /* 845a4aa671eSarutz * No need to fire any command, just set the state structure 846a4aa671eSarutz * to indicate previous state and set the level to active 847a4aa671eSarutz */ 848a4aa671eSarutz un->un_power_level = DCD_DEVICE_ACTIVE; 849a4aa671eSarutz if (un->un_state == DCD_STATE_PM_SUSPENDED) 850a4aa671eSarutz Restore_state(un); 851a4aa671eSarutz mutex_exit(DCD_MUTEX); 852a4aa671eSarutz } else { 853a4aa671eSarutz pkt = dcd_init_pkt(ROUTE, (struct dcd_pkt *)NULL, 854a4aa671eSarutz NULL, (uint32_t)sizeof (struct dcd_cmd), 2, PP_LEN, 855a4aa671eSarutz PKT_CONSISTENT, NULL_FUNC, NULL); 856a4aa671eSarutz 857a4aa671eSarutz if (pkt == (struct dcd_pkt *)NULL) { 858a4aa671eSarutz mutex_exit(DCD_MUTEX); 859a4aa671eSarutz return (DDI_FAILURE); 860a4aa671eSarutz } 861a4aa671eSarutz 862a4aa671eSarutz switch (level) { 863a4aa671eSarutz case DCD_DEVICE_IDLE: 864a4aa671eSarutz cmd = ATA_IDLE_IMMEDIATE; 865a4aa671eSarutz break; 866a4aa671eSarutz 867a4aa671eSarutz case DCD_DEVICE_STANDBY: 868a4aa671eSarutz cmd = ATA_STANDBY_IMMEDIATE; 869a4aa671eSarutz break; 870a4aa671eSarutz } 871a4aa671eSarutz 872a4aa671eSarutz makecommand(pkt, 0, cmd, 0, 0, 0, NO_DATA_XFER, 0); 873a4aa671eSarutz mutex_exit(DCD_MUTEX); 874a4aa671eSarutz /* 875a4aa671eSarutz * Issue the appropriate command 876a4aa671eSarutz */ 877a4aa671eSarutz if ((dcd_poll(pkt)) || (SCBP_C(pkt) != STATUS_GOOD)) { 878a4aa671eSarutz dcd_destroy_pkt(pkt); 879a4aa671eSarutz return (DDI_FAILURE); 880a4aa671eSarutz } 881a4aa671eSarutz dcd_destroy_pkt(pkt); 882a4aa671eSarutz mutex_enter(DCD_MUTEX); 883a4aa671eSarutz if (un->un_state != DCD_STATE_PM_SUSPENDED) 884a4aa671eSarutz New_state(un, DCD_STATE_PM_SUSPENDED); 885a4aa671eSarutz un->un_power_level = level; 886a4aa671eSarutz mutex_exit(DCD_MUTEX); 887a4aa671eSarutz } 888a4aa671eSarutz 889a4aa671eSarutz return (DDI_SUCCESS); 890a4aa671eSarutz } 891a4aa671eSarutz 892a4aa671eSarutz static int 893a4aa671eSarutz dcd_doattach(dev_info_t *devi, int (*canwait)()) 894a4aa671eSarutz { 895a4aa671eSarutz struct dcd_device *devp; 896a4aa671eSarutz struct dcd_disk *un = (struct dcd_disk *)0; 897a4aa671eSarutz int instance; 898a4aa671eSarutz int km_flags = (canwait != NULL_FUNC)? KM_SLEEP : KM_NOSLEEP; 899a4aa671eSarutz int rval; 900a4aa671eSarutz char *prop_template = "target%x-dcd-options"; 901a4aa671eSarutz int options; 902a4aa671eSarutz char prop_str[32]; 903a4aa671eSarutz int target; 904a4aa671eSarutz diskaddr_t capacity; 905a4aa671eSarutz 906a4aa671eSarutz devp = ddi_get_driver_private(devi); 907a4aa671eSarutz 908a4aa671eSarutz /* 909a4aa671eSarutz * Call the routine scsi_probe to do some of the dirty work. 910a4aa671eSarutz * If the INQUIRY command succeeds, the field dcd_inq in the 911a4aa671eSarutz * device structure will be filled in. The dcd_sense structure 912a4aa671eSarutz * will also be allocated. 913a4aa671eSarutz */ 914a4aa671eSarutz 915a4aa671eSarutz switch (dcd_probe(devp, canwait)) { 916a4aa671eSarutz default: 917a4aa671eSarutz return (DDI_FAILURE); 918a4aa671eSarutz 919a4aa671eSarutz case DCDPROBE_EXISTS: 920a4aa671eSarutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) { 921a4aa671eSarutz if (devp->dcd_ident->dcd_config & ATANON_REMOVABLE) { 922a4aa671eSarutz rval = DDI_SUCCESS; 923a4aa671eSarutz } else { 924a4aa671eSarutz rval = DDI_FAILURE; 925a4aa671eSarutz goto error; 926a4aa671eSarutz } 927a4aa671eSarutz } else { 928a4aa671eSarutz rval = DDI_FAILURE; 929a4aa671eSarutz goto error; 930a4aa671eSarutz } 931a4aa671eSarutz } 932a4aa671eSarutz 933a4aa671eSarutz 934a4aa671eSarutz instance = ddi_get_instance(devp->dcd_dev); 935a4aa671eSarutz 936a4aa671eSarutz if (ddi_soft_state_zalloc(dcd_state, instance) != DDI_SUCCESS) { 937a4aa671eSarutz rval = DDI_FAILURE; 938a4aa671eSarutz goto error; 939a4aa671eSarutz } 940a4aa671eSarutz 941a4aa671eSarutz un = ddi_get_soft_state(dcd_state, instance); 942a4aa671eSarutz 943a4aa671eSarutz un->un_sbufp = getrbuf(km_flags); 944a4aa671eSarutz if (un->un_sbufp == (struct buf *)NULL) { 945a4aa671eSarutz rval = DDI_FAILURE; 946a4aa671eSarutz goto error; 947a4aa671eSarutz } 948a4aa671eSarutz 949a4aa671eSarutz 950a4aa671eSarutz un->un_dcd = devp; 951a4aa671eSarutz un->un_power_level = -1; 952a4aa671eSarutz un->un_tgattribute.media_is_writable = 1; 953a4aa671eSarutz 954a4aa671eSarutz sema_init(&un->un_semoclose, 1, NULL, SEMA_DRIVER, NULL); 955a4aa671eSarutz cv_init(&un->un_sbuf_cv, NULL, CV_DRIVER, NULL); 956a4aa671eSarutz cv_init(&un->un_state_cv, NULL, CV_DRIVER, NULL); 957a4aa671eSarutz /* Initialize power management conditional variable */ 958a4aa671eSarutz cv_init(&un->un_disk_busy_cv, NULL, CV_DRIVER, NULL); 959a4aa671eSarutz cv_init(&un->un_suspend_cv, NULL, CV_DRIVER, NULL); 960a4aa671eSarutz 961a4aa671eSarutz if (un->un_dp == 0) { 962a4aa671eSarutz /* 963a4aa671eSarutz * Assume CCS drive, assume parity, but call 964a4aa671eSarutz * it a CDROM if it is a RODIRECT device. 965a4aa671eSarutz */ 966a4aa671eSarutz un->un_dp = (struct dcd_drivetype *) 967a4aa671eSarutz kmem_zalloc(sizeof (struct dcd_drivetype), km_flags); 968a4aa671eSarutz if (!un->un_dp) { 969a4aa671eSarutz rval = DDI_FAILURE; 970a4aa671eSarutz goto error; 971a4aa671eSarutz } 972a4aa671eSarutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) { 973a4aa671eSarutz if (devp->dcd_ident->dcd_config & ATANON_REMOVABLE) { 974a4aa671eSarutz un->un_dp->ctype = CTYPE_DISK; 975a4aa671eSarutz } 976a4aa671eSarutz } else { 977a4aa671eSarutz rval = DDI_FAILURE; 978a4aa671eSarutz goto error; 979a4aa671eSarutz } 980a4aa671eSarutz un->un_dp->name = "CCS"; 981a4aa671eSarutz un->un_dp->options = 0; 982a4aa671eSarutz } 983a4aa671eSarutz 984a4aa671eSarutz /* 985a4aa671eSarutz * Allow I/O requests at un_secsize offset in multiple of un_secsize. 986a4aa671eSarutz */ 987a4aa671eSarutz un->un_secsize = DEV_BSIZE; 988a4aa671eSarutz 989a4aa671eSarutz /* 990a4aa671eSarutz * If the device is not a removable media device, make sure that 991a4aa671eSarutz * that the device is ready, by issuing the another identify but 992a4aa671eSarutz * not needed. Get the capacity from identify data and store here. 993a4aa671eSarutz */ 994a4aa671eSarutz if (dcd_compute_dk_capacity(devp, &capacity) == 0) { 995a4aa671eSarutz un->un_diskcapacity = capacity; 996a4aa671eSarutz un->un_lbasize = DEV_BSIZE; 997a4aa671eSarutz } 998a4aa671eSarutz 999a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "Geometry Data\n"); 1000a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "cyls %x, heads %x", 1001a4aa671eSarutz devp->dcd_ident->dcd_fixcyls, 1002a4aa671eSarutz devp->dcd_ident->dcd_heads); 1003a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "sectors %x,", 1004a4aa671eSarutz devp->dcd_ident->dcd_sectors); 1005a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "capacity %llx\n", 1006a4aa671eSarutz capacity); 1007a4aa671eSarutz 1008a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1009a4aa671eSarutz "dcdprobe: drive selected\n"); 1010a4aa671eSarutz 1011a4aa671eSarutz /* 1012a4aa671eSarutz * Check for the property target<n>-dcd-options to find the option 1013a4aa671eSarutz * set by the HBA driver for this target so that we can set the 1014a4aa671eSarutz * Unit structure variable so that we can send commands accordingly. 1015a4aa671eSarutz */ 1016cd210bb4SChris Horne target = devp->dcd_address->da_target; 1017a4aa671eSarutz (void) sprintf(prop_str, prop_template, target); 1018a4aa671eSarutz options = ddi_prop_get_int(DDI_DEV_T_ANY, devi, DDI_PROP_NOTPROM, 1019a4aa671eSarutz prop_str, -1); 1020a4aa671eSarutz if (options < 0) { 1021a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1022a4aa671eSarutz "No per target properties"); 1023a4aa671eSarutz } else { 1024a4aa671eSarutz if ((options & DCD_DMA_MODE) == DCD_DMA_MODE) { 1025a4aa671eSarutz un->un_dp->options |= DMA_SUPPORTTED; 1026a4aa671eSarutz un->un_dp->dma_mode = (options >> 3) & 0x03; 1027a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1028a4aa671eSarutz "mode %x\n", un->un_dp->dma_mode); 1029a4aa671eSarutz } else { 1030a4aa671eSarutz un->un_dp->options &= ~DMA_SUPPORTTED; 1031a4aa671eSarutz un->un_dp->pio_mode = options & 0x7; 1032a4aa671eSarutz if (options & DCD_BLOCK_MODE) 1033a4aa671eSarutz un->un_dp->options |= BLOCK_MODE; 1034a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1035a4aa671eSarutz "mode %x\n", un->un_dp->pio_mode); 1036a4aa671eSarutz } 1037a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1038a4aa671eSarutz "options %x,", un->un_dp->options); 1039a4aa671eSarutz } 1040a4aa671eSarutz 1041a4aa671eSarutz un->un_throttle = 2; 1042a4aa671eSarutz /* 1043a4aa671eSarutz * set default max_xfer_size - This should depend on whether the 1044a4aa671eSarutz * Block mode is supported by the device or not. 1045a4aa671eSarutz */ 1046a4aa671eSarutz un->un_max_xfer_size = MAX_ATA_XFER_SIZE; 1047a4aa671eSarutz 1048a4aa671eSarutz /* 1049a4aa671eSarutz * Set write cache enable softstate 1050a4aa671eSarutz * 1051a4aa671eSarutz * WCE is only supported in ATAPI-4 or higher; for 1052a4aa671eSarutz * lower rev devices, must assume write cache is 1053a4aa671eSarutz * enabled. 1054a4aa671eSarutz */ 1055a4aa671eSarutz mutex_enter(DCD_MUTEX); 1056a4aa671eSarutz un->un_write_cache_enabled = (devp->dcd_ident->dcd_majvers == 0xffff) || 1057a4aa671eSarutz ((devp->dcd_ident->dcd_majvers & IDENTIFY_80_ATAPI_4) == 0) || 1058a4aa671eSarutz (devp->dcd_ident->dcd_features85 & IDENTIFY_85_WCE) != 0; 1059a4aa671eSarutz mutex_exit(DCD_MUTEX); 1060a4aa671eSarutz 1061a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1062a4aa671eSarutz "dcd_doattach returns good\n"); 1063a4aa671eSarutz 1064a4aa671eSarutz return (rval); 1065a4aa671eSarutz 1066a4aa671eSarutz error: 1067a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcd_doattach failed\n"); 1068a4aa671eSarutz dcd_free_softstate(un, devi); 1069a4aa671eSarutz return (rval); 1070a4aa671eSarutz } 1071a4aa671eSarutz 1072a4aa671eSarutz #ifdef NOTNEEDED 1073a4aa671eSarutz /* 1074a4aa671eSarutz * This routine is used to set the block mode of operation by issuing the 1075a4aa671eSarutz * Set Block mode ata command with the maximum block mode possible 1076a4aa671eSarutz */ 1077a4aa671eSarutz dcd_set_multiple(struct dcd_disk *un) 1078a4aa671eSarutz { 1079a4aa671eSarutz int status; 1080a4aa671eSarutz struct udcd_cmd ucmd; 1081a4aa671eSarutz struct dcd_cmd cdb; 1082a4aa671eSarutz dev_t dev; 1083a4aa671eSarutz 1084a4aa671eSarutz 1085a4aa671eSarutz /* Zero all the required structure */ 1086a4aa671eSarutz (void) bzero((caddr_t)&ucmd, sizeof (ucmd)); 1087a4aa671eSarutz 1088a4aa671eSarutz (void) bzero((caddr_t)&cdb, sizeof (struct dcd_cmd)); 1089a4aa671eSarutz 1090a4aa671eSarutz cdb.cmd = ATA_SET_MULTIPLE; 1091a4aa671eSarutz /* 1092a4aa671eSarutz * Here we should pass what needs to go into sector count REGISTER. 1093a4aa671eSarutz * Eventhough this field indicates the number of bytes to read we 1094a4aa671eSarutz * need to specify the block factor in terms of bytes so that it 1095a4aa671eSarutz * will be programmed by the HBA driver into the sector count register. 1096a4aa671eSarutz */ 1097a4aa671eSarutz cdb.size = un->un_lbasize * un->un_dp->block_factor; 1098a4aa671eSarutz 1099a4aa671eSarutz cdb.sector_num.lba_num = 0; 1100a4aa671eSarutz cdb.address_mode = ADD_LBA_MODE; 1101a4aa671eSarutz cdb.direction = NO_DATA_XFER; 1102a4aa671eSarutz 1103a4aa671eSarutz ucmd.udcd_flags = 0; 1104a4aa671eSarutz ucmd.udcd_cmd = &cdb; 1105a4aa671eSarutz ucmd.udcd_bufaddr = NULL; 1106a4aa671eSarutz ucmd.udcd_buflen = 0; 1107a4aa671eSarutz ucmd.udcd_flags |= UDCD_SILENT; 1108a4aa671eSarutz 1109a4aa671eSarutz dev = makedevice(ddi_driver_major(DCD_DEVINFO), 1110a4aa671eSarutz ddi_get_instance(DCD_DEVINFO) << DCDUNIT_SHIFT); 1111a4aa671eSarutz 1112a4aa671eSarutz 1113a4aa671eSarutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE); 1114a4aa671eSarutz 1115a4aa671eSarutz return (status); 1116a4aa671eSarutz } 1117a4aa671eSarutz /* 1118a4aa671eSarutz * The following routine is used only for setting the transfer mode 1119a4aa671eSarutz * and it is not designed for transferring any other features subcommand. 1120a4aa671eSarutz */ 1121a4aa671eSarutz dcd_set_features(struct dcd_disk *un, uchar_t mode) 1122a4aa671eSarutz { 1123a4aa671eSarutz int status; 1124a4aa671eSarutz struct udcd_cmd ucmd; 1125a4aa671eSarutz struct dcd_cmd cdb; 1126a4aa671eSarutz dev_t dev; 1127a4aa671eSarutz 1128a4aa671eSarutz 1129a4aa671eSarutz /* Zero all the required structure */ 1130a4aa671eSarutz (void) bzero((caddr_t)&ucmd, sizeof (ucmd)); 1131a4aa671eSarutz 1132a4aa671eSarutz (void) bzero((caddr_t)&cdb, sizeof (struct dcd_cmd)); 1133a4aa671eSarutz 1134a4aa671eSarutz cdb.cmd = ATA_SET_FEATURES; 1135a4aa671eSarutz /* 1136a4aa671eSarutz * Here we need to pass what needs to go into the sector count register 1137a4aa671eSarutz * But in the case of SET FEATURES command the value taken in the 1138a4aa671eSarutz * sector count register depends what type of subcommand is 1139a4aa671eSarutz * passed in the features register. Since we have defined the size to 1140a4aa671eSarutz * be the size in bytes in this context it does not indicate bytes 1141a4aa671eSarutz * instead it indicates the mode to be programmed. 1142a4aa671eSarutz */ 1143a4aa671eSarutz cdb.size = un->un_lbasize * mode; 1144a4aa671eSarutz 1145a4aa671eSarutz cdb.sector_num.lba_num = 0; 1146a4aa671eSarutz cdb.address_mode = ADD_LBA_MODE; 1147a4aa671eSarutz cdb.direction = NO_DATA_XFER; 1148a4aa671eSarutz cdb.features = ATA_FEATURE_SET_MODE; 1149a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1150a4aa671eSarutz "size %x, features %x, cmd %x\n", 1151a4aa671eSarutz cdb.size, cdb.features, cdb.cmd); 1152a4aa671eSarutz 1153a4aa671eSarutz ucmd.udcd_flags = 0; 1154a4aa671eSarutz ucmd.udcd_cmd = &cdb; 1155a4aa671eSarutz ucmd.udcd_bufaddr = NULL; 1156a4aa671eSarutz ucmd.udcd_buflen = 0; 1157a4aa671eSarutz ucmd.udcd_flags |= UDCD_SILENT; 1158a4aa671eSarutz 1159a4aa671eSarutz dev = makedevice(ddi_driver_major(DCD_DEVINFO), 1160a4aa671eSarutz ddi_get_instance(DCD_DEVINFO) << DCDUNIT_SHIFT); 1161a4aa671eSarutz 1162a4aa671eSarutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE); 1163a4aa671eSarutz 1164a4aa671eSarutz return (status); 1165a4aa671eSarutz } 1166a4aa671eSarutz #endif 1167a4aa671eSarutz 1168a4aa671eSarutz /* 1169a4aa671eSarutz * Validate the geometry for this disk, e.g., 1170a4aa671eSarutz * see whether it has a valid label. 1171a4aa671eSarutz */ 1172a4aa671eSarutz static int 1173a4aa671eSarutz dcd_validate_geometry(struct dcd_disk *un) 1174a4aa671eSarutz { 1175a4aa671eSarutz int secsize = 0; 1176a4aa671eSarutz struct dcd_device *devp; 1177a4aa671eSarutz int secdiv; 1178a4aa671eSarutz int rval; 1179a4aa671eSarutz 1180a4aa671eSarutz ASSERT(mutex_owned(DCD_MUTEX)); 1181a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1182a4aa671eSarutz "dcd_validate_geometry: started \n"); 1183a4aa671eSarutz 1184a4aa671eSarutz if (un->un_lbasize < 0) { 1185a4aa671eSarutz return (DCD_BAD_LABEL); 1186a4aa671eSarutz } 1187a4aa671eSarutz 1188a4aa671eSarutz if (un->un_state == DCD_STATE_PM_SUSPENDED) { 1189a4aa671eSarutz mutex_exit(DCD_MUTEX); 1190b9ccdc5aScth if (pm_raise_power(DCD_DEVINFO, 0, DCD_DEVICE_ACTIVE) != 1191b9ccdc5aScth DDI_SUCCESS) { 1192a4aa671eSarutz mutex_enter(DCD_MUTEX); 1193a4aa671eSarutz return (DCD_BAD_LABEL); 1194a4aa671eSarutz } 1195a4aa671eSarutz mutex_enter(DCD_MUTEX); 1196a4aa671eSarutz } 1197a4aa671eSarutz 1198a4aa671eSarutz secsize = un->un_secsize; 1199a4aa671eSarutz 1200a4aa671eSarutz /* 1201a4aa671eSarutz * take a log base 2 of sector size (sorry) 1202a4aa671eSarutz */ 1203a4aa671eSarutz for (secdiv = 0; secsize = secsize >> 1; secdiv++) 1204a4aa671eSarutz ; 1205a4aa671eSarutz un->un_secdiv = secdiv; 1206a4aa671eSarutz 1207a4aa671eSarutz /* 1208a4aa671eSarutz * Only DIRECT ACCESS devices will have Sun labels. 1209a4aa671eSarutz * CD's supposedly have a Sun label, too 1210a4aa671eSarutz */ 1211a4aa671eSarutz 1212a4aa671eSarutz devp = un->un_dcd; 1213a4aa671eSarutz 1214a4aa671eSarutz if (((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) && 1215a4aa671eSarutz (devp->dcd_ident->dcd_config & ATANON_REMOVABLE)) { 1216a4aa671eSarutz mutex_exit(DCD_MUTEX); 1217a4aa671eSarutz rval = cmlb_validate(un->un_dklbhandle, 0, 0); 1218a4aa671eSarutz mutex_enter(DCD_MUTEX); 1219a4aa671eSarutz if (rval == ENOMEM) 1220a4aa671eSarutz return (DCD_NO_MEM_FOR_LABEL); 1221a4aa671eSarutz else if (rval != 0) 1222a4aa671eSarutz return (DCD_BAD_LABEL); 1223a4aa671eSarutz } else { 1224a4aa671eSarutz /* it should never get here. */ 1225a4aa671eSarutz return (DCD_BAD_LABEL); 1226a4aa671eSarutz } 1227a4aa671eSarutz 1228a4aa671eSarutz /* 1229a4aa671eSarutz * take a log base 2 of logical block size 1230a4aa671eSarutz */ 1231a4aa671eSarutz secsize = un->un_lbasize; 1232a4aa671eSarutz for (secdiv = 0; secsize = secsize >> 1; secdiv++) 1233a4aa671eSarutz ; 1234a4aa671eSarutz un->un_lbadiv = secdiv; 1235a4aa671eSarutz 1236a4aa671eSarutz /* 1237a4aa671eSarutz * take a log base 2 of the multiple of DEV_BSIZE blocks that 1238a4aa671eSarutz * make up one logical block 1239a4aa671eSarutz */ 1240a4aa671eSarutz secsize = un->un_lbasize >> DEV_BSHIFT; 1241a4aa671eSarutz for (secdiv = 0; secsize = secsize >> 1; secdiv++) 1242a4aa671eSarutz ; 1243a4aa671eSarutz un->un_blknoshift = secdiv; 1244a4aa671eSarutz return (0); 1245a4aa671eSarutz } 1246a4aa671eSarutz 1247a4aa671eSarutz /* 1248a4aa671eSarutz * Unix Entry Points 1249a4aa671eSarutz */ 1250a4aa671eSarutz 1251a4aa671eSarutz /* ARGSUSED3 */ 1252a4aa671eSarutz static int 1253a4aa671eSarutz dcdopen(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 1254a4aa671eSarutz { 1255a4aa671eSarutz dev_t dev = *dev_p; 1256a4aa671eSarutz int rval = EIO; 1257a4aa671eSarutz int partmask; 1258a4aa671eSarutz int nodelay = (flag & (FNDELAY | FNONBLOCK)); 1259a4aa671eSarutz int i; 1260a4aa671eSarutz char kstatname[KSTAT_STRLEN]; 1261a4aa671eSarutz diskaddr_t lblocks; 1262a4aa671eSarutz char *partname; 1263a4aa671eSarutz 1264a4aa671eSarutz GET_SOFT_STATE(dev); 1265a4aa671eSarutz 1266a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1267a4aa671eSarutz "Inside Open flag %x, otyp %x\n", flag, otyp); 1268a4aa671eSarutz 1269a4aa671eSarutz if (otyp >= OTYPCNT) { 1270a4aa671eSarutz return (EINVAL); 1271a4aa671eSarutz } 1272a4aa671eSarutz 1273a4aa671eSarutz partmask = 1 << part; 1274a4aa671eSarutz 1275a4aa671eSarutz /* 1276a4aa671eSarutz * We use a semaphore here in order to serialize 1277a4aa671eSarutz * open and close requests on the device. 1278a4aa671eSarutz */ 1279a4aa671eSarutz sema_p(&un->un_semoclose); 1280a4aa671eSarutz 1281a4aa671eSarutz mutex_enter(DCD_MUTEX); 1282a4aa671eSarutz 1283a4aa671eSarutz if ((un->un_state & DCD_STATE_FATAL) == DCD_STATE_FATAL) { 1284a4aa671eSarutz rval = ENXIO; 1285a4aa671eSarutz goto done; 1286a4aa671eSarutz } 1287a4aa671eSarutz 1288a4aa671eSarutz while (un->un_state == DCD_STATE_SUSPENDED) { 1289a4aa671eSarutz cv_wait(&un->un_suspend_cv, DCD_MUTEX); 1290a4aa671eSarutz } 1291a4aa671eSarutz 1292a4aa671eSarutz if ((un->un_state == DCD_STATE_PM_SUSPENDED) && (!nodelay)) { 1293a4aa671eSarutz mutex_exit(DCD_MUTEX); 1294a4aa671eSarutz if (pm_raise_power(DCD_DEVINFO, 0, DCD_DEVICE_ACTIVE) 1295a4aa671eSarutz != DDI_SUCCESS) { 1296a4aa671eSarutz mutex_enter(DCD_MUTEX); 1297a4aa671eSarutz rval = EIO; 1298a4aa671eSarutz goto done; 1299a4aa671eSarutz } 1300a4aa671eSarutz mutex_enter(DCD_MUTEX); 1301a4aa671eSarutz } 1302a4aa671eSarutz 1303a4aa671eSarutz /* 1304a4aa671eSarutz * set make_dcd_cmd() flags and stat_size here since these 1305a4aa671eSarutz * are unlikely to change 1306a4aa671eSarutz */ 1307a4aa671eSarutz un->un_cmd_flags = 0; 1308a4aa671eSarutz 1309a4aa671eSarutz un->un_cmd_stat_size = 2; 1310a4aa671eSarutz 1311a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdopen un=0x%p\n", 1312a4aa671eSarutz (void *)un); 1313a4aa671eSarutz /* 1314a4aa671eSarutz * check for previous exclusive open 1315a4aa671eSarutz */ 1316a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1317a4aa671eSarutz "exclopen=%x, flag=%x, regopen=%x\n", 1318a4aa671eSarutz un->un_exclopen, flag, un->un_ocmap.regopen[otyp]); 1319a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1320a4aa671eSarutz "Exclusive open flag %x, partmask %x\n", 1321a4aa671eSarutz un->un_exclopen, partmask); 1322a4aa671eSarutz 1323a4aa671eSarutz if (un->un_exclopen & (partmask)) { 1324a4aa671eSarutz failed_exclusive: 1325a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1326a4aa671eSarutz "exclusive open fails\n"); 1327a4aa671eSarutz rval = EBUSY; 1328a4aa671eSarutz goto done; 1329a4aa671eSarutz } 1330a4aa671eSarutz 1331a4aa671eSarutz if (flag & FEXCL) { 1332a4aa671eSarutz int i; 1333a4aa671eSarutz if (un->un_ocmap.lyropen[part]) { 1334a4aa671eSarutz goto failed_exclusive; 1335a4aa671eSarutz } 1336a4aa671eSarutz for (i = 0; i < (OTYPCNT - 1); i++) { 1337a4aa671eSarutz if (un->un_ocmap.regopen[i] & (partmask)) { 1338a4aa671eSarutz goto failed_exclusive; 1339a4aa671eSarutz } 1340a4aa671eSarutz } 1341a4aa671eSarutz } 1342a4aa671eSarutz if (flag & FWRITE) { 1343a4aa671eSarutz mutex_exit(DCD_MUTEX); 1344a4aa671eSarutz if (dcd_check_wp(dev)) { 1345a4aa671eSarutz sema_v(&un->un_semoclose); 1346a4aa671eSarutz return (EROFS); 1347a4aa671eSarutz } 1348a4aa671eSarutz mutex_enter(DCD_MUTEX); 1349a4aa671eSarutz } 1350a4aa671eSarutz 1351a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1352a4aa671eSarutz "Check Write Protect handled\n"); 1353a4aa671eSarutz 1354a4aa671eSarutz if (!nodelay) { 1355a4aa671eSarutz mutex_exit(DCD_MUTEX); 1356a4aa671eSarutz if ((rval = dcd_ready_and_valid(dev, un)) != 0) { 1357a4aa671eSarutz rval = EIO; 1358a4aa671eSarutz } 1359a4aa671eSarutz (void) pm_idle_component(DCD_DEVINFO, 0); 1360a4aa671eSarutz /* 1361a4aa671eSarutz * Fail if device is not ready or if the number of disk 1362a4aa671eSarutz * blocks is zero or negative for non CD devices. 1363a4aa671eSarutz */ 1364a4aa671eSarutz if (rval || cmlb_partinfo(un->un_dklbhandle, 1365a4aa671eSarutz part, &lblocks, NULL, &partname, NULL, 0) || 1366a4aa671eSarutz lblocks <= 0) { 1367a4aa671eSarutz rval = EIO; 1368a4aa671eSarutz mutex_enter(DCD_MUTEX); 1369a4aa671eSarutz goto done; 1370a4aa671eSarutz } 1371a4aa671eSarutz mutex_enter(DCD_MUTEX); 1372a4aa671eSarutz } 1373a4aa671eSarutz 1374a4aa671eSarutz if (otyp == OTYP_LYR) { 1375a4aa671eSarutz un->un_ocmap.lyropen[part]++; 1376a4aa671eSarutz } else { 1377a4aa671eSarutz un->un_ocmap.regopen[otyp] |= partmask; 1378a4aa671eSarutz } 1379a4aa671eSarutz 1380a4aa671eSarutz /* 1381a4aa671eSarutz * set up open and exclusive open flags 1382a4aa671eSarutz */ 1383a4aa671eSarutz if (flag & FEXCL) { 1384a4aa671eSarutz un->un_exclopen |= (partmask); 1385a4aa671eSarutz } 1386a4aa671eSarutz 1387a4aa671eSarutz 1388a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1389a4aa671eSarutz "open of part %d type %d\n", 1390a4aa671eSarutz part, otyp); 1391a4aa671eSarutz 1392a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1393a4aa671eSarutz "Kstats getting updated\n"); 1394a4aa671eSarutz /* 1395a4aa671eSarutz * only create kstats for disks, CD kstats created in dcdattach 1396a4aa671eSarutz */ 1397a4aa671eSarutz _NOTE(NO_COMPETING_THREADS_NOW); 1398a4aa671eSarutz mutex_exit(DCD_MUTEX); 1399a4aa671eSarutz if (un->un_stats == (kstat_t *)0) { 1400a4aa671eSarutz un->un_stats = kstat_create("dad", instance, 1401a4aa671eSarutz NULL, "disk", KSTAT_TYPE_IO, 1, 1402a4aa671eSarutz KSTAT_FLAG_PERSISTENT); 1403a4aa671eSarutz if (un->un_stats) { 1404a4aa671eSarutz un->un_stats->ks_lock = DCD_MUTEX; 1405a4aa671eSarutz kstat_install(un->un_stats); 1406a4aa671eSarutz } 1407a4aa671eSarutz 1408a4aa671eSarutz /* 1409a4aa671eSarutz * set up partition statistics for each partition 1410a4aa671eSarutz * with number of blocks > 0 1411a4aa671eSarutz */ 1412a4aa671eSarutz if (!nodelay) { 1413a4aa671eSarutz for (i = 0; i < NDKMAP; i++) { 1414a4aa671eSarutz if ((un->un_pstats[i] == (kstat_t *)0) && 1415a4aa671eSarutz (cmlb_partinfo(un->un_dklbhandle, 1416a4aa671eSarutz i, &lblocks, NULL, &partname, 1417a4aa671eSarutz NULL, 0) == 0) && lblocks > 0) { 1418a4aa671eSarutz (void) sprintf(kstatname, "dad%d,%s", 1419a4aa671eSarutz instance, partname); 1420a4aa671eSarutz un->un_pstats[i] = kstat_create("dad", 1421a4aa671eSarutz instance, 1422a4aa671eSarutz kstatname, 1423a4aa671eSarutz "partition", 1424a4aa671eSarutz KSTAT_TYPE_IO, 1425a4aa671eSarutz 1, 1426a4aa671eSarutz KSTAT_FLAG_PERSISTENT); 1427a4aa671eSarutz if (un->un_pstats[i]) { 1428a4aa671eSarutz un->un_pstats[i]->ks_lock = 1429a4aa671eSarutz DCD_MUTEX; 1430a4aa671eSarutz kstat_install(un->un_pstats[i]); 1431a4aa671eSarutz } 1432a4aa671eSarutz } 1433a4aa671eSarutz } 1434a4aa671eSarutz } 1435a4aa671eSarutz /* 1436a4aa671eSarutz * set up error kstats 1437a4aa671eSarutz */ 1438a4aa671eSarutz (void) dcd_create_errstats(un, instance); 1439a4aa671eSarutz } 1440a4aa671eSarutz #ifndef lint 1441a4aa671eSarutz _NOTE(COMPETING_THREADS_NOW); 1442a4aa671eSarutz #endif 1443a4aa671eSarutz 1444a4aa671eSarutz sema_v(&un->un_semoclose); 1445a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "Open success\n"); 1446a4aa671eSarutz return (0); 1447a4aa671eSarutz 1448a4aa671eSarutz done: 1449a4aa671eSarutz mutex_exit(DCD_MUTEX); 1450a4aa671eSarutz sema_v(&un->un_semoclose); 1451a4aa671eSarutz return (rval); 1452a4aa671eSarutz 1453a4aa671eSarutz } 1454a4aa671eSarutz 1455a4aa671eSarutz /* 1456a4aa671eSarutz * Test if disk is ready and has a valid geometry. 1457a4aa671eSarutz */ 1458a4aa671eSarutz static int 1459a4aa671eSarutz dcd_ready_and_valid(dev_t dev, struct dcd_disk *un) 1460a4aa671eSarutz { 1461a4aa671eSarutz int rval = 1; 1462a4aa671eSarutz int g_error = 0; 1463a4aa671eSarutz 1464a4aa671eSarutz mutex_enter(DCD_MUTEX); 1465a4aa671eSarutz /* 1466a4aa671eSarutz * cmds outstanding 1467a4aa671eSarutz */ 1468a4aa671eSarutz if (un->un_ncmds == 0) { 1469a4aa671eSarutz (void) dcd_unit_ready(dev); 1470a4aa671eSarutz } 1471a4aa671eSarutz 1472a4aa671eSarutz /* 1473a4aa671eSarutz * If device is not yet ready here, inform it is offline 1474a4aa671eSarutz */ 1475a4aa671eSarutz if (un->un_state == DCD_STATE_NORMAL) { 1476a4aa671eSarutz rval = dcd_unit_ready(dev); 1477a4aa671eSarutz if (rval != 0 && rval != EACCES) { 1478a4aa671eSarutz dcd_offline(un, 1); 1479a4aa671eSarutz goto done; 1480a4aa671eSarutz } 1481a4aa671eSarutz } 1482a4aa671eSarutz 1483a4aa671eSarutz if (un->un_format_in_progress == 0) { 1484a4aa671eSarutz g_error = dcd_validate_geometry(un); 1485a4aa671eSarutz } 1486a4aa671eSarutz 1487a4aa671eSarutz /* 1488a4aa671eSarutz * check if geometry was valid. We don't check the validity of 1489a4aa671eSarutz * geometry for CDROMS. 1490a4aa671eSarutz */ 1491a4aa671eSarutz 1492a4aa671eSarutz if (g_error == DCD_BAD_LABEL) { 1493a4aa671eSarutz rval = 1; 1494a4aa671eSarutz goto done; 1495a4aa671eSarutz } 1496a4aa671eSarutz 1497a4aa671eSarutz 1498a4aa671eSarutz /* 1499a4aa671eSarutz * the state has changed; inform the media watch routines 1500a4aa671eSarutz */ 1501a4aa671eSarutz un->un_mediastate = DKIO_INSERTED; 1502a4aa671eSarutz cv_broadcast(&un->un_state_cv); 1503a4aa671eSarutz rval = 0; 1504a4aa671eSarutz 1505a4aa671eSarutz done: 1506a4aa671eSarutz mutex_exit(DCD_MUTEX); 1507a4aa671eSarutz return (rval); 1508a4aa671eSarutz } 1509a4aa671eSarutz 1510a4aa671eSarutz 1511a4aa671eSarutz /*ARGSUSED*/ 1512a4aa671eSarutz static int 1513a4aa671eSarutz dcdclose(dev_t dev, int flag, int otyp, cred_t *cred_p) 1514a4aa671eSarutz { 1515a4aa671eSarutz uchar_t *cp; 1516a4aa671eSarutz int i; 1517a4aa671eSarutz 1518a4aa671eSarutz GET_SOFT_STATE(dev); 1519a4aa671eSarutz 1520a4aa671eSarutz 1521a4aa671eSarutz if (otyp >= OTYPCNT) 1522a4aa671eSarutz return (ENXIO); 1523a4aa671eSarutz 1524a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1525a4aa671eSarutz "close of part %d type %d\n", 1526a4aa671eSarutz part, otyp); 1527a4aa671eSarutz sema_p(&un->un_semoclose); 1528a4aa671eSarutz 1529a4aa671eSarutz mutex_enter(DCD_MUTEX); 1530a4aa671eSarutz 1531a4aa671eSarutz if (un->un_exclopen & (1<<part)) { 1532a4aa671eSarutz un->un_exclopen &= ~(1<<part); 1533a4aa671eSarutz } 1534a4aa671eSarutz 1535a4aa671eSarutz if (otyp == OTYP_LYR) { 1536a4aa671eSarutz un->un_ocmap.lyropen[part] -= 1; 1537a4aa671eSarutz } else { 1538a4aa671eSarutz un->un_ocmap.regopen[otyp] &= ~(1<<part); 1539a4aa671eSarutz } 1540a4aa671eSarutz 1541a4aa671eSarutz cp = &un->un_ocmap.chkd[0]; 1542a4aa671eSarutz while (cp < &un->un_ocmap.chkd[OCSIZE]) { 1543a4aa671eSarutz if (*cp != (uchar_t)0) { 1544a4aa671eSarutz break; 1545a4aa671eSarutz } 1546a4aa671eSarutz cp++; 1547a4aa671eSarutz } 1548a4aa671eSarutz 1549a4aa671eSarutz if (cp == &un->un_ocmap.chkd[OCSIZE]) { 1550a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "last close\n"); 1551a4aa671eSarutz if (un->un_state == DCD_STATE_OFFLINE) { 1552a4aa671eSarutz dcd_offline(un, 1); 1553a4aa671eSarutz } 1554a4aa671eSarutz 1555a4aa671eSarutz mutex_exit(DCD_MUTEX); 1556a4aa671eSarutz (void) cmlb_close(un->un_dklbhandle, 0); 1557a4aa671eSarutz 1558a4aa671eSarutz _NOTE(NO_COMPETING_THREADS_NOW); 1559a4aa671eSarutz if (un->un_stats) { 1560a4aa671eSarutz kstat_delete(un->un_stats); 1561a4aa671eSarutz un->un_stats = 0; 1562a4aa671eSarutz } 1563a4aa671eSarutz for (i = 0; i < NDKMAP; i++) { 1564a4aa671eSarutz if (un->un_pstats[i]) { 1565a4aa671eSarutz kstat_delete(un->un_pstats[i]); 1566a4aa671eSarutz un->un_pstats[i] = (kstat_t *)0; 1567a4aa671eSarutz } 1568a4aa671eSarutz } 1569a4aa671eSarutz 1570a4aa671eSarutz if (un->un_errstats) { 1571a4aa671eSarutz kstat_delete(un->un_errstats); 1572a4aa671eSarutz un->un_errstats = (kstat_t *)0; 1573a4aa671eSarutz } 1574a4aa671eSarutz mutex_enter(DCD_MUTEX); 1575a4aa671eSarutz 1576a4aa671eSarutz #ifndef lint 1577a4aa671eSarutz _NOTE(COMPETING_THREADS_NOW); 1578a4aa671eSarutz #endif 1579a4aa671eSarutz } 1580a4aa671eSarutz 1581a4aa671eSarutz mutex_exit(DCD_MUTEX); 1582a4aa671eSarutz sema_v(&un->un_semoclose); 1583a4aa671eSarutz return (0); 1584a4aa671eSarutz } 1585a4aa671eSarutz 1586a4aa671eSarutz static void 1587a4aa671eSarutz dcd_offline(struct dcd_disk *un, int bechatty) 1588a4aa671eSarutz { 1589a4aa671eSarutz if (bechatty) 1590a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, "offline\n"); 1591a4aa671eSarutz 1592a4aa671eSarutz mutex_exit(DCD_MUTEX); 1593a4aa671eSarutz cmlb_invalidate(un->un_dklbhandle, 0); 1594a4aa671eSarutz mutex_enter(DCD_MUTEX); 1595a4aa671eSarutz } 1596a4aa671eSarutz 1597a4aa671eSarutz /* 1598a4aa671eSarutz * Given the device number return the devinfo pointer 1599a4aa671eSarutz * from the scsi_device structure. 1600a4aa671eSarutz */ 1601a4aa671eSarutz /*ARGSUSED*/ 1602a4aa671eSarutz static int 1603a4aa671eSarutz dcdinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 1604a4aa671eSarutz { 1605a4aa671eSarutz dev_t dev; 1606a4aa671eSarutz struct dcd_disk *un; 1607a4aa671eSarutz int instance, error; 1608a4aa671eSarutz 1609a4aa671eSarutz 1610a4aa671eSarutz switch (infocmd) { 1611a4aa671eSarutz case DDI_INFO_DEVT2DEVINFO: 1612a4aa671eSarutz dev = (dev_t)arg; 1613a4aa671eSarutz instance = DCDUNIT(dev); 1614a4aa671eSarutz if ((un = ddi_get_soft_state(dcd_state, instance)) == NULL) 1615a4aa671eSarutz return (DDI_FAILURE); 1616a4aa671eSarutz *result = (void *) DCD_DEVINFO; 1617a4aa671eSarutz error = DDI_SUCCESS; 1618a4aa671eSarutz break; 1619a4aa671eSarutz case DDI_INFO_DEVT2INSTANCE: 1620a4aa671eSarutz dev = (dev_t)arg; 1621a4aa671eSarutz instance = DCDUNIT(dev); 1622a4aa671eSarutz *result = (void *)(uintptr_t)instance; 1623a4aa671eSarutz error = DDI_SUCCESS; 1624a4aa671eSarutz break; 1625a4aa671eSarutz default: 1626a4aa671eSarutz error = DDI_FAILURE; 1627a4aa671eSarutz } 1628a4aa671eSarutz return (error); 1629a4aa671eSarutz } 1630a4aa671eSarutz 1631a4aa671eSarutz /* 1632a4aa671eSarutz * property operation routine. return the number of blocks for the partition 1633a4aa671eSarutz * in question or forward the request to the propery facilities. 1634a4aa671eSarutz */ 1635a4aa671eSarutz static int 1636a4aa671eSarutz dcd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 1637a4aa671eSarutz char *name, caddr_t valuep, int *lengthp) 1638a4aa671eSarutz { 1639a4aa671eSarutz struct dcd_disk *un; 1640a4aa671eSarutz 1641b9ccdc5aScth if ((un = ddi_get_soft_state(dcd_state, ddi_get_instance(dip))) == NULL) 1642a4aa671eSarutz return (ddi_prop_op(dev, dip, prop_op, mod_flags, 1643a4aa671eSarutz name, valuep, lengthp)); 1644a4aa671eSarutz 1645b9ccdc5aScth return (cmlb_prop_op(un->un_dklbhandle, 1646b9ccdc5aScth dev, dip, prop_op, mod_flags, name, valuep, lengthp, 1647b9ccdc5aScth DCDPART(dev), NULL)); 1648a4aa671eSarutz } 1649a4aa671eSarutz 1650a4aa671eSarutz /* 1651a4aa671eSarutz * These routines perform raw i/o operations. 1652a4aa671eSarutz */ 1653a4aa671eSarutz /*ARGSUSED*/ 1654a4aa671eSarutz void 1655a4aa671eSarutz dcduscsimin(struct buf *bp) 1656a4aa671eSarutz { 1657a4aa671eSarutz 1658a4aa671eSarutz } 1659a4aa671eSarutz 1660a4aa671eSarutz 1661a4aa671eSarutz static void 1662a4aa671eSarutz dcdmin(struct buf *bp) 1663a4aa671eSarutz { 1664a4aa671eSarutz struct dcd_disk *un; 1665a4aa671eSarutz int instance; 1666a4aa671eSarutz minor_t minor = getminor(bp->b_edev); 1667a4aa671eSarutz instance = minor >> DCDUNIT_SHIFT; 1668a4aa671eSarutz un = ddi_get_soft_state(dcd_state, instance); 1669a4aa671eSarutz 1670a4aa671eSarutz if (bp->b_bcount > un->un_max_xfer_size) 1671a4aa671eSarutz bp->b_bcount = un->un_max_xfer_size; 1672a4aa671eSarutz } 1673a4aa671eSarutz 1674a4aa671eSarutz 1675a4aa671eSarutz /* ARGSUSED2 */ 1676a4aa671eSarutz static int 1677a4aa671eSarutz dcdread(dev_t dev, struct uio *uio, cred_t *cred_p) 1678a4aa671eSarutz { 1679a4aa671eSarutz int secmask; 1680a4aa671eSarutz GET_SOFT_STATE(dev); 1681a4aa671eSarutz #ifdef lint 1682a4aa671eSarutz part = part; 1683a4aa671eSarutz #endif /* lint */ 1684a4aa671eSarutz secmask = un->un_secsize - 1; 1685a4aa671eSarutz 1686a4aa671eSarutz if (uio->uio_loffset & ((offset_t)(secmask))) { 1687a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1688a4aa671eSarutz "file offset not modulo %d\n", 1689a4aa671eSarutz un->un_secsize); 1690a4aa671eSarutz return (EINVAL); 1691a4aa671eSarutz } else if (uio->uio_iov->iov_len & (secmask)) { 1692a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1693a4aa671eSarutz "transfer length not modulo %d\n", un->un_secsize); 1694a4aa671eSarutz return (EINVAL); 1695a4aa671eSarutz } 1696a4aa671eSarutz return (physio(dcdstrategy, (struct buf *)0, dev, B_READ, dcdmin, uio)); 1697a4aa671eSarutz } 1698a4aa671eSarutz 1699a4aa671eSarutz /* ARGSUSED2 */ 1700a4aa671eSarutz static int 1701a4aa671eSarutz dcdaread(dev_t dev, struct aio_req *aio, cred_t *cred_p) 1702a4aa671eSarutz { 1703a4aa671eSarutz int secmask; 1704a4aa671eSarutz struct uio *uio = aio->aio_uio; 1705a4aa671eSarutz GET_SOFT_STATE(dev); 1706a4aa671eSarutz #ifdef lint 1707a4aa671eSarutz part = part; 1708a4aa671eSarutz #endif /* lint */ 1709a4aa671eSarutz secmask = un->un_secsize - 1; 1710a4aa671eSarutz 1711a4aa671eSarutz if (uio->uio_loffset & ((offset_t)(secmask))) { 1712a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1713a4aa671eSarutz "file offset not modulo %d\n", 1714a4aa671eSarutz un->un_secsize); 1715a4aa671eSarutz return (EINVAL); 1716a4aa671eSarutz } else if (uio->uio_iov->iov_len & (secmask)) { 1717a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1718a4aa671eSarutz "transfer length not modulo %d\n", un->un_secsize); 1719a4aa671eSarutz return (EINVAL); 1720a4aa671eSarutz } 1721a4aa671eSarutz return (aphysio(dcdstrategy, anocancel, dev, B_READ, dcdmin, aio)); 1722a4aa671eSarutz } 1723a4aa671eSarutz 1724a4aa671eSarutz /* ARGSUSED2 */ 1725a4aa671eSarutz static int 1726a4aa671eSarutz dcdwrite(dev_t dev, struct uio *uio, cred_t *cred_p) 1727a4aa671eSarutz { 1728a4aa671eSarutz int secmask; 1729a4aa671eSarutz GET_SOFT_STATE(dev); 1730a4aa671eSarutz #ifdef lint 1731a4aa671eSarutz part = part; 1732a4aa671eSarutz #endif /* lint */ 1733a4aa671eSarutz secmask = un->un_secsize - 1; 1734a4aa671eSarutz 1735a4aa671eSarutz if (uio->uio_loffset & ((offset_t)(secmask))) { 1736a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1737a4aa671eSarutz "file offset not modulo %d\n", 1738a4aa671eSarutz un->un_secsize); 1739a4aa671eSarutz return (EINVAL); 1740a4aa671eSarutz } else if (uio->uio_iov->iov_len & (secmask)) { 1741a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1742a4aa671eSarutz "transfer length not modulo %d\n", un->un_secsize); 1743a4aa671eSarutz return (EINVAL); 1744a4aa671eSarutz } 1745a4aa671eSarutz return (physio(dcdstrategy, (struct buf *)0, dev, B_WRITE, dcdmin, 1746a4aa671eSarutz uio)); 1747a4aa671eSarutz } 1748a4aa671eSarutz 1749a4aa671eSarutz /* ARGSUSED2 */ 1750a4aa671eSarutz static int 1751a4aa671eSarutz dcdawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p) 1752a4aa671eSarutz { 1753a4aa671eSarutz int secmask; 1754a4aa671eSarutz struct uio *uio = aio->aio_uio; 1755a4aa671eSarutz GET_SOFT_STATE(dev); 1756a4aa671eSarutz #ifdef lint 1757a4aa671eSarutz part = part; 1758a4aa671eSarutz #endif /* lint */ 1759a4aa671eSarutz secmask = un->un_secsize - 1; 1760a4aa671eSarutz 1761a4aa671eSarutz if (uio->uio_loffset & ((offset_t)(secmask))) { 1762a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1763a4aa671eSarutz "file offset not modulo %d\n", 1764a4aa671eSarutz un->un_secsize); 1765a4aa671eSarutz return (EINVAL); 1766a4aa671eSarutz } else if (uio->uio_iov->iov_len & (secmask)) { 1767a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1768a4aa671eSarutz "transfer length not modulo %d\n", un->un_secsize); 1769a4aa671eSarutz return (EINVAL); 1770a4aa671eSarutz } 1771a4aa671eSarutz return (aphysio(dcdstrategy, anocancel, dev, B_WRITE, dcdmin, aio)); 1772a4aa671eSarutz } 1773a4aa671eSarutz 1774a4aa671eSarutz /* 1775a4aa671eSarutz * strategy routine 1776a4aa671eSarutz */ 1777a4aa671eSarutz static int 1778a4aa671eSarutz dcdstrategy(struct buf *bp) 1779a4aa671eSarutz { 1780a4aa671eSarutz struct dcd_disk *un; 1781a4aa671eSarutz struct diskhd *dp; 1782a4aa671eSarutz int i; 1783a4aa671eSarutz minor_t minor = getminor(bp->b_edev); 1784a4aa671eSarutz diskaddr_t p_lblksrt; 1785a4aa671eSarutz diskaddr_t lblocks; 1786a4aa671eSarutz diskaddr_t bn; 1787a4aa671eSarutz 1788a4aa671eSarutz if ((un = ddi_get_soft_state(dcd_state, 1789a4aa671eSarutz minor >> DCDUNIT_SHIFT)) == NULL || 1790a4aa671eSarutz un->un_state == DCD_STATE_DUMPING || 1791a4aa671eSarutz ((un->un_state & DCD_STATE_FATAL) == DCD_STATE_FATAL)) { 1792a4aa671eSarutz SET_BP_ERROR(bp, ((un) ? ENXIO : EIO)); 1793a4aa671eSarutz error: 1794a4aa671eSarutz bp->b_resid = bp->b_bcount; 1795a4aa671eSarutz biodone(bp); 1796a4aa671eSarutz return (0); 1797a4aa671eSarutz } 1798a4aa671eSarutz 1799a4aa671eSarutz /* 1800a4aa671eSarutz * If the request size (buf->b_bcount)is greater than the size 1801a4aa671eSarutz * (un->un_max_xfer_size) supported by the target driver fail 1802a4aa671eSarutz * the request with EINVAL error code. 1803a4aa671eSarutz * 1804a4aa671eSarutz * We are not supposed to receive requests exceeding 1805a4aa671eSarutz * un->un_max_xfer_size size because the caller is expected to 1806a4aa671eSarutz * check what is the maximum size that is supported by this 1807a4aa671eSarutz * driver either through ioctl or dcdmin routine(which is private 1808a4aa671eSarutz * to this driver). 1809a4aa671eSarutz * But we have seen cases (like meta driver(md))where dcdstrategy 1810a4aa671eSarutz * called with more than supported size and cause data corruption. 1811a4aa671eSarutz */ 1812a4aa671eSarutz 1813a4aa671eSarutz if (bp->b_bcount > un->un_max_xfer_size) { 1814a4aa671eSarutz SET_BP_ERROR(bp, EINVAL); 1815a4aa671eSarutz goto error; 1816a4aa671eSarutz } 1817a4aa671eSarutz 1818a4aa671eSarutz TRACE_2(TR_FAC_DADA, TR_DCDSTRATEGY_START, 1819a4aa671eSarutz "dcdstrategy_start: bp 0x%p un 0x%p", bp, un); 1820a4aa671eSarutz 1821a4aa671eSarutz /* 1822a4aa671eSarutz * Commands may sneak in while we released the mutex in 1823a4aa671eSarutz * DDI_SUSPEND, we should block new commands. 1824a4aa671eSarutz */ 1825a4aa671eSarutz mutex_enter(DCD_MUTEX); 1826a4aa671eSarutz while (un->un_state == DCD_STATE_SUSPENDED) { 1827a4aa671eSarutz cv_wait(&un->un_suspend_cv, DCD_MUTEX); 1828a4aa671eSarutz } 1829a4aa671eSarutz 1830a4aa671eSarutz if (un->un_state == DCD_STATE_PM_SUSPENDED) { 1831a4aa671eSarutz mutex_exit(DCD_MUTEX); 1832a4aa671eSarutz (void) pm_idle_component(DCD_DEVINFO, 0); 1833a4aa671eSarutz if (pm_raise_power(DCD_DEVINFO, 0, 1834a4aa671eSarutz DCD_DEVICE_ACTIVE) != DDI_SUCCESS) { 1835a4aa671eSarutz SET_BP_ERROR(bp, EIO); 1836a4aa671eSarutz goto error; 1837a4aa671eSarutz } 1838a4aa671eSarutz mutex_enter(DCD_MUTEX); 1839a4aa671eSarutz } 1840a4aa671eSarutz mutex_exit(DCD_MUTEX); 1841a4aa671eSarutz 1842a4aa671eSarutz /* 1843a4aa671eSarutz * Map-in the buffer in case starting address is not word aligned. 1844a4aa671eSarutz */ 1845a4aa671eSarutz 1846a4aa671eSarutz if (((uintptr_t)bp->b_un.b_addr) & 0x1) 1847a4aa671eSarutz bp_mapin(bp); 1848a4aa671eSarutz 1849a4aa671eSarutz bp->b_flags &= ~(B_DONE|B_ERROR); 1850a4aa671eSarutz bp->b_resid = 0; 1851a4aa671eSarutz bp->av_forw = 0; 1852a4aa671eSarutz 1853a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1854a4aa671eSarutz "bp->b_bcount %lx\n", bp->b_bcount); 1855a4aa671eSarutz 1856a4aa671eSarutz if (bp != un->un_sbufp) { 1857a4aa671eSarutz validated: if (cmlb_partinfo(un->un_dklbhandle, 1858a4aa671eSarutz minor & DCDPART_MASK, 1859a4aa671eSarutz &lblocks, 1860a4aa671eSarutz &p_lblksrt, 1861a4aa671eSarutz NULL, 1862a4aa671eSarutz NULL, 1863a4aa671eSarutz 0) == 0) { 1864a4aa671eSarutz 1865a4aa671eSarutz bn = dkblock(bp); 1866a4aa671eSarutz 1867a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1868a4aa671eSarutz "dkblock(bp) is %llu\n", bn); 1869a4aa671eSarutz 1870a4aa671eSarutz i = 0; 1871a4aa671eSarutz if (bn < 0) { 1872a4aa671eSarutz i = -1; 1873a4aa671eSarutz } else if (bn >= lblocks) { 1874a4aa671eSarutz /* 1875a4aa671eSarutz * For proper comparison, file system block 1876a4aa671eSarutz * number has to be scaled to actual CD 1877a4aa671eSarutz * transfer size. 1878a4aa671eSarutz * Since all the CDROM operations 1879a4aa671eSarutz * that have Sun Labels are in the correct 1880a4aa671eSarutz * block size this will work for CD's. This 1881a4aa671eSarutz * will have to change when we have different 1882a4aa671eSarutz * sector sizes. 1883a4aa671eSarutz * 1884a4aa671eSarutz * if bn == lblocks, 1885a4aa671eSarutz * Not an error, resid == count 1886a4aa671eSarutz */ 1887a4aa671eSarutz if (bn > lblocks) { 1888a4aa671eSarutz i = -1; 1889a4aa671eSarutz } else { 1890a4aa671eSarutz i = 1; 1891a4aa671eSarutz } 1892a4aa671eSarutz } else if (bp->b_bcount & (un->un_secsize-1)) { 1893a4aa671eSarutz /* 1894a4aa671eSarutz * This should really be: 1895a4aa671eSarutz * 1896a4aa671eSarutz * ... if (bp->b_bcount & (un->un_lbasize-1)) 1897a4aa671eSarutz * 1898a4aa671eSarutz */ 1899a4aa671eSarutz i = -1; 1900a4aa671eSarutz } else { 1901a4aa671eSarutz if (!bp->b_bcount) { 1902a4aa671eSarutz printf("Waring : Zero read or Write\n"); 1903a4aa671eSarutz goto error; 1904a4aa671eSarutz } 1905a4aa671eSarutz /* 1906a4aa671eSarutz * sort by absolute block number. 1907a4aa671eSarutz */ 1908a4aa671eSarutz bp->b_resid = bn; 1909a4aa671eSarutz bp->b_resid += p_lblksrt; 1910a4aa671eSarutz /* 1911a4aa671eSarutz * zero out av_back - this will be a signal 1912a4aa671eSarutz * to dcdstart to go and fetch the resources 1913a4aa671eSarutz */ 1914a4aa671eSarutz bp->av_back = NO_PKT_ALLOCATED; 1915a4aa671eSarutz } 1916a4aa671eSarutz 1917a4aa671eSarutz /* 1918a4aa671eSarutz * Check to see whether or not we are done 1919a4aa671eSarutz * (with or without errors). 1920a4aa671eSarutz */ 1921a4aa671eSarutz 1922a4aa671eSarutz if (i != 0) { 1923a4aa671eSarutz if (i < 0) { 1924a4aa671eSarutz bp->b_flags |= B_ERROR; 1925a4aa671eSarutz } 1926a4aa671eSarutz goto error; 1927a4aa671eSarutz } 1928a4aa671eSarutz } else { 1929a4aa671eSarutz /* 1930a4aa671eSarutz * opened in NDELAY/NONBLOCK mode? 1931a4aa671eSarutz * Check if disk is ready and has a valid geometry 1932a4aa671eSarutz */ 1933a4aa671eSarutz if (dcd_ready_and_valid(bp->b_edev, un) == 0) { 1934a4aa671eSarutz goto validated; 1935a4aa671eSarutz } else { 1936a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 1937a4aa671eSarutz "i/o to invalid geometry\n"); 1938a4aa671eSarutz SET_BP_ERROR(bp, EIO); 1939a4aa671eSarutz goto error; 1940a4aa671eSarutz } 1941a4aa671eSarutz } 1942a4aa671eSarutz } else if (BP_HAS_NO_PKT(bp)) { 1943a4aa671eSarutz struct udcd_cmd *tscmdp; 1944a4aa671eSarutz struct dcd_cmd *tcmdp; 1945a4aa671eSarutz /* 1946a4aa671eSarutz * This indicates that it is a special buffer 1947a4aa671eSarutz * This could be a udcd-cmd and hence call bp_mapin just 1948a4aa671eSarutz * in case that it could be a PIO command issued. 1949a4aa671eSarutz */ 1950a4aa671eSarutz tscmdp = (struct udcd_cmd *)bp->b_forw; 1951a4aa671eSarutz tcmdp = tscmdp->udcd_cmd; 1952a4aa671eSarutz if ((tcmdp->cmd != ATA_READ_DMA) && (tcmdp->cmd != 0xc9) && 1953a4aa671eSarutz (tcmdp->cmd != ATA_WRITE_DMA) && (tcmdp->cmd != 0xcb) && 1954a4aa671eSarutz (tcmdp->cmd != IDENTIFY_DMA) && 1955a4aa671eSarutz (tcmdp->cmd != ATA_FLUSH_CACHE)) { 1956a4aa671eSarutz bp_mapin(bp); 1957a4aa671eSarutz } 1958a4aa671eSarutz } 1959a4aa671eSarutz 1960a4aa671eSarutz /* 1961a4aa671eSarutz * We are doing it a bit non-standard. That is, the 1962a4aa671eSarutz * head of the b_actf chain is *not* the active command- 1963a4aa671eSarutz * it is just the head of the wait queue. The reason 1964a4aa671eSarutz * we do this is that the head of the b_actf chain is 1965a4aa671eSarutz * guaranteed to not be moved by disksort(), so that 1966a4aa671eSarutz * our restart command (pointed to by 1967a4aa671eSarutz * b_forw) and the head of the wait queue (b_actf) can 1968a4aa671eSarutz * have resources granted without it getting lost in 1969a4aa671eSarutz * the queue at some later point (where we would have 1970a4aa671eSarutz * to go and look for it). 1971a4aa671eSarutz */ 1972a4aa671eSarutz mutex_enter(DCD_MUTEX); 1973a4aa671eSarutz 1974a4aa671eSarutz DCD_DO_KSTATS(un, kstat_waitq_enter, bp); 1975a4aa671eSarutz 1976a4aa671eSarutz dp = &un->un_utab; 1977a4aa671eSarutz 1978a4aa671eSarutz if (dp->b_actf == NULL) { 1979a4aa671eSarutz dp->b_actf = bp; 1980a4aa671eSarutz dp->b_actl = bp; 1981a4aa671eSarutz } else if ((un->un_state == DCD_STATE_SUSPENDED) && 1982a4aa671eSarutz bp == un->un_sbufp) { 1983a4aa671eSarutz bp->b_actf = dp->b_actf; 1984a4aa671eSarutz dp->b_actf = bp; 1985a4aa671eSarutz } else { 1986a4aa671eSarutz TRACE_3(TR_FAC_DADA, TR_DCDSTRATEGY_DISKSORT_START, 1987a4aa671eSarutz "dcdstrategy_disksort_start: dp 0x%p bp 0x%p un 0x%p", 1988a4aa671eSarutz dp, bp, un); 1989a4aa671eSarutz disksort(dp, bp); 1990a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDSTRATEGY_DISKSORT_END, 1991a4aa671eSarutz "dcdstrategy_disksort_end"); 1992a4aa671eSarutz } 1993a4aa671eSarutz 1994a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 1995a4aa671eSarutz "ncmd %x , throttle %x, forw 0x%p\n", 1996a4aa671eSarutz un->un_ncmds, un->un_throttle, (void *)dp->b_forw); 1997a4aa671eSarutz ASSERT(un->un_ncmds >= 0); 1998a4aa671eSarutz ASSERT(un->un_throttle >= 0); 1999a4aa671eSarutz if ((un->un_ncmds < un->un_throttle) && (dp->b_forw == NULL)) { 2000a4aa671eSarutz dcdstart(un); 2001a4aa671eSarutz } else if (BP_HAS_NO_PKT(dp->b_actf)) { 2002a4aa671eSarutz struct buf *cmd_bp; 2003a4aa671eSarutz 2004a4aa671eSarutz cmd_bp = dp->b_actf; 2005a4aa671eSarutz cmd_bp->av_back = ALLOCATING_PKT; 2006a4aa671eSarutz mutex_exit(DCD_MUTEX); 2007a4aa671eSarutz /* 2008a4aa671eSarutz * try and map this one 2009a4aa671eSarutz */ 2010a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDSTRATEGY_SMALL_WINDOW_START, 2011a4aa671eSarutz "dcdstrategy_small_window_call (begin)"); 2012a4aa671eSarutz 2013a4aa671eSarutz make_dcd_cmd(un, cmd_bp, NULL_FUNC); 2014a4aa671eSarutz 2015a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDSTRATEGY_SMALL_WINDOW_END, 2016a4aa671eSarutz "dcdstrategy_small_window_call (end)"); 2017a4aa671eSarutz 2018a4aa671eSarutz /* 2019a4aa671eSarutz * there is a small window where the active cmd 2020a4aa671eSarutz * completes before make_dcd_cmd returns. 2021a4aa671eSarutz * consequently, this cmd never gets started so 2022a4aa671eSarutz * we start it from here 2023a4aa671eSarutz */ 2024a4aa671eSarutz mutex_enter(DCD_MUTEX); 2025a4aa671eSarutz if ((un->un_ncmds < un->un_throttle) && 2026a4aa671eSarutz (dp->b_forw == NULL)) { 2027a4aa671eSarutz dcdstart(un); 2028a4aa671eSarutz } 2029a4aa671eSarutz } 2030a4aa671eSarutz mutex_exit(DCD_MUTEX); 2031a4aa671eSarutz 2032a4aa671eSarutz done: 2033a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDSTRATEGY_END, "dcdstrategy_end"); 2034a4aa671eSarutz return (0); 2035a4aa671eSarutz } 2036a4aa671eSarutz 2037a4aa671eSarutz 2038a4aa671eSarutz /* 2039a4aa671eSarutz * Unit start and Completion 2040a4aa671eSarutz * NOTE: we assume that the caller has at least checked for: 2041a4aa671eSarutz * (un->un_ncmds < un->un_throttle) 2042a4aa671eSarutz * if not, there is no real harm done, dcd_transport() will 2043a4aa671eSarutz * return BUSY 2044a4aa671eSarutz */ 2045a4aa671eSarutz static void 2046a4aa671eSarutz dcdstart(struct dcd_disk *un) 2047a4aa671eSarutz { 2048a4aa671eSarutz int status, sort_key; 2049a4aa671eSarutz struct buf *bp; 2050a4aa671eSarutz struct diskhd *dp; 2051a4aa671eSarutz uchar_t state = un->un_last_state; 2052a4aa671eSarutz 2053a4aa671eSarutz TRACE_1(TR_FAC_DADA, TR_DCDSTART_START, "dcdstart_start: un 0x%p", un); 2054a4aa671eSarutz 2055a4aa671eSarutz retry: 2056a4aa671eSarutz ASSERT(mutex_owned(DCD_MUTEX)); 2057a4aa671eSarutz 2058a4aa671eSarutz dp = &un->un_utab; 2059a4aa671eSarutz if (((bp = dp->b_actf) == NULL) || (bp->av_back == ALLOCATING_PKT) || 2060a4aa671eSarutz (dp->b_forw != NULL)) { 2061a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDSTART_NO_WORK_END, 2062a4aa671eSarutz "dcdstart_end (no work)"); 2063a4aa671eSarutz return; 2064a4aa671eSarutz } 2065a4aa671eSarutz 2066a4aa671eSarutz /* 2067a4aa671eSarutz * remove from active queue 2068a4aa671eSarutz */ 2069a4aa671eSarutz dp->b_actf = bp->b_actf; 2070a4aa671eSarutz bp->b_actf = 0; 2071a4aa671eSarutz 2072a4aa671eSarutz /* 2073a4aa671eSarutz * increment ncmds before calling dcd_transport because dcdintr 2074a4aa671eSarutz * may be called before we return from dcd_transport! 2075a4aa671eSarutz */ 2076a4aa671eSarutz un->un_ncmds++; 2077a4aa671eSarutz 2078a4aa671eSarutz /* 2079a4aa671eSarutz * If measuring stats, mark exit from wait queue and 2080a4aa671eSarutz * entrance into run 'queue' if and only if we are 2081a4aa671eSarutz * going to actually start a command. 2082a4aa671eSarutz * Normally the bp already has a packet at this point 2083a4aa671eSarutz */ 2084a4aa671eSarutz DCD_DO_KSTATS(un, kstat_waitq_to_runq, bp); 2085a4aa671eSarutz 2086a4aa671eSarutz mutex_exit(DCD_MUTEX); 2087a4aa671eSarutz 2088a4aa671eSarutz if (BP_HAS_NO_PKT(bp)) { 2089a4aa671eSarutz make_dcd_cmd(un, bp, dcdrunout); 2090a4aa671eSarutz if (BP_HAS_NO_PKT(bp) && !(bp->b_flags & B_ERROR)) { 2091a4aa671eSarutz mutex_enter(DCD_MUTEX); 2092a4aa671eSarutz DCD_DO_KSTATS(un, kstat_runq_back_to_waitq, bp); 2093a4aa671eSarutz 2094a4aa671eSarutz bp->b_actf = dp->b_actf; 2095a4aa671eSarutz dp->b_actf = bp; 2096a4aa671eSarutz New_state(un, DCD_STATE_RWAIT); 2097a4aa671eSarutz un->un_ncmds--; 2098a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDSTART_NO_RESOURCES_END, 2099a4aa671eSarutz "dcdstart_end (No Resources)"); 2100a4aa671eSarutz goto done; 2101a4aa671eSarutz 2102a4aa671eSarutz } else if (bp->b_flags & B_ERROR) { 2103a4aa671eSarutz mutex_enter(DCD_MUTEX); 2104a4aa671eSarutz DCD_DO_KSTATS(un, kstat_runq_exit, bp); 2105a4aa671eSarutz 2106a4aa671eSarutz un->un_ncmds--; 2107a4aa671eSarutz bp->b_resid = bp->b_bcount; 2108a4aa671eSarutz if (bp->b_error == 0) { 2109a4aa671eSarutz SET_BP_ERROR(bp, EIO); 2110a4aa671eSarutz } 2111a4aa671eSarutz 2112a4aa671eSarutz /* 2113a4aa671eSarutz * restore old state 2114a4aa671eSarutz */ 2115a4aa671eSarutz un->un_state = un->un_last_state; 2116a4aa671eSarutz un->un_last_state = state; 2117a4aa671eSarutz 2118a4aa671eSarutz mutex_exit(DCD_MUTEX); 2119a4aa671eSarutz 2120a4aa671eSarutz biodone(bp); 2121a4aa671eSarutz mutex_enter(DCD_MUTEX); 2122a4aa671eSarutz if (un->un_state == DCD_STATE_SUSPENDED) { 2123a4aa671eSarutz cv_broadcast(&un->un_disk_busy_cv); 2124a4aa671eSarutz } 2125a4aa671eSarutz 2126a4aa671eSarutz if ((un->un_ncmds < un->un_throttle) && 2127a4aa671eSarutz (dp->b_forw == NULL)) { 2128a4aa671eSarutz goto retry; 2129a4aa671eSarutz } else { 2130a4aa671eSarutz goto done; 2131a4aa671eSarutz } 2132a4aa671eSarutz } 2133a4aa671eSarutz } 2134a4aa671eSarutz 2135a4aa671eSarutz /* 2136a4aa671eSarutz * Restore resid from the packet, b_resid had been the 2137a4aa671eSarutz * disksort key. 2138a4aa671eSarutz */ 2139a4aa671eSarutz sort_key = bp->b_resid; 2140a4aa671eSarutz bp->b_resid = BP_PKT(bp)->pkt_resid; 2141a4aa671eSarutz BP_PKT(bp)->pkt_resid = 0; 2142a4aa671eSarutz 2143a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 2144a4aa671eSarutz "bp->b_resid %lx, pkt_resid %lx\n", 2145a4aa671eSarutz bp->b_resid, BP_PKT(bp)->pkt_resid); 2146a4aa671eSarutz 2147a4aa671eSarutz /* 2148a4aa671eSarutz * We used to check whether or not to try and link commands here. 2149a4aa671eSarutz * Since we have found that there is no performance improvement 2150a4aa671eSarutz * for linked commands, this has not made much sense. 2151a4aa671eSarutz */ 2152a4aa671eSarutz if ((status = dcd_transport((struct dcd_pkt *)BP_PKT(bp))) 2153a4aa671eSarutz != TRAN_ACCEPT) { 2154a4aa671eSarutz mutex_enter(DCD_MUTEX); 2155a4aa671eSarutz un->un_ncmds--; 2156a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 2157a4aa671eSarutz "transport returned %x\n", status); 2158a4aa671eSarutz if (status == TRAN_BUSY) { 2159a4aa671eSarutz DCD_DO_ERRSTATS(un, dcd_transerrs); 2160a4aa671eSarutz DCD_DO_KSTATS(un, kstat_runq_back_to_waitq, bp); 2161a4aa671eSarutz dcd_handle_tran_busy(bp, dp, un); 2162a4aa671eSarutz if (un->un_ncmds > 0) { 2163a4aa671eSarutz bp->b_resid = sort_key; 2164a4aa671eSarutz } 2165a4aa671eSarutz } else { 2166a4aa671eSarutz DCD_DO_KSTATS(un, kstat_runq_exit, bp); 2167a4aa671eSarutz mutex_exit(DCD_MUTEX); 2168a4aa671eSarutz 2169a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2170a4aa671eSarutz "transport rejected (%d)\n", 2171a4aa671eSarutz status); 2172a4aa671eSarutz SET_BP_ERROR(bp, EIO); 2173a4aa671eSarutz bp->b_resid = bp->b_bcount; 2174a4aa671eSarutz if (bp != un->un_sbufp) { 2175a4aa671eSarutz dcd_destroy_pkt(BP_PKT(bp)); 2176a4aa671eSarutz } 2177a4aa671eSarutz biodone(bp); 2178a4aa671eSarutz 2179a4aa671eSarutz mutex_enter(DCD_MUTEX); 2180a4aa671eSarutz if (un->un_state == DCD_STATE_SUSPENDED) { 2181a4aa671eSarutz cv_broadcast(&un->un_disk_busy_cv); 2182a4aa671eSarutz } 2183a4aa671eSarutz if ((un->un_ncmds < un->un_throttle) && 2184a4aa671eSarutz (dp->b_forw == NULL)) { 2185a4aa671eSarutz goto retry; 2186a4aa671eSarutz } 2187a4aa671eSarutz } 2188a4aa671eSarutz } else { 2189a4aa671eSarutz mutex_enter(DCD_MUTEX); 2190a4aa671eSarutz 2191a4aa671eSarutz if (dp->b_actf && BP_HAS_NO_PKT(dp->b_actf)) { 2192a4aa671eSarutz struct buf *cmd_bp; 2193a4aa671eSarutz 2194a4aa671eSarutz cmd_bp = dp->b_actf; 2195a4aa671eSarutz cmd_bp->av_back = ALLOCATING_PKT; 2196a4aa671eSarutz mutex_exit(DCD_MUTEX); 2197a4aa671eSarutz /* 2198a4aa671eSarutz * try and map this one 2199a4aa671eSarutz */ 2200a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCASTART_SMALL_WINDOW_START, 2201a4aa671eSarutz "dcdstart_small_window_start"); 2202a4aa671eSarutz 2203a4aa671eSarutz make_dcd_cmd(un, cmd_bp, NULL_FUNC); 2204a4aa671eSarutz 2205a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDSTART_SMALL_WINDOW_END, 2206a4aa671eSarutz "dcdstart_small_window_end"); 2207a4aa671eSarutz /* 2208a4aa671eSarutz * there is a small window where the active cmd 2209a4aa671eSarutz * completes before make_dcd_cmd returns. 2210a4aa671eSarutz * consequently, this cmd never gets started so 2211a4aa671eSarutz * we start it from here 2212a4aa671eSarutz */ 2213a4aa671eSarutz mutex_enter(DCD_MUTEX); 2214a4aa671eSarutz if ((un->un_ncmds < un->un_throttle) && 2215a4aa671eSarutz (dp->b_forw == NULL)) { 2216a4aa671eSarutz goto retry; 2217a4aa671eSarutz } 2218a4aa671eSarutz } 2219a4aa671eSarutz } 2220a4aa671eSarutz 2221a4aa671eSarutz done: 2222a4aa671eSarutz ASSERT(mutex_owned(DCD_MUTEX)); 2223a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDSTART_END, "dcdstart_end"); 2224a4aa671eSarutz } 2225a4aa671eSarutz 2226a4aa671eSarutz /* 2227a4aa671eSarutz * make_dcd_cmd: create a pkt 2228a4aa671eSarutz */ 2229a4aa671eSarutz static void 2230a4aa671eSarutz make_dcd_cmd(struct dcd_disk *un, struct buf *bp, int (*func)()) 2231a4aa671eSarutz { 2232a4aa671eSarutz auto int count, com, direction; 2233a4aa671eSarutz struct dcd_pkt *pkt; 2234a4aa671eSarutz int flags, tval; 2235a4aa671eSarutz 2236a4aa671eSarutz _NOTE(DATA_READABLE_WITHOUT_LOCK(dcd_disk::un_dp)) 2237a4aa671eSarutz TRACE_3(TR_FAC_DADA, TR_MAKE_DCD_CMD_START, 2238a4aa671eSarutz "make_dcd_cmd_start: un 0x%p bp 0x%p un 0x%p", un, bp, un); 2239a4aa671eSarutz 2240a4aa671eSarutz 2241a4aa671eSarutz flags = un->un_cmd_flags; 2242a4aa671eSarutz 2243a4aa671eSarutz if (bp != un->un_sbufp) { 2244a4aa671eSarutz int partition = DCDPART(bp->b_edev); 2245a4aa671eSarutz diskaddr_t p_lblksrt; 2246a4aa671eSarutz diskaddr_t lblocks; 2247a4aa671eSarutz long secnt; 2248a4aa671eSarutz uint32_t blkno; 2249a4aa671eSarutz int dkl_nblk, delta; 2250a4aa671eSarutz long resid; 2251a4aa671eSarutz 2252a4aa671eSarutz if (cmlb_partinfo(un->un_dklbhandle, 2253a4aa671eSarutz partition, 2254a4aa671eSarutz &lblocks, 2255a4aa671eSarutz &p_lblksrt, 2256a4aa671eSarutz NULL, 2257a4aa671eSarutz NULL, 2258a4aa671eSarutz 0) != NULL) { 2259a4aa671eSarutz lblocks = 0; 2260a4aa671eSarutz p_lblksrt = 0; 2261a4aa671eSarutz } 2262a4aa671eSarutz 2263a4aa671eSarutz dkl_nblk = (int)lblocks; 2264a4aa671eSarutz 2265a4aa671eSarutz /* 2266a4aa671eSarutz * Make sure we don't run off the end of a partition. 2267a4aa671eSarutz * 2268a4aa671eSarutz * Put this test here so that we can adjust b_count 2269a4aa671eSarutz * to accurately reflect the actual amount we are 2270a4aa671eSarutz * goint to transfer. 2271a4aa671eSarutz */ 2272a4aa671eSarutz 2273a4aa671eSarutz /* 2274a4aa671eSarutz * First, compute partition-relative block number 2275a4aa671eSarutz */ 2276a4aa671eSarutz blkno = dkblock(bp); 2277a4aa671eSarutz secnt = (bp->b_bcount + (un->un_secsize - 1)) >> un->un_secdiv; 2278a4aa671eSarutz count = MIN(secnt, dkl_nblk - blkno); 2279a4aa671eSarutz if (count != secnt) { 2280a4aa671eSarutz /* 2281a4aa671eSarutz * We have an overrun 2282a4aa671eSarutz */ 2283a4aa671eSarutz resid = (secnt - count) << un->un_secdiv; 2284a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 2285a4aa671eSarutz "overrun by %ld sectors\n", 2286a4aa671eSarutz secnt - count); 2287a4aa671eSarutz bp->b_bcount -= resid; 2288a4aa671eSarutz } else { 2289a4aa671eSarutz resid = 0; 2290a4aa671eSarutz } 2291a4aa671eSarutz 2292a4aa671eSarutz /* 2293a4aa671eSarutz * Adjust block number to absolute 2294a4aa671eSarutz */ 2295a4aa671eSarutz delta = (int)p_lblksrt; 2296a4aa671eSarutz blkno += delta; 2297a4aa671eSarutz 2298a4aa671eSarutz mutex_enter(DCD_MUTEX); 2299a4aa671eSarutz /* 2300a4aa671eSarutz * This is for devices having block size different from 2301a4aa671eSarutz * from DEV_BSIZE (e.g. 2K CDROMs). 2302a4aa671eSarutz */ 2303a4aa671eSarutz if (un->un_lbasize != un->un_secsize) { 2304a4aa671eSarutz blkno >>= un->un_blknoshift; 2305a4aa671eSarutz count >>= un->un_blknoshift; 2306a4aa671eSarutz } 2307a4aa671eSarutz mutex_exit(DCD_MUTEX); 2308a4aa671eSarutz 2309a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_MAKE_DCD_CMD_INIT_PKT_START, 2310a4aa671eSarutz "make_dcd_cmd_init_pkt_call (begin)"); 2311a4aa671eSarutz pkt = dcd_init_pkt(ROUTE, NULL, bp, 2312a4aa671eSarutz (uint32_t)sizeof (struct dcd_cmd), 2313a4aa671eSarutz un->un_cmd_stat_size, PP_LEN, PKT_CONSISTENT, 2314a4aa671eSarutz func, (caddr_t)un); 2315a4aa671eSarutz TRACE_1(TR_FAC_DADA, TR_MAKE_DCD_CMD_INIT_PKT_END, 2316a4aa671eSarutz "make_dcd_cmd_init_pkt_call (end): pkt 0x%p", pkt); 2317a4aa671eSarutz if (!pkt) { 2318a4aa671eSarutz bp->b_bcount += resid; 2319a4aa671eSarutz bp->av_back = NO_PKT_ALLOCATED; 2320a4aa671eSarutz TRACE_0(TR_FAC_DADA, 2321a4aa671eSarutz TR_MAKE_DCD_CMD_NO_PKT_ALLOCATED1_END, 2322a4aa671eSarutz "make_dcd_cmd_end (NO_PKT_ALLOCATED1)"); 2323a4aa671eSarutz return; 2324a4aa671eSarutz } 2325a4aa671eSarutz if (bp->b_flags & B_READ) { 2326a4aa671eSarutz if ((un->un_dp->options & DMA_SUPPORTTED) == 2327a4aa671eSarutz DMA_SUPPORTTED) { 2328a4aa671eSarutz com = ATA_READ_DMA; 2329a4aa671eSarutz } else { 2330a4aa671eSarutz if (un->un_dp->options & BLOCK_MODE) 2331a4aa671eSarutz com = ATA_READ_MULTIPLE; 2332a4aa671eSarutz else 2333a4aa671eSarutz com = ATA_READ; 2334a4aa671eSarutz } 2335a4aa671eSarutz direction = DATA_READ; 2336a4aa671eSarutz } else { 2337a4aa671eSarutz if ((un->un_dp->options & DMA_SUPPORTTED) == 2338a4aa671eSarutz DMA_SUPPORTTED) { 2339a4aa671eSarutz com = ATA_WRITE_DMA; 2340a4aa671eSarutz } else { 2341a4aa671eSarutz if (un->un_dp->options & BLOCK_MODE) 2342a4aa671eSarutz com = ATA_WRITE_MULTIPLE; 2343a4aa671eSarutz else 2344a4aa671eSarutz com = ATA_WRITE; 2345a4aa671eSarutz } 2346a4aa671eSarutz direction = DATA_WRITE; 2347a4aa671eSarutz } 2348a4aa671eSarutz 2349a4aa671eSarutz /* 2350a4aa671eSarutz * Save the resid in the packet, temporarily until 2351a4aa671eSarutz * we transport the command. 2352a4aa671eSarutz */ 2353a4aa671eSarutz pkt->pkt_resid = resid; 2354a4aa671eSarutz 2355a4aa671eSarutz makecommand(pkt, flags, com, blkno, ADD_LBA_MODE, 2356a4aa671eSarutz bp->b_bcount, direction, 0); 2357a4aa671eSarutz tval = dcd_io_time; 2358a4aa671eSarutz } else { 2359a4aa671eSarutz 2360a4aa671eSarutz struct udcd_cmd *scmd = (struct udcd_cmd *)bp->b_forw; 2361a4aa671eSarutz 2362a4aa671eSarutz /* 2363a4aa671eSarutz * set options 2364a4aa671eSarutz */ 2365a4aa671eSarutz if ((scmd->udcd_flags & UDCD_SILENT) && !(DEBUGGING)) { 2366a4aa671eSarutz flags |= FLAG_SILENT; 2367a4aa671eSarutz } 2368a4aa671eSarutz if (scmd->udcd_flags & UDCD_DIAGNOSE) 2369a4aa671eSarutz flags |= FLAG_DIAGNOSE; 2370a4aa671eSarutz 2371a4aa671eSarutz if (scmd->udcd_flags & UDCD_NOINTR) 2372a4aa671eSarutz flags |= FLAG_NOINTR; 2373a4aa671eSarutz 2374a4aa671eSarutz pkt = dcd_init_pkt(ROUTE, (struct dcd_pkt *)NULL, 2375a4aa671eSarutz (bp->b_bcount)? bp: NULL, 2376a4aa671eSarutz (uint32_t)sizeof (struct dcd_cmd), 2377a4aa671eSarutz 2, PP_LEN, PKT_CONSISTENT, func, (caddr_t)un); 2378a4aa671eSarutz 2379a4aa671eSarutz if (!pkt) { 2380a4aa671eSarutz bp->av_back = NO_PKT_ALLOCATED; 2381a4aa671eSarutz return; 2382a4aa671eSarutz } 2383a4aa671eSarutz 2384a4aa671eSarutz makecommand(pkt, 0, scmd->udcd_cmd->cmd, 2385a4aa671eSarutz scmd->udcd_cmd->sector_num.lba_num, 2386a4aa671eSarutz scmd->udcd_cmd->address_mode, 2387a4aa671eSarutz scmd->udcd_cmd->size, 2388a4aa671eSarutz scmd->udcd_cmd->direction, scmd->udcd_cmd->features); 2389a4aa671eSarutz 2390a4aa671eSarutz pkt->pkt_flags = flags; 2391a4aa671eSarutz if (scmd->udcd_timeout == 0) 2392a4aa671eSarutz tval = dcd_io_time; 2393a4aa671eSarutz else 2394a4aa671eSarutz tval = scmd->udcd_timeout; 2395a4aa671eSarutz /* UDAD interface should be decided. */ 2396a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 2397a4aa671eSarutz "udcd interface\n"); 2398a4aa671eSarutz } 2399a4aa671eSarutz 2400a4aa671eSarutz pkt->pkt_comp = dcdintr; 2401a4aa671eSarutz pkt->pkt_time = tval; 2402a4aa671eSarutz PKT_SET_BP(pkt, bp); 2403a4aa671eSarutz bp->av_back = (struct buf *)pkt; 2404a4aa671eSarutz 2405a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_MAKE_DCD_CMD_END, "make_dcd_cmd_end"); 2406a4aa671eSarutz } 2407a4aa671eSarutz 2408a4aa671eSarutz /* 2409a4aa671eSarutz * Command completion processing 2410a4aa671eSarutz */ 2411a4aa671eSarutz static void 2412a4aa671eSarutz dcdintr(struct dcd_pkt *pkt) 2413a4aa671eSarutz { 2414a4aa671eSarutz struct dcd_disk *un; 2415a4aa671eSarutz struct buf *bp; 2416a4aa671eSarutz int action; 2417a4aa671eSarutz int status; 2418a4aa671eSarutz 2419a4aa671eSarutz bp = PKT_GET_BP(pkt); 2420a4aa671eSarutz un = ddi_get_soft_state(dcd_state, DCDUNIT(bp->b_edev)); 2421a4aa671eSarutz 2422a4aa671eSarutz TRACE_1(TR_FAC_DADA, TR_DCDINTR_START, "dcdintr_start: un 0x%p", un); 2423a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdintr\n"); 2424a4aa671eSarutz 2425a4aa671eSarutz mutex_enter(DCD_MUTEX); 2426a4aa671eSarutz un->un_ncmds--; 2427a4aa671eSarutz DCD_DO_KSTATS(un, kstat_runq_exit, bp); 2428a4aa671eSarutz ASSERT(un->un_ncmds >= 0); 2429a4aa671eSarutz 2430a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 2431a4aa671eSarutz "reason %x and Status %x\n", pkt->pkt_reason, SCBP_C(pkt)); 2432a4aa671eSarutz 2433a4aa671eSarutz /* 2434a4aa671eSarutz * do most common case first 2435a4aa671eSarutz */ 2436a4aa671eSarutz if ((pkt->pkt_reason == CMD_CMPLT) && (SCBP_C(pkt) == 0)) { 2437a4aa671eSarutz int com = GETATACMD((struct dcd_cmd *)pkt->pkt_cdbp); 2438a4aa671eSarutz 2439a4aa671eSarutz if (un->un_state == DCD_STATE_OFFLINE) { 2440a4aa671eSarutz un->un_state = un->un_last_state; 2441a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_NOTE, 2442a4aa671eSarutz (const char *) diskokay); 2443a4aa671eSarutz } 2444a4aa671eSarutz /* 2445a4aa671eSarutz * If the command is a read or a write, and we have 2446a4aa671eSarutz * a non-zero pkt_resid, that is an error. We should 2447a4aa671eSarutz * attempt to retry the operation if possible. 2448a4aa671eSarutz */ 2449a4aa671eSarutz action = COMMAND_DONE; 2450a4aa671eSarutz if (pkt->pkt_resid && (com == ATA_READ || com == ATA_WRITE)) { 2451a4aa671eSarutz DCD_DO_ERRSTATS(un, dcd_harderrs); 2452a4aa671eSarutz if ((int)PKT_GET_RETRY_CNT(pkt) < dcd_retry_count) { 2453a4aa671eSarutz PKT_INCR_RETRY_CNT(pkt, 1); 2454a4aa671eSarutz action = QUE_COMMAND; 2455a4aa671eSarutz } else { 2456a4aa671eSarutz /* 2457a4aa671eSarutz * if we have exhausted retries 2458a4aa671eSarutz * a command with a residual is in error in 2459a4aa671eSarutz * this case. 2460a4aa671eSarutz */ 2461a4aa671eSarutz action = COMMAND_DONE_ERROR; 2462a4aa671eSarutz } 2463a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, 2464a4aa671eSarutz CE_WARN, "incomplete %s- %s\n", 2465a4aa671eSarutz (bp->b_flags & B_READ)? "read" : "write", 2466a4aa671eSarutz (action == QUE_COMMAND)? "retrying" : 2467a4aa671eSarutz "giving up"); 2468a4aa671eSarutz } 2469a4aa671eSarutz 2470a4aa671eSarutz /* 2471a4aa671eSarutz * pkt_resid will reflect, at this point, a residual 2472a4aa671eSarutz * of how many bytes left to be transferred there were 2473a4aa671eSarutz * from the actual scsi command. Add this to b_resid i.e 2474a4aa671eSarutz * the amount this driver could not see to transfer, 2475a4aa671eSarutz * to get the total number of bytes not transfered. 2476a4aa671eSarutz */ 2477a4aa671eSarutz if (action != QUE_COMMAND) { 2478a4aa671eSarutz bp->b_resid += pkt->pkt_resid; 2479a4aa671eSarutz } 2480a4aa671eSarutz 2481a4aa671eSarutz } else if (pkt->pkt_reason != CMD_CMPLT) { 2482a4aa671eSarutz action = dcd_handle_incomplete(un, bp); 2483a4aa671eSarutz } 2484a4aa671eSarutz 2485a4aa671eSarutz /* 2486a4aa671eSarutz * If we are in the middle of syncing or dumping, we have got 2487a4aa671eSarutz * here because dcd_transport has called us explictly after 2488a4aa671eSarutz * completing the command in a polled mode. We don't want to 2489a4aa671eSarutz * have a recursive call into dcd_transport again. 2490a4aa671eSarutz */ 2491a4aa671eSarutz if (ddi_in_panic() && (action == QUE_COMMAND)) { 2492a4aa671eSarutz action = COMMAND_DONE_ERROR; 2493a4aa671eSarutz } 2494a4aa671eSarutz 2495a4aa671eSarutz /* 2496a4aa671eSarutz * save pkt reason; consecutive failures are not reported unless 2497a4aa671eSarutz * fatal 2498a4aa671eSarutz * do not reset last_pkt_reason when the cmd was retried and 2499a4aa671eSarutz * succeeded because 2500a4aa671eSarutz * there maybe more commands comming back with last_pkt_reason 2501a4aa671eSarutz */ 2502a4aa671eSarutz if ((un->un_last_pkt_reason != pkt->pkt_reason) && 2503a4aa671eSarutz ((pkt->pkt_reason != CMD_CMPLT) || 2504a4aa671eSarutz (PKT_GET_RETRY_CNT(pkt) == 0))) { 2505a4aa671eSarutz un->un_last_pkt_reason = pkt->pkt_reason; 2506a4aa671eSarutz } 2507a4aa671eSarutz 2508a4aa671eSarutz switch (action) { 2509a4aa671eSarutz case COMMAND_DONE_ERROR: 2510a4aa671eSarutz error: 2511a4aa671eSarutz if (bp->b_resid == 0) { 2512a4aa671eSarutz bp->b_resid = bp->b_bcount; 2513a4aa671eSarutz } 2514a4aa671eSarutz if (bp->b_error == 0) { 2515a4aa671eSarutz struct dcd_cmd *cdbp = (struct dcd_cmd *)pkt->pkt_cdbp; 2516a4aa671eSarutz if (cdbp->cmd == ATA_FLUSH_CACHE && 2517a4aa671eSarutz (pkt->pkt_scbp[0] & STATUS_ATA_ERR) && 2518a4aa671eSarutz (pkt->pkt_scbp[1] & ERR_ABORT)) { 2519a4aa671eSarutz SET_BP_ERROR(bp, ENOTSUP); 2520a4aa671eSarutz un->un_flush_not_supported = 1; 2521a4aa671eSarutz } else { 2522a4aa671eSarutz SET_BP_ERROR(bp, EIO); 2523a4aa671eSarutz } 2524a4aa671eSarutz } 2525a4aa671eSarutz bp->b_flags |= B_ERROR; 2526a4aa671eSarutz /*FALLTHROUGH*/ 2527a4aa671eSarutz case COMMAND_DONE: 2528a4aa671eSarutz dcddone_and_mutex_exit(un, bp); 2529a4aa671eSarutz 2530a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDINTR_COMMAND_DONE_END, 2531a4aa671eSarutz "dcdintr_end (COMMAND_DONE)"); 2532a4aa671eSarutz return; 2533a4aa671eSarutz 2534a4aa671eSarutz case QUE_COMMAND: 2535a4aa671eSarutz if (un->un_ncmds >= un->un_throttle) { 2536a4aa671eSarutz struct diskhd *dp = &un->un_utab; 2537a4aa671eSarutz 2538a4aa671eSarutz bp->b_actf = dp->b_actf; 2539a4aa671eSarutz dp->b_actf = bp; 2540a4aa671eSarutz 2541a4aa671eSarutz DCD_DO_KSTATS(un, kstat_waitq_enter, bp); 2542a4aa671eSarutz 2543a4aa671eSarutz mutex_exit(DCD_MUTEX); 2544a4aa671eSarutz goto exit; 2545a4aa671eSarutz } 2546a4aa671eSarutz 2547a4aa671eSarutz un->un_ncmds++; 2548a4aa671eSarutz /* reset the pkt reason again */ 2549a4aa671eSarutz pkt->pkt_reason = 0; 2550a4aa671eSarutz DCD_DO_KSTATS(un, kstat_runq_enter, bp); 2551a4aa671eSarutz mutex_exit(DCD_MUTEX); 2552a4aa671eSarutz if ((status = dcd_transport(BP_PKT(bp))) != TRAN_ACCEPT) { 2553a4aa671eSarutz struct diskhd *dp = &un->un_utab; 2554a4aa671eSarutz 2555a4aa671eSarutz mutex_enter(DCD_MUTEX); 2556a4aa671eSarutz un->un_ncmds--; 2557a4aa671eSarutz if (status == TRAN_BUSY) { 2558a4aa671eSarutz DCD_DO_KSTATS(un, kstat_runq_back_to_waitq, bp); 2559a4aa671eSarutz dcd_handle_tran_busy(bp, dp, un); 2560a4aa671eSarutz mutex_exit(DCD_MUTEX); 2561a4aa671eSarutz goto exit; 2562a4aa671eSarutz } 2563a4aa671eSarutz DCD_DO_ERRSTATS(un, dcd_transerrs); 2564a4aa671eSarutz DCD_DO_KSTATS(un, kstat_runq_exit, bp); 2565a4aa671eSarutz 2566a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2567a4aa671eSarutz "requeue of command fails (%x)\n", status); 2568a4aa671eSarutz SET_BP_ERROR(bp, EIO); 2569a4aa671eSarutz bp->b_resid = bp->b_bcount; 2570a4aa671eSarutz 2571a4aa671eSarutz dcddone_and_mutex_exit(un, bp); 2572a4aa671eSarutz goto exit; 2573a4aa671eSarutz } 2574a4aa671eSarutz break; 2575a4aa671eSarutz 2576a4aa671eSarutz case JUST_RETURN: 2577a4aa671eSarutz default: 2578a4aa671eSarutz DCD_DO_KSTATS(un, kstat_waitq_enter, bp); 2579a4aa671eSarutz mutex_exit(DCD_MUTEX); 2580a4aa671eSarutz break; 2581a4aa671eSarutz } 2582a4aa671eSarutz 2583a4aa671eSarutz exit: 2584a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDINTR_END, "dcdintr_end"); 2585a4aa671eSarutz } 2586a4aa671eSarutz 2587a4aa671eSarutz 2588a4aa671eSarutz /* 2589a4aa671eSarutz * Done with a command. 2590a4aa671eSarutz */ 2591a4aa671eSarutz static void 2592a4aa671eSarutz dcddone_and_mutex_exit(struct dcd_disk *un, register struct buf *bp) 2593a4aa671eSarutz { 2594a4aa671eSarutz struct diskhd *dp; 2595a4aa671eSarutz 2596a4aa671eSarutz TRACE_1(TR_FAC_DADA, TR_DCDONE_START, "dcddone_start: un 0x%p", un); 2597a4aa671eSarutz 2598a4aa671eSarutz _NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(&un->un_dcd->dcd_mutex)); 2599a4aa671eSarutz 2600a4aa671eSarutz dp = &un->un_utab; 2601a4aa671eSarutz if (bp == dp->b_forw) { 2602a4aa671eSarutz dp->b_forw = NULL; 2603a4aa671eSarutz } 2604a4aa671eSarutz 2605a4aa671eSarutz if (un->un_stats) { 2606a4aa671eSarutz ulong_t n_done = bp->b_bcount - bp->b_resid; 2607a4aa671eSarutz if (bp->b_flags & B_READ) { 2608a4aa671eSarutz IOSP->reads++; 2609a4aa671eSarutz IOSP->nread += n_done; 2610a4aa671eSarutz } else { 2611a4aa671eSarutz IOSP->writes++; 2612a4aa671eSarutz IOSP->nwritten += n_done; 2613a4aa671eSarutz } 2614a4aa671eSarutz } 2615a4aa671eSarutz if (IO_PARTITION_STATS) { 2616a4aa671eSarutz ulong_t n_done = bp->b_bcount - bp->b_resid; 2617a4aa671eSarutz if (bp->b_flags & B_READ) { 2618a4aa671eSarutz IOSP_PARTITION->reads++; 2619a4aa671eSarutz IOSP_PARTITION->nread += n_done; 2620a4aa671eSarutz } else { 2621a4aa671eSarutz IOSP_PARTITION->writes++; 2622a4aa671eSarutz IOSP_PARTITION->nwritten += n_done; 2623a4aa671eSarutz } 2624a4aa671eSarutz } 2625a4aa671eSarutz 2626a4aa671eSarutz /* 2627a4aa671eSarutz * Start the next one before releasing resources on this one 2628a4aa671eSarutz */ 2629a4aa671eSarutz if (un->un_state == DCD_STATE_SUSPENDED) { 2630a4aa671eSarutz cv_broadcast(&un->un_disk_busy_cv); 2631a4aa671eSarutz } else if (dp->b_actf && (un->un_ncmds < un->un_throttle) && 2632a4aa671eSarutz (dp->b_forw == NULL && un->un_state != DCD_STATE_SUSPENDED)) { 2633a4aa671eSarutz dcdstart(un); 2634a4aa671eSarutz } 2635a4aa671eSarutz 2636a4aa671eSarutz mutex_exit(DCD_MUTEX); 2637a4aa671eSarutz 2638a4aa671eSarutz if (bp != un->un_sbufp) { 2639a4aa671eSarutz dcd_destroy_pkt(BP_PKT(bp)); 2640a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 2641a4aa671eSarutz "regular done: resid %ld\n", bp->b_resid); 2642a4aa671eSarutz } else { 2643a4aa671eSarutz ASSERT(un->un_sbuf_busy); 2644a4aa671eSarutz } 2645a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDDONE_BIODONE_CALL, "dcddone_biodone_call"); 2646a4aa671eSarutz 2647a4aa671eSarutz biodone(bp); 2648a4aa671eSarutz 2649a4aa671eSarutz (void) pm_idle_component(DCD_DEVINFO, 0); 2650a4aa671eSarutz 2651a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCDDONE_END, "dcddone end"); 2652a4aa671eSarutz } 2653a4aa671eSarutz 2654a4aa671eSarutz 2655a4aa671eSarutz /* 2656a4aa671eSarutz * reset the disk unless the transport layer has already 2657a4aa671eSarutz * cleared the problem 2658a4aa671eSarutz */ 2659a4aa671eSarutz #define C1 (STAT_ATA_BUS_RESET|STAT_ATA_DEV_RESET|STAT_ATA_ABORTED) 2660a4aa671eSarutz static void 2661a4aa671eSarutz dcd_reset_disk(struct dcd_disk *un, struct dcd_pkt *pkt) 2662a4aa671eSarutz { 2663a4aa671eSarutz 2664a4aa671eSarutz if ((pkt->pkt_statistics & C1) == 0) { 2665a4aa671eSarutz mutex_exit(DCD_MUTEX); 2666a4aa671eSarutz if (!dcd_reset(ROUTE, RESET_ALL)) { 2667a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 2668a4aa671eSarutz "Reset failed"); 2669a4aa671eSarutz } 2670a4aa671eSarutz mutex_enter(DCD_MUTEX); 2671a4aa671eSarutz } 2672a4aa671eSarutz } 2673a4aa671eSarutz 2674a4aa671eSarutz static int 2675a4aa671eSarutz dcd_handle_incomplete(struct dcd_disk *un, struct buf *bp) 2676a4aa671eSarutz { 2677a4aa671eSarutz static char *fail = "ATA transport failed: reason '%s': %s\n"; 2678a4aa671eSarutz static char *notresp = "disk not responding to selection\n"; 2679a4aa671eSarutz int rval = COMMAND_DONE_ERROR; 2680a4aa671eSarutz int action = COMMAND_SOFT_ERROR; 2681a4aa671eSarutz struct dcd_pkt *pkt = BP_PKT(bp); 2682a4aa671eSarutz int be_chatty = (un->un_state != DCD_STATE_SUSPENDED) && 2683a4aa671eSarutz (bp != un->un_sbufp || !(pkt->pkt_flags & FLAG_SILENT)); 2684a4aa671eSarutz 2685a4aa671eSarutz ASSERT(mutex_owned(DCD_MUTEX)); 2686a4aa671eSarutz 2687a4aa671eSarutz switch (pkt->pkt_reason) { 2688a4aa671eSarutz 2689a4aa671eSarutz case CMD_TIMEOUT: 2690a4aa671eSarutz /* 2691a4aa671eSarutz * This Indicates the already the HBA would have reset 2692a4aa671eSarutz * so Just indicate to retry the command 2693a4aa671eSarutz */ 2694a4aa671eSarutz break; 2695a4aa671eSarutz 2696a4aa671eSarutz case CMD_INCOMPLETE: 2697a4aa671eSarutz action = dcd_check_error(un, bp); 2698a4aa671eSarutz DCD_DO_ERRSTATS(un, dcd_transerrs); 26992900c43aSkc28005 if (action == COMMAND_HARD_ERROR) { 2700a4aa671eSarutz (void) dcd_reset_disk(un, pkt); 27012900c43aSkc28005 } 2702a4aa671eSarutz break; 2703a4aa671eSarutz 2704a4aa671eSarutz case CMD_FATAL: 2705a4aa671eSarutz /* 2706a4aa671eSarutz * Something drastic has gone wrong 2707a4aa671eSarutz */ 2708a4aa671eSarutz break; 2709a4aa671eSarutz case CMD_DMA_DERR: 2710a4aa671eSarutz case CMD_DATA_OVR: 2711a4aa671eSarutz /* FALLTHROUGH */ 2712a4aa671eSarutz 2713a4aa671eSarutz default: 2714a4aa671eSarutz /* 2715a4aa671eSarutz * the target may still be running the command, 2716a4aa671eSarutz * so we should try and reset that target. 2717a4aa671eSarutz */ 2718a4aa671eSarutz DCD_DO_ERRSTATS(un, dcd_transerrs); 2719a4aa671eSarutz if ((pkt->pkt_reason != CMD_RESET) && 2720a4aa671eSarutz (pkt->pkt_reason != CMD_ABORTED)) { 2721a4aa671eSarutz (void) dcd_reset_disk(un, pkt); 2722a4aa671eSarutz } 2723a4aa671eSarutz break; 2724a4aa671eSarutz } 2725a4aa671eSarutz 2726a4aa671eSarutz /* 2727a4aa671eSarutz * If pkt_reason is CMD_RESET/ABORTED, chances are that this pkt got 2728a4aa671eSarutz * reset/aborted because another disk on this bus caused it. 2729a4aa671eSarutz * The disk that caused it, should get CMD_TIMEOUT with pkt_statistics 2730a4aa671eSarutz * of STAT_TIMEOUT/STAT_DEV_RESET 2731a4aa671eSarutz */ 2732a4aa671eSarutz if ((pkt->pkt_reason == CMD_RESET) ||(pkt->pkt_reason == CMD_ABORTED)) { 2733a4aa671eSarutz /* To be written : XXX */ 2734a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 2735a4aa671eSarutz "Command aborted\n"); 2736a4aa671eSarutz } 2737a4aa671eSarutz 2738a4aa671eSarutz if (bp == un->un_sbufp && (pkt->pkt_flags & FLAG_DIAGNOSE)) { 2739a4aa671eSarutz rval = COMMAND_DONE_ERROR; 2740a4aa671eSarutz } else { 2741a4aa671eSarutz if ((rval == COMMAND_DONE_ERROR) && 2742a4aa671eSarutz (action == COMMAND_SOFT_ERROR) && 2743a4aa671eSarutz ((int)PKT_GET_RETRY_CNT(pkt) < dcd_retry_count)) { 2744a4aa671eSarutz PKT_INCR_RETRY_CNT(pkt, 1); 2745a4aa671eSarutz rval = QUE_COMMAND; 2746a4aa671eSarutz } 2747a4aa671eSarutz } 2748a4aa671eSarutz 2749a4aa671eSarutz if (pkt->pkt_reason == CMD_INCOMPLETE && rval == COMMAND_DONE_ERROR) { 2750a4aa671eSarutz /* 2751a4aa671eSarutz * Looks like someone turned off this shoebox. 2752a4aa671eSarutz */ 2753a4aa671eSarutz if (un->un_state != DCD_STATE_OFFLINE) { 2754a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2755a4aa671eSarutz (const char *) notresp); 2756a4aa671eSarutz New_state(un, DCD_STATE_OFFLINE); 2757a4aa671eSarutz } 2758a4aa671eSarutz } else if (pkt->pkt_reason == CMD_FATAL) { 2759a4aa671eSarutz /* 2760a4aa671eSarutz * Suppressing the following message for the time being 2761a4aa671eSarutz * dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2762a4aa671eSarutz * (const char *) notresp); 2763a4aa671eSarutz */ 2764a4aa671eSarutz PKT_INCR_RETRY_CNT(pkt, 6); 2765a4aa671eSarutz rval = COMMAND_DONE_ERROR; 2766a4aa671eSarutz New_state(un, DCD_STATE_FATAL); 2767a4aa671eSarutz } else if (be_chatty) { 2768a4aa671eSarutz int in_panic = ddi_in_panic(); 2769a4aa671eSarutz if (!in_panic || (rval == COMMAND_DONE_ERROR)) { 2770a4aa671eSarutz if (((pkt->pkt_reason != un->un_last_pkt_reason) && 2771a4aa671eSarutz (pkt->pkt_reason != CMD_RESET)) || 2772a4aa671eSarutz (rval == COMMAND_DONE_ERROR) || 2773a4aa671eSarutz (dcd_error_level == DCD_ERR_ALL)) { 2774a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2775a4aa671eSarutz fail, dcd_rname(pkt->pkt_reason), 2776a4aa671eSarutz (rval == COMMAND_DONE_ERROR) ? 2777a4aa671eSarutz "giving up": "retrying command"); 2778a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 2779a4aa671eSarutz "retrycount=%x\n", 2780a4aa671eSarutz PKT_GET_RETRY_CNT(pkt)); 2781a4aa671eSarutz } 2782a4aa671eSarutz } 2783a4aa671eSarutz } 2784a4aa671eSarutz error: 2785a4aa671eSarutz return (rval); 2786a4aa671eSarutz } 2787a4aa671eSarutz 2788a4aa671eSarutz static int 2789a4aa671eSarutz dcd_check_error(struct dcd_disk *un, struct buf *bp) 2790a4aa671eSarutz { 2791a4aa671eSarutz struct diskhd *dp = &un->un_utab; 2792a4aa671eSarutz struct dcd_pkt *pkt = BP_PKT(bp); 2793a4aa671eSarutz int rval = 0; 2794a4aa671eSarutz unsigned char status; 2795a4aa671eSarutz unsigned char error; 2796a4aa671eSarutz 2797a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCD_CHECK_ERROR_START, "dcd_check_error_start"); 2798a4aa671eSarutz ASSERT(mutex_owned(DCD_MUTEX)); 2799a4aa671eSarutz 2800a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 2801a4aa671eSarutz "Pkt: 0x%p dp: 0x%p\n", (void *)pkt, (void *)dp); 2802a4aa671eSarutz 2803a4aa671eSarutz /* 2804a4aa671eSarutz * Here we need to check status first and then if error is indicated 2805a4aa671eSarutz * Then the error register. 2806a4aa671eSarutz */ 2807a4aa671eSarutz 2808a4aa671eSarutz status = (pkt->pkt_scbp)[0]; 2809a4aa671eSarutz if ((status & STATUS_ATA_DWF) == STATUS_ATA_DWF) { 2810a4aa671eSarutz /* 2811a4aa671eSarutz * There has been a Device Fault - reason for such error 2812a4aa671eSarutz * is vendor specific 2813a4aa671eSarutz * Action to be taken is - Indicate error and reset device. 2814a4aa671eSarutz */ 2815a4aa671eSarutz 2816a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, "Device Fault\n"); 2817a4aa671eSarutz rval = COMMAND_HARD_ERROR; 2818a4aa671eSarutz } else if ((status & STATUS_ATA_CORR) == STATUS_ATA_CORR) { 2819a4aa671eSarutz 2820a4aa671eSarutz /* 2821a4aa671eSarutz * The sector read or written is marginal and hence ECC 2822a4aa671eSarutz * Correction has been applied. Indicate to repair 2823a4aa671eSarutz * Here we need to probably re-assign based on the badblock 2824a4aa671eSarutz * mapping. 2825a4aa671eSarutz */ 2826a4aa671eSarutz 2827a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2828a4aa671eSarutz "Soft Error on block %x\n", 2829a4aa671eSarutz ((struct dcd_cmd *)pkt->pkt_cdbp)->sector_num.lba_num); 2830a4aa671eSarutz rval = COMMAND_SOFT_ERROR; 2831a4aa671eSarutz } else if ((status & STATUS_ATA_ERR) == STATUS_ATA_ERR) { 2832a4aa671eSarutz error = pkt->pkt_scbp[1]; 2833a4aa671eSarutz 2834a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2835a4aa671eSarutz "Command:0x%x,Error:0x%x,Status:0x%x\n", 2836a4aa671eSarutz GETATACMD((struct dcd_cmd *)pkt->pkt_cdbp), 2837a4aa671eSarutz error, status); 2838a4aa671eSarutz if ((error & ERR_AMNF) == ERR_AMNF) { 2839a4aa671eSarutz /* Address make not found */ 2840a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2841a4aa671eSarutz "Address Mark Not Found"); 2842a4aa671eSarutz } else if ((error & ERR_TKONF) == ERR_TKONF) { 2843a4aa671eSarutz /* Track 0 Not found */ 2844a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2845a4aa671eSarutz "Track 0 Not found \n"); 2846a4aa671eSarutz } else if ((error & ERR_IDNF) == ERR_IDNF) { 2847a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2848a4aa671eSarutz " ID not found \n"); 2849a4aa671eSarutz } else if ((error & ERR_UNC) == ERR_UNC) { 2850a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2851a4aa671eSarutz "Uncorrectable data Error: Block %x\n", 2852b9ccdc5aScth ((struct dcd_cmd *)pkt->pkt_cdbp)-> 2853b9ccdc5aScth sector_num.lba_num); 2854a4aa671eSarutz } else if ((error & ERR_BBK) == ERR_BBK) { 2855a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2856a4aa671eSarutz "Bad block detected: Block %x\n", 2857b9ccdc5aScth ((struct dcd_cmd *)pkt->pkt_cdbp)-> 2858b9ccdc5aScth sector_num.lba_num); 2859a4aa671eSarutz } else if ((error & ERR_ABORT) == ERR_ABORT) { 2860a4aa671eSarutz /* Aborted Command */ 2861a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2862a4aa671eSarutz " Aborted Command \n"); 2863a4aa671eSarutz } 2864a4aa671eSarutz /* 2865a4aa671eSarutz * Return the soft error so that the command 2866a4aa671eSarutz * will be retried. 2867a4aa671eSarutz */ 2868a4aa671eSarutz rval = COMMAND_SOFT_ERROR; 2869a4aa671eSarutz } 2870a4aa671eSarutz 2871a4aa671eSarutz TRACE_0(TR_FAC_DADA, TR_DCD_CHECK_ERROR_END, "dcd_check_error_end"); 2872a4aa671eSarutz return (rval); 2873a4aa671eSarutz } 2874a4aa671eSarutz 2875a4aa671eSarutz 2876a4aa671eSarutz /* 2877a4aa671eSarutz * System Crash Dump routine 2878a4aa671eSarutz */ 2879a4aa671eSarutz 2880a4aa671eSarutz #define NDUMP_RETRIES 5 2881a4aa671eSarutz 2882a4aa671eSarutz static int 2883a4aa671eSarutz dcddump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) 2884a4aa671eSarutz { 2885a4aa671eSarutz struct dcd_pkt *pkt; 2886a4aa671eSarutz int i; 2887a4aa671eSarutz struct buf local, *bp; 2888a4aa671eSarutz int err; 2889a4aa671eSarutz unsigned char com; 2890a4aa671eSarutz diskaddr_t p_lblksrt; 2891a4aa671eSarutz diskaddr_t lblocks; 2892a4aa671eSarutz 2893a4aa671eSarutz GET_SOFT_STATE(dev); 2894a4aa671eSarutz #ifdef lint 2895a4aa671eSarutz part = part; 2896a4aa671eSarutz #endif /* lint */ 2897a4aa671eSarutz 2898a4aa671eSarutz _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*un)) 2899a4aa671eSarutz 2900a4aa671eSarutz if ((un->un_state & DCD_STATE_FATAL) == DCD_STATE_FATAL) 2901a4aa671eSarutz return (ENXIO); 2902a4aa671eSarutz 2903a4aa671eSarutz if (cmlb_partinfo(un->un_dklbhandle, DCDPART(dev), 2904a4aa671eSarutz &lblocks, &p_lblksrt, NULL, NULL, 0)) 2905a4aa671eSarutz return (ENXIO); 2906a4aa671eSarutz 2907a4aa671eSarutz if (blkno+nblk > lblocks) { 2908a4aa671eSarutz return (EINVAL); 2909a4aa671eSarutz } 2910a4aa671eSarutz 2911a4aa671eSarutz 2912a4aa671eSarutz if ((un->un_state == DCD_STATE_SUSPENDED) || 2913a4aa671eSarutz (un->un_state == DCD_STATE_PM_SUSPENDED)) { 2914a4aa671eSarutz if (pm_raise_power(DCD_DEVINFO, 0, 2915a4aa671eSarutz DCD_DEVICE_ACTIVE) != DDI_SUCCESS) { 2916a4aa671eSarutz return (EIO); 2917a4aa671eSarutz } 2918a4aa671eSarutz } 2919a4aa671eSarutz 2920a4aa671eSarutz /* 2921a4aa671eSarutz * When cpr calls dcddump, we know that dad is in a 2922a4aa671eSarutz * a good state, so no bus reset is required 2923a4aa671eSarutz */ 2924a4aa671eSarutz un->un_throttle = 0; 2925a4aa671eSarutz 2926a4aa671eSarutz if ((un->un_state != DCD_STATE_SUSPENDED) && 2927a4aa671eSarutz (un->un_state != DCD_STATE_DUMPING)) { 2928a4aa671eSarutz 2929a4aa671eSarutz New_state(un, DCD_STATE_DUMPING); 2930a4aa671eSarutz 2931a4aa671eSarutz /* 2932a4aa671eSarutz * Reset the bus. I'd like to not have to do this, 2933a4aa671eSarutz * but this is the safest thing to do... 2934a4aa671eSarutz */ 2935a4aa671eSarutz 2936a4aa671eSarutz if (dcd_reset(ROUTE, RESET_ALL) == 0) { 2937a4aa671eSarutz return (EIO); 2938a4aa671eSarutz } 2939a4aa671eSarutz 2940a4aa671eSarutz } 2941a4aa671eSarutz 2942a4aa671eSarutz blkno += p_lblksrt; 2943a4aa671eSarutz 2944a4aa671eSarutz /* 2945a4aa671eSarutz * It should be safe to call the allocator here without 2946a4aa671eSarutz * worrying about being locked for DVMA mapping because 2947a4aa671eSarutz * the address we're passed is already a DVMA mapping 2948a4aa671eSarutz * 2949a4aa671eSarutz * We are also not going to worry about semaphore ownership 2950a4aa671eSarutz * in the dump buffer. Dumping is single threaded at present. 2951a4aa671eSarutz */ 2952a4aa671eSarutz 2953a4aa671eSarutz bp = &local; 2954a4aa671eSarutz bzero((caddr_t)bp, sizeof (*bp)); 2955a4aa671eSarutz bp->b_flags = B_BUSY; 2956a4aa671eSarutz bp->b_un.b_addr = addr; 2957a4aa671eSarutz bp->b_bcount = nblk << DEV_BSHIFT; 2958a4aa671eSarutz bp->b_resid = 0; 2959a4aa671eSarutz 2960a4aa671eSarutz for (i = 0; i < NDUMP_RETRIES; i++) { 2961a4aa671eSarutz bp->b_flags &= ~B_ERROR; 2962a4aa671eSarutz if ((pkt = dcd_init_pkt(ROUTE, NULL, bp, 2963a4aa671eSarutz (uint32_t)sizeof (struct dcd_cmd), 2, PP_LEN, 2964a4aa671eSarutz PKT_CONSISTENT, NULL_FUNC, NULL)) != NULL) { 2965a4aa671eSarutz break; 2966a4aa671eSarutz } 2967a4aa671eSarutz if (i == 0) { 2968a4aa671eSarutz if (bp->b_flags & B_ERROR) { 2969a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2970a4aa671eSarutz "no resources for dumping; " 2971a4aa671eSarutz "error code: 0x%x, retrying", 2972a4aa671eSarutz geterror(bp)); 2973a4aa671eSarutz } else { 2974a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 2975a4aa671eSarutz "no resources for dumping; retrying"); 2976a4aa671eSarutz } 2977a4aa671eSarutz } else if (i != (NDUMP_RETRIES - 1)) { 2978a4aa671eSarutz if (bp->b_flags & B_ERROR) { 2979a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_CONT, "no " 2980a4aa671eSarutz "resources for dumping; error code: 0x%x, " 2981a4aa671eSarutz "retrying\n", geterror(bp)); 2982a4aa671eSarutz } 2983a4aa671eSarutz } else { 2984a4aa671eSarutz if (bp->b_flags & B_ERROR) { 2985a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_CONT, 2986a4aa671eSarutz "no resources for dumping; " 2987a4aa671eSarutz "error code: 0x%x, retries failed, " 2988a4aa671eSarutz "giving up.\n", geterror(bp)); 2989a4aa671eSarutz } else { 2990a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_CONT, 2991a4aa671eSarutz "no resources for dumping; " 2992a4aa671eSarutz "retries failed, giving up.\n"); 2993a4aa671eSarutz } 2994a4aa671eSarutz return (EIO); 2995a4aa671eSarutz } 2996a4aa671eSarutz delay(10); 2997a4aa671eSarutz } 2998a4aa671eSarutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) { 2999a4aa671eSarutz com = ATA_WRITE_DMA; 3000a4aa671eSarutz } else { 3001a4aa671eSarutz if (un->un_dp->options & BLOCK_MODE) 3002a4aa671eSarutz com = ATA_WRITE_MULTIPLE; 3003a4aa671eSarutz else 3004a4aa671eSarutz com = ATA_WRITE; 3005a4aa671eSarutz } 3006a4aa671eSarutz 3007a4aa671eSarutz makecommand(pkt, 0, com, blkno, ADD_LBA_MODE, 3008a4aa671eSarutz (int)nblk*un->un_secsize, DATA_WRITE, 0); 3009a4aa671eSarutz 3010a4aa671eSarutz for (err = EIO, i = 0; i < NDUMP_RETRIES && err == EIO; i++) { 3011a4aa671eSarutz 3012a4aa671eSarutz if (dcd_poll(pkt) == 0) { 3013a4aa671eSarutz switch (SCBP_C(pkt)) { 3014a4aa671eSarutz case STATUS_GOOD: 3015a4aa671eSarutz if (pkt->pkt_resid == 0) { 3016a4aa671eSarutz err = 0; 3017a4aa671eSarutz } 3018a4aa671eSarutz break; 3019a4aa671eSarutz case STATUS_ATA_BUSY: 3020a4aa671eSarutz (void) dcd_reset(ROUTE, RESET_TARGET); 3021a4aa671eSarutz break; 3022a4aa671eSarutz default: 3023a4aa671eSarutz mutex_enter(DCD_MUTEX); 3024a4aa671eSarutz (void) dcd_reset_disk(un, pkt); 3025a4aa671eSarutz mutex_exit(DCD_MUTEX); 3026a4aa671eSarutz break; 3027a4aa671eSarutz } 3028a4aa671eSarutz } else if (i > NDUMP_RETRIES/2) { 3029a4aa671eSarutz (void) dcd_reset(ROUTE, RESET_ALL); 3030a4aa671eSarutz } 3031a4aa671eSarutz 3032a4aa671eSarutz } 3033a4aa671eSarutz dcd_destroy_pkt(pkt); 3034a4aa671eSarutz return (err); 3035a4aa671eSarutz } 3036a4aa671eSarutz 3037a4aa671eSarutz /* 3038a4aa671eSarutz * This routine implements the ioctl calls. It is called 3039a4aa671eSarutz * from the device switch at normal priority. 3040a4aa671eSarutz */ 3041a4aa671eSarutz /* ARGSUSED3 */ 3042a4aa671eSarutz static int 3043a4aa671eSarutz dcdioctl(dev_t dev, int cmd, intptr_t arg, int flag, 3044a4aa671eSarutz cred_t *cred_p, int *rval_p) 3045a4aa671eSarutz { 3046a4aa671eSarutz auto int32_t data[512 / (sizeof (int32_t))]; 3047a4aa671eSarutz struct dk_cinfo *info; 3048a4aa671eSarutz struct dk_minfo media_info; 3049a4aa671eSarutz struct udcd_cmd *scmd; 3050a4aa671eSarutz int i, err; 3051a4aa671eSarutz enum uio_seg uioseg = 0; 3052a4aa671eSarutz enum dkio_state state = 0; 3053a4aa671eSarutz #ifdef _MULTI_DATAMODEL 3054a4aa671eSarutz struct dadkio_rwcmd rwcmd; 3055a4aa671eSarutz #endif 3056a4aa671eSarutz struct dadkio_rwcmd32 rwcmd32; 3057a4aa671eSarutz struct dcd_cmd dcdcmd; 3058a4aa671eSarutz 3059a4aa671eSarutz GET_SOFT_STATE(dev); 3060a4aa671eSarutz #ifdef lint 3061a4aa671eSarutz part = part; 3062a4aa671eSarutz state = state; 3063a4aa671eSarutz uioseg = uioseg; 3064a4aa671eSarutz #endif /* lint */ 3065a4aa671eSarutz 3066a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 3067a4aa671eSarutz "dcd_ioctl : cmd %x, arg %lx\n", cmd, arg); 3068a4aa671eSarutz 3069a4aa671eSarutz bzero((caddr_t)data, sizeof (data)); 3070a4aa671eSarutz 3071a4aa671eSarutz switch (cmd) { 3072a4aa671eSarutz 3073a4aa671eSarutz #ifdef DCDDEBUG 3074a4aa671eSarutz /* 3075a4aa671eSarutz * Following ioctl are for testing RESET/ABORTS 3076a4aa671eSarutz */ 3077a4aa671eSarutz #define DKIOCRESET (DKIOC|14) 3078a4aa671eSarutz #define DKIOCABORT (DKIOC|15) 3079a4aa671eSarutz 3080a4aa671eSarutz case DKIOCRESET: 3081a4aa671eSarutz if (ddi_copyin((caddr_t)arg, (caddr_t)data, 4, flag)) 3082a4aa671eSarutz return (EFAULT); 3083a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 3084a4aa671eSarutz "DKIOCRESET: data = 0x%x\n", data[0]); 3085a4aa671eSarutz if (dcd_reset(ROUTE, data[0])) { 3086a4aa671eSarutz return (0); 3087a4aa671eSarutz } else { 3088a4aa671eSarutz return (EIO); 3089a4aa671eSarutz } 3090a4aa671eSarutz case DKIOCABORT: 3091a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, 3092a4aa671eSarutz "DKIOCABORT:\n"); 3093a4aa671eSarutz if (dcd_abort(ROUTE, (struct dcd_pkt *)0)) { 3094a4aa671eSarutz return (0); 3095a4aa671eSarutz } else { 3096a4aa671eSarutz return (EIO); 3097a4aa671eSarutz } 3098a4aa671eSarutz #endif 3099a4aa671eSarutz 3100a4aa671eSarutz case DKIOCINFO: 3101a4aa671eSarutz /* 3102a4aa671eSarutz * Controller Information 3103a4aa671eSarutz */ 3104a4aa671eSarutz info = (struct dk_cinfo *)data; 3105a4aa671eSarutz 3106a4aa671eSarutz mutex_enter(DCD_MUTEX); 3107a4aa671eSarutz switch (un->un_dp->ctype) { 3108a4aa671eSarutz default: 3109a4aa671eSarutz info->dki_ctype = DKC_DIRECT; 3110a4aa671eSarutz break; 3111a4aa671eSarutz } 3112a4aa671eSarutz mutex_exit(DCD_MUTEX); 3113a4aa671eSarutz info->dki_cnum = ddi_get_instance(ddi_get_parent(DCD_DEVINFO)); 3114a4aa671eSarutz (void) strcpy(info->dki_cname, 3115a4aa671eSarutz ddi_get_name(ddi_get_parent(DCD_DEVINFO))); 3116a4aa671eSarutz /* 3117a4aa671eSarutz * Unit Information 3118a4aa671eSarutz */ 3119a4aa671eSarutz info->dki_unit = ddi_get_instance(DCD_DEVINFO); 3120a4aa671eSarutz info->dki_slave = (Tgt(DCD_DCD_DEVP)<<3); 3121a4aa671eSarutz (void) strcpy(info->dki_dname, ddi_driver_name(DCD_DEVINFO)); 3122a4aa671eSarutz info->dki_flags = DKI_FMTVOL; 3123a4aa671eSarutz info->dki_partition = DCDPART(dev); 3124a4aa671eSarutz 3125a4aa671eSarutz /* 3126a4aa671eSarutz * Max Transfer size of this device in blocks 3127a4aa671eSarutz */ 3128a4aa671eSarutz info->dki_maxtransfer = un->un_max_xfer_size / DEV_BSIZE; 3129a4aa671eSarutz 3130a4aa671eSarutz /* 3131a4aa671eSarutz * We can't get from here to there yet 3132a4aa671eSarutz */ 3133a4aa671eSarutz info->dki_addr = 0; 3134a4aa671eSarutz info->dki_space = 0; 3135a4aa671eSarutz info->dki_prio = 0; 3136a4aa671eSarutz info->dki_vec = 0; 3137a4aa671eSarutz 3138a4aa671eSarutz i = sizeof (struct dk_cinfo); 3139a4aa671eSarutz if (ddi_copyout((caddr_t)data, (caddr_t)arg, i, flag)) 3140a4aa671eSarutz return (EFAULT); 3141a4aa671eSarutz else 3142a4aa671eSarutz return (0); 3143a4aa671eSarutz 3144a4aa671eSarutz case DKIOCGMEDIAINFO: 3145a4aa671eSarutz /* 3146a4aa671eSarutz * As dad target driver is used for IDE disks only 3147a4aa671eSarutz * Can keep the return value hardcoded to FIXED_DISK 3148a4aa671eSarutz */ 3149a4aa671eSarutz media_info.dki_media_type = DK_FIXED_DISK; 3150a4aa671eSarutz 3151a4aa671eSarutz mutex_enter(DCD_MUTEX); 3152a4aa671eSarutz media_info.dki_lbsize = un->un_lbasize; 3153a4aa671eSarutz media_info.dki_capacity = un->un_diskcapacity; 3154a4aa671eSarutz mutex_exit(DCD_MUTEX); 3155a4aa671eSarutz 3156a4aa671eSarutz if (ddi_copyout(&media_info, (caddr_t)arg, 3157a4aa671eSarutz sizeof (struct dk_minfo), flag)) 3158a4aa671eSarutz return (EFAULT); 3159a4aa671eSarutz else 3160a4aa671eSarutz return (0); 3161a4aa671eSarutz 3162a4aa671eSarutz case DKIOCGGEOM: 3163a4aa671eSarutz case DKIOCGVTOC: 3164a4aa671eSarutz case DKIOCGETEFI: 3165a4aa671eSarutz 3166a4aa671eSarutz mutex_enter(DCD_MUTEX); 3167a4aa671eSarutz if (un->un_ncmds == 0) { 3168a4aa671eSarutz if ((err = dcd_unit_ready(dev)) != 0) { 3169a4aa671eSarutz mutex_exit(DCD_MUTEX); 3170a4aa671eSarutz return (err); 3171a4aa671eSarutz } 3172a4aa671eSarutz } 3173a4aa671eSarutz 3174a4aa671eSarutz mutex_exit(DCD_MUTEX); 3175a4aa671eSarutz err = cmlb_ioctl(un->un_dklbhandle, dev, cmd, 3176a4aa671eSarutz arg, flag, cred_p, rval_p, 0); 3177a4aa671eSarutz return (err); 3178a4aa671eSarutz 3179a4aa671eSarutz case DKIOCGAPART: 3180a4aa671eSarutz case DKIOCSAPART: 3181a4aa671eSarutz case DKIOCSGEOM: 3182a4aa671eSarutz case DKIOCSVTOC: 3183a4aa671eSarutz case DKIOCSETEFI: 3184a4aa671eSarutz case DKIOCPARTITION: 3185a4aa671eSarutz case DKIOCPARTINFO: 3186a4aa671eSarutz case DKIOCGMBOOT: 3187a4aa671eSarutz case DKIOCSMBOOT: 3188a4aa671eSarutz 3189a4aa671eSarutz err = cmlb_ioctl(un->un_dklbhandle, dev, cmd, 3190a4aa671eSarutz arg, flag, cred_p, rval_p, 0); 3191a4aa671eSarutz return (err); 3192a4aa671eSarutz 3193a4aa671eSarutz case DIOCTL_RWCMD: 3194a4aa671eSarutz if (drv_priv(cred_p) != 0) { 3195a4aa671eSarutz return (EPERM); 3196a4aa671eSarutz } 3197a4aa671eSarutz 3198a4aa671eSarutz #ifdef _MULTI_DATAMODEL 3199a4aa671eSarutz switch (ddi_model_convert_from(flag & FMODELS)) { 3200a4aa671eSarutz case DDI_MODEL_NONE: 3201a4aa671eSarutz if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd, 3202a4aa671eSarutz sizeof (struct dadkio_rwcmd), flag)) { 3203a4aa671eSarutz return (EFAULT); 3204a4aa671eSarutz } 3205a4aa671eSarutz rwcmd32.cmd = rwcmd.cmd; 3206a4aa671eSarutz rwcmd32.flags = rwcmd.flags; 3207a4aa671eSarutz rwcmd32.blkaddr = rwcmd.blkaddr; 3208a4aa671eSarutz rwcmd32.buflen = rwcmd.buflen; 3209a4aa671eSarutz rwcmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmd.bufaddr; 3210a4aa671eSarutz break; 3211a4aa671eSarutz case DDI_MODEL_ILP32: 3212a4aa671eSarutz if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd32, 3213a4aa671eSarutz sizeof (struct dadkio_rwcmd32), flag)) { 3214a4aa671eSarutz return (EFAULT); 3215a4aa671eSarutz } 3216a4aa671eSarutz break; 3217a4aa671eSarutz } 3218a4aa671eSarutz #else 3219a4aa671eSarutz if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd32, 3220a4aa671eSarutz sizeof (struct dadkio_rwcmd32), flag)) { 3221a4aa671eSarutz return (EFAULT); 3222a4aa671eSarutz } 3223a4aa671eSarutz #endif 3224a4aa671eSarutz mutex_enter(DCD_MUTEX); 3225a4aa671eSarutz 3226a4aa671eSarutz uioseg = UIO_SYSSPACE; 3227a4aa671eSarutz scmd = (struct udcd_cmd *)data; 3228a4aa671eSarutz scmd->udcd_cmd = &dcdcmd; 3229a4aa671eSarutz /* 3230a4aa671eSarutz * Convert the dadkio_rwcmd structure to udcd_cmd so that 3231a4aa671eSarutz * it can take the normal path to get the io done 3232a4aa671eSarutz */ 3233a4aa671eSarutz if (rwcmd32.cmd == DADKIO_RWCMD_READ) { 3234a4aa671eSarutz if ((un->un_dp->options & DMA_SUPPORTTED) == 3235a4aa671eSarutz DMA_SUPPORTTED) 3236a4aa671eSarutz scmd->udcd_cmd->cmd = ATA_READ_DMA; 3237a4aa671eSarutz else 3238a4aa671eSarutz scmd->udcd_cmd->cmd = ATA_READ; 3239a4aa671eSarutz scmd->udcd_cmd->address_mode = ADD_LBA_MODE; 3240a4aa671eSarutz scmd->udcd_cmd->direction = DATA_READ; 3241a4aa671eSarutz scmd->udcd_flags |= UDCD_READ|UDCD_SILENT; 3242a4aa671eSarutz } else if (rwcmd32.cmd == DADKIO_RWCMD_WRITE) { 3243a4aa671eSarutz if ((un->un_dp->options & DMA_SUPPORTTED) == 3244a4aa671eSarutz DMA_SUPPORTTED) 3245a4aa671eSarutz scmd->udcd_cmd->cmd = ATA_WRITE_DMA; 3246a4aa671eSarutz else 3247a4aa671eSarutz scmd->udcd_cmd->cmd = ATA_WRITE; 3248a4aa671eSarutz scmd->udcd_cmd->direction = DATA_WRITE; 3249a4aa671eSarutz scmd->udcd_flags |= UDCD_WRITE|UDCD_SILENT; 3250a4aa671eSarutz } else { 3251a4aa671eSarutz mutex_exit(DCD_MUTEX); 3252a4aa671eSarutz return (EINVAL); 3253a4aa671eSarutz } 3254a4aa671eSarutz 3255a4aa671eSarutz scmd->udcd_cmd->address_mode = ADD_LBA_MODE; 3256a4aa671eSarutz scmd->udcd_cmd->features = 0; 3257a4aa671eSarutz scmd->udcd_cmd->size = rwcmd32.buflen; 3258a4aa671eSarutz scmd->udcd_cmd->sector_num.lba_num = rwcmd32.blkaddr; 3259a4aa671eSarutz scmd->udcd_bufaddr = (caddr_t)(uintptr_t)rwcmd32.bufaddr; 3260a4aa671eSarutz scmd->udcd_buflen = rwcmd32.buflen; 3261a4aa671eSarutz scmd->udcd_timeout = (ushort_t)dcd_io_time; 3262a4aa671eSarutz scmd->udcd_resid = 0ULL; 3263a4aa671eSarutz scmd->udcd_status = 0; 3264a4aa671eSarutz scmd->udcd_error_reg = 0; 3265a4aa671eSarutz scmd->udcd_status_reg = 0; 3266a4aa671eSarutz 3267a4aa671eSarutz mutex_exit(DCD_MUTEX); 3268a4aa671eSarutz 3269a4aa671eSarutz i = dcdioctl_cmd(dev, scmd, UIO_SYSSPACE, UIO_USERSPACE); 3270a4aa671eSarutz mutex_enter(DCD_MUTEX); 3271a4aa671eSarutz /* 3272a4aa671eSarutz * After return convert the status from scmd to 3273a4aa671eSarutz * dadkio_status 3274a4aa671eSarutz */ 3275a4aa671eSarutz (void) dcd_translate(&(rwcmd32.status), scmd); 3276a4aa671eSarutz rwcmd32.status.resid = scmd->udcd_resid; 3277a4aa671eSarutz mutex_exit(DCD_MUTEX); 3278a4aa671eSarutz 3279a4aa671eSarutz #ifdef _MULTI_DATAMODEL 3280a4aa671eSarutz switch (ddi_model_convert_from(flag & FMODELS)) { 3281a4aa671eSarutz case DDI_MODEL_NONE: { 3282a4aa671eSarutz int counter; 3283a4aa671eSarutz rwcmd.status.status = rwcmd32.status.status; 3284a4aa671eSarutz rwcmd.status.resid = rwcmd32.status.resid; 3285a4aa671eSarutz rwcmd.status.failed_blk_is_valid = 3286a4aa671eSarutz rwcmd32.status.failed_blk_is_valid; 3287a4aa671eSarutz rwcmd.status.failed_blk = rwcmd32.status.failed_blk; 3288a4aa671eSarutz rwcmd.status.fru_code_is_valid = 3289a4aa671eSarutz rwcmd32.status.fru_code_is_valid; 3290a4aa671eSarutz rwcmd.status.fru_code = rwcmd32.status.fru_code; 3291a4aa671eSarutz for (counter = 0; 3292a4aa671eSarutz counter < DADKIO_ERROR_INFO_LEN; counter++) 3293a4aa671eSarutz rwcmd.status.add_error_info[counter] = 3294a4aa671eSarutz rwcmd32.status.add_error_info[counter]; 3295a4aa671eSarutz } 3296a4aa671eSarutz /* Copy out the result back to the user program */ 3297a4aa671eSarutz if (ddi_copyout((caddr_t)&rwcmd, (caddr_t)arg, 3298a4aa671eSarutz sizeof (struct dadkio_rwcmd), flag)) { 3299a4aa671eSarutz if (i != 0) { 3300a4aa671eSarutz i = EFAULT; 3301a4aa671eSarutz } 3302a4aa671eSarutz } 3303a4aa671eSarutz break; 3304a4aa671eSarutz case DDI_MODEL_ILP32: 3305a4aa671eSarutz /* Copy out the result back to the user program */ 3306a4aa671eSarutz if (ddi_copyout((caddr_t)&rwcmd32, (caddr_t)arg, 3307a4aa671eSarutz sizeof (struct dadkio_rwcmd32), flag)) { 3308a4aa671eSarutz if (i != 0) { 3309a4aa671eSarutz i = EFAULT; 3310a4aa671eSarutz } 3311a4aa671eSarutz } 3312a4aa671eSarutz break; 3313a4aa671eSarutz } 3314a4aa671eSarutz #else 3315a4aa671eSarutz /* Copy out the result back to the user program */ 3316a4aa671eSarutz if (ddi_copyout((caddr_t)&rwcmd32, (caddr_t)arg, 3317a4aa671eSarutz sizeof (struct dadkio_rwcmd32), flag)) { 3318a4aa671eSarutz if (i != 0) 3319a4aa671eSarutz i = EFAULT; 3320a4aa671eSarutz } 3321a4aa671eSarutz #endif 3322a4aa671eSarutz return (i); 3323a4aa671eSarutz 3324a4aa671eSarutz case UDCDCMD: { 3325a4aa671eSarutz #ifdef _MULTI_DATAMODEL 3326a4aa671eSarutz /* 3327a4aa671eSarutz * For use when a 32 bit app makes a call into a 3328a4aa671eSarutz * 64 bit ioctl 3329a4aa671eSarutz */ 3330a4aa671eSarutz struct udcd_cmd32 udcd_cmd_32_for_64; 3331a4aa671eSarutz struct udcd_cmd32 *ucmd32 = &udcd_cmd_32_for_64; 3332a4aa671eSarutz model_t model; 3333a4aa671eSarutz #endif /* _MULTI_DATAMODEL */ 3334a4aa671eSarutz 3335a4aa671eSarutz if (drv_priv(cred_p) != 0) { 3336a4aa671eSarutz return (EPERM); 3337a4aa671eSarutz } 3338a4aa671eSarutz 3339a4aa671eSarutz scmd = (struct udcd_cmd *)data; 3340a4aa671eSarutz 3341a4aa671eSarutz #ifdef _MULTI_DATAMODEL 3342a4aa671eSarutz switch (model = ddi_model_convert_from(flag & FMODELS)) { 3343a4aa671eSarutz case DDI_MODEL_ILP32: 3344a4aa671eSarutz if (ddi_copyin((caddr_t)arg, ucmd32, 3345a4aa671eSarutz sizeof (struct udcd_cmd32), flag)) { 3346a4aa671eSarutz return (EFAULT); 3347a4aa671eSarutz } 3348a4aa671eSarutz /* 3349a4aa671eSarutz * Convert the ILP32 uscsi data from the 3350a4aa671eSarutz * application to LP64 for internal use. 3351a4aa671eSarutz */ 3352a4aa671eSarutz udcd_cmd32toudcd_cmd(ucmd32, scmd); 3353a4aa671eSarutz break; 3354a4aa671eSarutz case DDI_MODEL_NONE: 3355a4aa671eSarutz if (ddi_copyin((caddr_t)arg, scmd, sizeof (*scmd), 3356a4aa671eSarutz flag)) { 3357a4aa671eSarutz return (EFAULT); 3358a4aa671eSarutz } 3359a4aa671eSarutz break; 3360a4aa671eSarutz } 3361a4aa671eSarutz #else /* ! _MULTI_DATAMODEL */ 3362a4aa671eSarutz if (ddi_copyin((caddr_t)arg, (caddr_t)scmd, 3363a4aa671eSarutz sizeof (*scmd), flag)) { 3364a4aa671eSarutz return (EFAULT); 3365a4aa671eSarutz } 3366a4aa671eSarutz #endif /* ! _MULTI_DATAMODEL */ 3367a4aa671eSarutz 3368a4aa671eSarutz scmd->udcd_flags &= ~UDCD_NOINTR; 3369a4aa671eSarutz uioseg = (flag & FKIOCTL)? UIO_SYSSPACE: UIO_USERSPACE; 3370a4aa671eSarutz 3371a4aa671eSarutz i = dcdioctl_cmd(dev, scmd, uioseg, uioseg); 3372a4aa671eSarutz #ifdef _MULTI_DATAMODEL 3373a4aa671eSarutz switch (model) { 3374a4aa671eSarutz case DDI_MODEL_ILP32: 3375a4aa671eSarutz /* 3376a4aa671eSarutz * Convert back to ILP32 before copyout to the 3377a4aa671eSarutz * application 3378a4aa671eSarutz */ 3379a4aa671eSarutz udcd_cmdtoudcd_cmd32(scmd, ucmd32); 3380a4aa671eSarutz if (ddi_copyout(ucmd32, (caddr_t)arg, 3381a4aa671eSarutz sizeof (*ucmd32), flag)) { 3382a4aa671eSarutz if (i != 0) 3383a4aa671eSarutz i = EFAULT; 3384a4aa671eSarutz } 3385a4aa671eSarutz break; 3386a4aa671eSarutz case DDI_MODEL_NONE: 3387a4aa671eSarutz if (ddi_copyout(scmd, (caddr_t)arg, sizeof (*scmd), 3388a4aa671eSarutz flag)) { 3389a4aa671eSarutz if (i != 0) 3390a4aa671eSarutz i = EFAULT; 3391a4aa671eSarutz } 3392a4aa671eSarutz break; 3393a4aa671eSarutz } 3394a4aa671eSarutz #else /* ! _MULTI_DATAMODE */ 3395a4aa671eSarutz if (ddi_copyout((caddr_t)scmd, (caddr_t)arg, 3396a4aa671eSarutz sizeof (*scmd), flag)) { 3397a4aa671eSarutz if (i != 0) 3398a4aa671eSarutz i = EFAULT; 3399a4aa671eSarutz } 3400a4aa671eSarutz #endif 3401a4aa671eSarutz return (i); 3402a4aa671eSarutz } 3403a4aa671eSarutz case DKIOCFLUSHWRITECACHE: { 3404a4aa671eSarutz struct dk_callback *dkc = (struct dk_callback *)arg; 3405a4aa671eSarutz struct dcd_pkt *pkt; 3406a4aa671eSarutz struct buf *bp; 3407a4aa671eSarutz int is_sync = 1; 3408a4aa671eSarutz 3409a4aa671eSarutz mutex_enter(DCD_MUTEX); 3410a4aa671eSarutz if (un->un_flush_not_supported || 3411a4aa671eSarutz ! un->un_write_cache_enabled) { 3412a4aa671eSarutz i = un->un_flush_not_supported ? ENOTSUP : 0; 3413a4aa671eSarutz mutex_exit(DCD_MUTEX); 3414a4aa671eSarutz /* 3415a4aa671eSarutz * If a callback was requested: a callback will 3416a4aa671eSarutz * always be done if the caller saw the 3417a4aa671eSarutz * DKIOCFLUSHWRITECACHE ioctl return 0, and 3418a4aa671eSarutz * never done if the caller saw the ioctl return 3419a4aa671eSarutz * an error. 3420a4aa671eSarutz */ 3421a4aa671eSarutz if ((flag & FKIOCTL) && dkc != NULL && 3422a4aa671eSarutz dkc->dkc_callback != NULL) { 3423a4aa671eSarutz (*dkc->dkc_callback)(dkc->dkc_cookie, i); 3424a4aa671eSarutz /* 3425a4aa671eSarutz * Did callback and reported error. 3426a4aa671eSarutz * Since we did a callback, ioctl 3427a4aa671eSarutz * should return 0. 3428a4aa671eSarutz */ 3429a4aa671eSarutz i = 0; 3430a4aa671eSarutz } 3431a4aa671eSarutz return (i); 3432a4aa671eSarutz } 3433a4aa671eSarutz 3434a4aa671eSarutz /* 3435a4aa671eSarutz * Get the special buffer 3436a4aa671eSarutz */ 3437a4aa671eSarutz while (un->un_sbuf_busy) { 3438a4aa671eSarutz cv_wait(&un->un_sbuf_cv, DCD_MUTEX); 3439a4aa671eSarutz } 3440a4aa671eSarutz un->un_sbuf_busy = 1; 3441a4aa671eSarutz bp = un->un_sbufp; 3442a4aa671eSarutz mutex_exit(DCD_MUTEX); 3443a4aa671eSarutz 3444a4aa671eSarutz pkt = dcd_init_pkt(ROUTE, (struct dcd_pkt *)NULL, 3445a4aa671eSarutz NULL, (uint32_t)sizeof (struct dcd_cmd), 3446a4aa671eSarutz 2, PP_LEN, PKT_CONSISTENT, SLEEP_FUNC, (caddr_t)un); 3447a4aa671eSarutz ASSERT(pkt != NULL); 3448a4aa671eSarutz 3449a4aa671eSarutz makecommand(pkt, un->un_cmd_flags | FLAG_SILENT, 3450a4aa671eSarutz ATA_FLUSH_CACHE, 0, ADD_LBA_MODE, 0, NO_DATA_XFER, 0); 3451a4aa671eSarutz 3452a4aa671eSarutz pkt->pkt_comp = dcdintr; 3453a4aa671eSarutz pkt->pkt_time = DCD_FLUSH_TIME; 3454a4aa671eSarutz PKT_SET_BP(pkt, bp); 3455a4aa671eSarutz 3456a4aa671eSarutz bp->av_back = (struct buf *)pkt; 3457a4aa671eSarutz bp->b_forw = NULL; 3458a4aa671eSarutz bp->b_flags = B_BUSY; 3459a4aa671eSarutz bp->b_error = 0; 3460a4aa671eSarutz bp->b_edev = dev; 3461a4aa671eSarutz bp->b_dev = cmpdev(dev); 3462a4aa671eSarutz bp->b_bcount = 0; 3463a4aa671eSarutz bp->b_blkno = 0; 3464a4aa671eSarutz bp->b_un.b_addr = 0; 3465a4aa671eSarutz bp->b_iodone = NULL; 3466a4aa671eSarutz bp->b_list = NULL; 3467*744947dcSTom Erickson bp->b_private = NULL; 3468a4aa671eSarutz 3469a4aa671eSarutz if ((flag & FKIOCTL) && dkc != NULL && 3470a4aa671eSarutz dkc->dkc_callback != NULL) { 3471a4aa671eSarutz struct dk_callback *dkc2 = (struct dk_callback *) 3472a4aa671eSarutz kmem_zalloc(sizeof (*dkc2), KM_SLEEP); 3473a4aa671eSarutz bcopy(dkc, dkc2, sizeof (*dkc2)); 3474a4aa671eSarutz 3475*744947dcSTom Erickson bp->b_private = dkc2; 3476a4aa671eSarutz bp->b_iodone = dcdflushdone; 3477a4aa671eSarutz is_sync = 0; 3478a4aa671eSarutz } 3479a4aa671eSarutz 3480a4aa671eSarutz (void) dcdstrategy(bp); 3481a4aa671eSarutz 3482a4aa671eSarutz i = 0; 3483a4aa671eSarutz if (is_sync) { 3484a4aa671eSarutz i = biowait(bp); 3485a4aa671eSarutz (void) dcdflushdone(bp); 3486a4aa671eSarutz } 3487a4aa671eSarutz 3488a4aa671eSarutz return (i); 3489a4aa671eSarutz } 3490a4aa671eSarutz default: 3491a4aa671eSarutz break; 3492a4aa671eSarutz } 3493a4aa671eSarutz return (ENOTTY); 3494a4aa671eSarutz } 3495a4aa671eSarutz 3496a4aa671eSarutz 3497a4aa671eSarutz static int 3498a4aa671eSarutz dcdflushdone(struct buf *bp) 3499a4aa671eSarutz { 3500a4aa671eSarutz struct dcd_disk *un = ddi_get_soft_state(dcd_state, 3501a4aa671eSarutz DCDUNIT(bp->b_edev)); 3502a4aa671eSarutz struct dcd_pkt *pkt = BP_PKT(bp); 3503*744947dcSTom Erickson struct dk_callback *dkc = bp->b_private; 3504a4aa671eSarutz 3505a4aa671eSarutz ASSERT(un != NULL); 3506a4aa671eSarutz ASSERT(bp == un->un_sbufp); 3507a4aa671eSarutz ASSERT(pkt != NULL); 3508a4aa671eSarutz 3509a4aa671eSarutz dcd_destroy_pkt(pkt); 3510a4aa671eSarutz bp->av_back = NO_PKT_ALLOCATED; 3511a4aa671eSarutz 3512a4aa671eSarutz if (dkc != NULL) { 3513a4aa671eSarutz ASSERT(bp->b_iodone != NULL); 3514a4aa671eSarutz (*dkc->dkc_callback)(dkc->dkc_cookie, geterror(bp)); 3515a4aa671eSarutz kmem_free(dkc, sizeof (*dkc)); 3516a4aa671eSarutz bp->b_iodone = NULL; 3517*744947dcSTom Erickson bp->b_private = NULL; 3518a4aa671eSarutz } 3519a4aa671eSarutz 3520a4aa671eSarutz /* 3521a4aa671eSarutz * Tell anybody who cares that the buffer is now free 3522a4aa671eSarutz */ 3523a4aa671eSarutz mutex_enter(DCD_MUTEX); 3524a4aa671eSarutz un->un_sbuf_busy = 0; 3525a4aa671eSarutz cv_signal(&un->un_sbuf_cv); 3526a4aa671eSarutz mutex_exit(DCD_MUTEX); 3527a4aa671eSarutz return (0); 3528a4aa671eSarutz } 3529a4aa671eSarutz 3530a4aa671eSarutz /* 3531a4aa671eSarutz * dcdrunout: 3532a4aa671eSarutz * the callback function for resource allocation 3533a4aa671eSarutz * 3534a4aa671eSarutz * XXX it would be preferable that dcdrunout() scans the whole 3535a4aa671eSarutz * list for possible candidates for dcdstart(); this avoids 3536a4aa671eSarutz * that a bp at the head of the list whose request cannot be 3537a4aa671eSarutz * satisfied is retried again and again 3538a4aa671eSarutz */ 3539a4aa671eSarutz /*ARGSUSED*/ 3540a4aa671eSarutz static int 3541a4aa671eSarutz dcdrunout(caddr_t arg) 3542a4aa671eSarutz { 3543a4aa671eSarutz int serviced; 3544a4aa671eSarutz struct dcd_disk *un; 3545a4aa671eSarutz struct diskhd *dp; 3546a4aa671eSarutz 3547a4aa671eSarutz TRACE_1(TR_FAC_DADA, TR_DCDRUNOUT_START, "dcdrunout_start: arg 0x%p", 3548a4aa671eSarutz arg); 3549a4aa671eSarutz serviced = 1; 3550a4aa671eSarutz 3551a4aa671eSarutz un = (struct dcd_disk *)arg; 3552a4aa671eSarutz dp = &un->un_utab; 3553a4aa671eSarutz 3554a4aa671eSarutz /* 3555a4aa671eSarutz * We now support passing a structure to the callback 3556a4aa671eSarutz * routine. 3557a4aa671eSarutz */ 3558a4aa671eSarutz ASSERT(un != NULL); 3559a4aa671eSarutz mutex_enter(DCD_MUTEX); 3560a4aa671eSarutz if ((un->un_ncmds < un->un_throttle) && (dp->b_forw == NULL)) { 3561a4aa671eSarutz dcdstart(un); 3562a4aa671eSarutz } 3563a4aa671eSarutz if (un->un_state == DCD_STATE_RWAIT) { 3564a4aa671eSarutz serviced = 0; 3565a4aa671eSarutz } 3566a4aa671eSarutz mutex_exit(DCD_MUTEX); 3567a4aa671eSarutz TRACE_1(TR_FAC_DADA, TR_DCDRUNOUT_END, 3568a4aa671eSarutz "dcdrunout_end: serviced %d", serviced); 3569a4aa671eSarutz return (serviced); 3570a4aa671eSarutz } 3571a4aa671eSarutz 3572a4aa671eSarutz 3573a4aa671eSarutz /* 3574a4aa671eSarutz * This routine called to see whether unit is (still) there. Must not 3575a4aa671eSarutz * be called when un->un_sbufp is in use, and must not be called with 3576a4aa671eSarutz * an unattached disk. Soft state of disk is restored to what it was 3577a4aa671eSarutz * upon entry- up to caller to set the correct state. 3578a4aa671eSarutz * 3579a4aa671eSarutz * We enter with the disk mutex held. 3580a4aa671eSarutz */ 3581a4aa671eSarutz 3582a4aa671eSarutz /* ARGSUSED0 */ 3583a4aa671eSarutz static int 3584a4aa671eSarutz dcd_unit_ready(dev_t dev) 3585a4aa671eSarutz { 3586a4aa671eSarutz #ifndef lint 3587a4aa671eSarutz auto struct udcd_cmd dcmd, *com = &dcmd; 3588a4aa671eSarutz auto struct dcd_cmd cmdblk; 3589a4aa671eSarutz #endif 3590a4aa671eSarutz int error; 3591a4aa671eSarutz #ifndef lint 3592a4aa671eSarutz GET_SOFT_STATE(dev); 3593a4aa671eSarutz #endif 3594a4aa671eSarutz 3595a4aa671eSarutz /* 3596a4aa671eSarutz * Now that we protect the special buffer with 3597a4aa671eSarutz * a mutex, we could probably do a mutex_tryenter 3598a4aa671eSarutz * on it here and return failure if it were held... 3599a4aa671eSarutz */ 3600a4aa671eSarutz 3601a4aa671eSarutz error = 0; 3602a4aa671eSarutz return (error); 3603a4aa671eSarutz } 3604a4aa671eSarutz 3605a4aa671eSarutz /* ARGSUSED0 */ 3606a4aa671eSarutz int 3607a4aa671eSarutz dcdioctl_cmd(dev_t devp, struct udcd_cmd *in, enum uio_seg cdbspace, 3608a4aa671eSarutz enum uio_seg dataspace) 3609a4aa671eSarutz { 3610a4aa671eSarutz 3611a4aa671eSarutz struct buf *bp; 3612a4aa671eSarutz struct udcd_cmd *scmd; 3613a4aa671eSarutz struct dcd_pkt *pkt; 3614a4aa671eSarutz int err, rw; 3615a4aa671eSarutz caddr_t cdb; 3616a4aa671eSarutz int flags = 0; 3617a4aa671eSarutz 3618a4aa671eSarutz GET_SOFT_STATE(devp); 3619a4aa671eSarutz 3620a4aa671eSarutz #ifdef lint 3621a4aa671eSarutz part = part; 3622a4aa671eSarutz #endif 3623a4aa671eSarutz 3624a4aa671eSarutz /* 3625a4aa671eSarutz * Is this a request to reset the bus? 3626a4aa671eSarutz * if so, we need to do reseting. 3627a4aa671eSarutz */ 3628a4aa671eSarutz 3629a4aa671eSarutz if (in->udcd_flags & UDCD_RESET) { 3630a4aa671eSarutz int flag = RESET_TARGET; 3631a4aa671eSarutz err = dcd_reset(ROUTE, flag) ? 0: EIO; 3632a4aa671eSarutz return (err); 3633a4aa671eSarutz } 3634a4aa671eSarutz 3635a4aa671eSarutz scmd = in; 3636a4aa671eSarutz 3637a4aa671eSarutz 3638a4aa671eSarutz /* Do some sanity checks */ 3639a4aa671eSarutz if (scmd->udcd_buflen <= 0) { 3640a4aa671eSarutz if (scmd->udcd_flags & (UDCD_READ | UDCD_WRITE)) { 3641a4aa671eSarutz return (EINVAL); 3642a4aa671eSarutz } else { 3643a4aa671eSarutz scmd->udcd_buflen = 0; 3644a4aa671eSarutz } 3645a4aa671eSarutz } 3646a4aa671eSarutz 3647a4aa671eSarutz /* Make a copy of the dcd_cmd passed */ 3648a4aa671eSarutz cdb = kmem_zalloc(sizeof (struct dcd_cmd), KM_SLEEP); 3649a4aa671eSarutz if (cdbspace == UIO_SYSSPACE) { 3650a4aa671eSarutz flags |= FKIOCTL; 3651a4aa671eSarutz } 3652a4aa671eSarutz 3653a4aa671eSarutz if (ddi_copyin((void *)scmd->udcd_cmd, cdb, sizeof (struct dcd_cmd), 3654a4aa671eSarutz flags)) { 3655a4aa671eSarutz kmem_free(cdb, sizeof (struct dcd_cmd)); 3656a4aa671eSarutz return (EFAULT); 3657a4aa671eSarutz } 3658a4aa671eSarutz scmd = (struct udcd_cmd *)kmem_alloc(sizeof (*scmd), KM_SLEEP); 3659a4aa671eSarutz bcopy((caddr_t)in, (caddr_t)scmd, sizeof (*scmd)); 3660a4aa671eSarutz scmd->udcd_cmd = (struct dcd_cmd *)cdb; 3661a4aa671eSarutz rw = (scmd->udcd_flags & UDCD_READ) ? B_READ: B_WRITE; 3662a4aa671eSarutz 3663a4aa671eSarutz 3664a4aa671eSarutz /* 3665a4aa671eSarutz * Get the special buffer 3666a4aa671eSarutz */ 3667a4aa671eSarutz 3668a4aa671eSarutz mutex_enter(DCD_MUTEX); 3669a4aa671eSarutz while (un->un_sbuf_busy) { 3670a4aa671eSarutz if (cv_wait_sig(&un->un_sbuf_cv, DCD_MUTEX) == 0) { 3671a4aa671eSarutz kmem_free(scmd->udcd_cmd, sizeof (struct dcd_cmd)); 3672a4aa671eSarutz kmem_free((caddr_t)scmd, sizeof (*scmd)); 3673a4aa671eSarutz mutex_exit(DCD_MUTEX); 3674a4aa671eSarutz return (EINTR); 3675a4aa671eSarutz } 3676a4aa671eSarutz } 3677a4aa671eSarutz 3678a4aa671eSarutz un->un_sbuf_busy = 1; 3679a4aa671eSarutz bp = un->un_sbufp; 3680a4aa671eSarutz mutex_exit(DCD_MUTEX); 3681a4aa671eSarutz 3682a4aa671eSarutz 3683a4aa671eSarutz /* 3684a4aa671eSarutz * If we are going to do actual I/O, let physio do all the 3685a4aa671eSarutz * things 3686a4aa671eSarutz */ 3687a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 3688a4aa671eSarutz "dcdioctl_cmd : buflen %x\n", scmd->udcd_buflen); 3689a4aa671eSarutz 3690a4aa671eSarutz if (scmd->udcd_buflen) { 3691a4aa671eSarutz auto struct iovec aiov; 3692a4aa671eSarutz auto struct uio auio; 3693a4aa671eSarutz struct uio *uio = &auio; 3694a4aa671eSarutz 3695a4aa671eSarutz bzero((caddr_t)&auio, sizeof (struct uio)); 3696a4aa671eSarutz bzero((caddr_t)&aiov, sizeof (struct iovec)); 3697a4aa671eSarutz 3698a4aa671eSarutz aiov.iov_base = scmd->udcd_bufaddr; 3699a4aa671eSarutz aiov.iov_len = scmd->udcd_buflen; 3700a4aa671eSarutz 3701a4aa671eSarutz uio->uio_iov = &aiov; 3702a4aa671eSarutz uio->uio_iovcnt = 1; 3703a4aa671eSarutz uio->uio_resid = scmd->udcd_buflen; 3704a4aa671eSarutz uio->uio_segflg = dataspace; 3705a4aa671eSarutz 3706a4aa671eSarutz /* 3707a4aa671eSarutz * Let physio do the rest... 3708a4aa671eSarutz */ 3709a4aa671eSarutz bp->av_back = NO_PKT_ALLOCATED; 3710a4aa671eSarutz bp->b_forw = (struct buf *)scmd; 3711a4aa671eSarutz err = physio(dcdstrategy, bp, devp, rw, dcdudcdmin, uio); 3712a4aa671eSarutz } else { 3713a4aa671eSarutz /* 3714a4aa671eSarutz * We have to mimic what physio would do here. 3715a4aa671eSarutz */ 3716a4aa671eSarutz bp->av_back = NO_PKT_ALLOCATED; 3717a4aa671eSarutz bp->b_forw = (struct buf *)scmd; 3718a4aa671eSarutz bp->b_flags = B_BUSY | rw; 3719a4aa671eSarutz bp->b_edev = devp; 3720a4aa671eSarutz bp->b_dev = cmpdev(devp); 3721a4aa671eSarutz bp->b_bcount = bp->b_blkno = 0; 3722a4aa671eSarutz (void) dcdstrategy(bp); 3723a4aa671eSarutz err = biowait(bp); 3724a4aa671eSarutz } 3725a4aa671eSarutz 3726a4aa671eSarutz done: 3727a4aa671eSarutz if ((pkt = BP_PKT(bp)) != NULL) { 3728a4aa671eSarutz bp->av_back = NO_PKT_ALLOCATED; 3729a4aa671eSarutz /* we need to update the completion status of udcd command */ 3730a4aa671eSarutz in->udcd_resid = bp->b_resid; 3731a4aa671eSarutz in->udcd_status_reg = SCBP_C(pkt); 3732a4aa671eSarutz /* XXX: we need to give error_reg also */ 3733a4aa671eSarutz dcd_destroy_pkt(pkt); 3734a4aa671eSarutz } 3735a4aa671eSarutz /* 3736a4aa671eSarutz * Tell anybody who cares that the buffer is now free 3737a4aa671eSarutz */ 3738a4aa671eSarutz mutex_enter(DCD_MUTEX); 3739a4aa671eSarutz un->un_sbuf_busy = 0; 3740a4aa671eSarutz cv_signal(&un->un_sbuf_cv); 3741a4aa671eSarutz mutex_exit(DCD_MUTEX); 3742a4aa671eSarutz 3743a4aa671eSarutz kmem_free(scmd->udcd_cmd, sizeof (struct dcd_cmd)); 3744a4aa671eSarutz kmem_free((caddr_t)scmd, sizeof (*scmd)); 3745a4aa671eSarutz return (err); 3746a4aa671eSarutz } 3747a4aa671eSarutz 3748a4aa671eSarutz static void 3749a4aa671eSarutz dcdudcdmin(struct buf *bp) 3750a4aa671eSarutz { 3751a4aa671eSarutz 3752a4aa671eSarutz #ifdef lint 3753a4aa671eSarutz bp = bp; 3754a4aa671eSarutz #endif 3755a4aa671eSarutz 3756a4aa671eSarutz } 3757a4aa671eSarutz 3758a4aa671eSarutz /* 3759a4aa671eSarutz * restart a cmd from timeout() context 3760a4aa671eSarutz * 3761a4aa671eSarutz * the cmd is expected to be in un_utab.b_forw. If this pointer is non-zero 3762a4aa671eSarutz * a restart timeout request has been issued and no new timeouts should 3763a4aa671eSarutz * be requested. b_forw is reset when the cmd eventually completes in 3764a4aa671eSarutz * dcddone_and_mutex_exit() 3765a4aa671eSarutz */ 3766a4aa671eSarutz void 3767a4aa671eSarutz dcdrestart(void *arg) 3768a4aa671eSarutz { 3769a4aa671eSarutz struct dcd_disk *un = (struct dcd_disk *)arg; 3770a4aa671eSarutz struct buf *bp; 3771a4aa671eSarutz int status; 3772a4aa671eSarutz 3773a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdrestart\n"); 3774a4aa671eSarutz 3775a4aa671eSarutz mutex_enter(DCD_MUTEX); 3776a4aa671eSarutz bp = un->un_utab.b_forw; 3777a4aa671eSarutz if (bp) { 3778a4aa671eSarutz un->un_ncmds++; 3779a4aa671eSarutz DCD_DO_KSTATS(un, kstat_waitq_to_runq, bp); 3780a4aa671eSarutz } 3781a4aa671eSarutz 3782a4aa671eSarutz 3783a4aa671eSarutz if (bp) { 3784a4aa671eSarutz struct dcd_pkt *pkt = BP_PKT(bp); 3785a4aa671eSarutz 3786a4aa671eSarutz mutex_exit(DCD_MUTEX); 3787a4aa671eSarutz 3788a4aa671eSarutz pkt->pkt_flags = 0; 3789a4aa671eSarutz 3790a4aa671eSarutz if ((status = dcd_transport(pkt)) != TRAN_ACCEPT) { 3791a4aa671eSarutz mutex_enter(DCD_MUTEX); 3792a4aa671eSarutz DCD_DO_KSTATS(un, kstat_runq_back_to_waitq, bp); 3793a4aa671eSarutz un->un_ncmds--; 3794a4aa671eSarutz if (status == TRAN_BUSY) { 3795a4aa671eSarutz /* XXX : To be checked */ 3796a4aa671eSarutz /* 3797a4aa671eSarutz * if (un->un_throttle > 1) { 3798a4aa671eSarutz * ASSERT(un->un_ncmds >= 0); 3799a4aa671eSarutz * un->un_throttle = un->un_ncmds; 3800a4aa671eSarutz * } 3801a4aa671eSarutz */ 3802a4aa671eSarutz un->un_reissued_timeid = 3803a4aa671eSarutz timeout(dcdrestart, (caddr_t)un, 3804a4aa671eSarutz DCD_BSY_TIMEOUT/500); 3805a4aa671eSarutz mutex_exit(DCD_MUTEX); 3806a4aa671eSarutz return; 3807a4aa671eSarutz } 3808a4aa671eSarutz DCD_DO_ERRSTATS(un, dcd_transerrs); 3809a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 3810a4aa671eSarutz "dcdrestart transport failed (%x)\n", status); 3811a4aa671eSarutz bp->b_resid = bp->b_bcount; 3812a4aa671eSarutz SET_BP_ERROR(bp, EIO); 3813a4aa671eSarutz 3814a4aa671eSarutz DCD_DO_KSTATS(un, kstat_waitq_exit, bp); 3815a4aa671eSarutz un->un_reissued_timeid = 0L; 3816a4aa671eSarutz dcddone_and_mutex_exit(un, bp); 3817a4aa671eSarutz return; 3818a4aa671eSarutz } 3819a4aa671eSarutz mutex_enter(DCD_MUTEX); 3820a4aa671eSarutz } 3821a4aa671eSarutz un->un_reissued_timeid = 0L; 3822a4aa671eSarutz mutex_exit(DCD_MUTEX); 3823a4aa671eSarutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdrestart done\n"); 3824a4aa671eSarutz } 3825a4aa671eSarutz 3826a4aa671eSarutz /* 3827a4aa671eSarutz * This routine gets called to reset the throttle to its saved 3828a4aa671eSarutz * value wheneven we lower the throttle. 3829a4aa671eSarutz */ 3830a4aa671eSarutz void 3831a4aa671eSarutz dcd_reset_throttle(caddr_t arg) 3832a4aa671eSarutz { 3833a4aa671eSarutz struct dcd_disk *un = (struct dcd_disk *)arg; 3834a4aa671eSarutz struct diskhd *dp; 3835a4aa671eSarutz 3836a4aa671eSarutz mutex_enter(DCD_MUTEX); 3837a4aa671eSarutz dp = &un->un_utab; 3838a4aa671eSarutz 3839a4aa671eSarutz /* 3840a4aa671eSarutz * start any commands that didn't start while throttling. 3841a4aa671eSarutz */ 3842a4aa671eSarutz if (dp->b_actf && (un->un_ncmds < un->un_throttle) && 3843a4aa671eSarutz (dp->b_forw == NULL)) { 3844a4aa671eSarutz dcdstart(un); 3845a4aa671eSarutz } 3846a4aa671eSarutz mutex_exit(DCD_MUTEX); 3847a4aa671eSarutz } 3848a4aa671eSarutz 3849a4aa671eSarutz 3850a4aa671eSarutz /* 3851a4aa671eSarutz * This routine handles the case when a TRAN_BUSY is 3852a4aa671eSarutz * returned by HBA. 3853a4aa671eSarutz * 3854a4aa671eSarutz * If there are some commands already in the transport, the 3855a4aa671eSarutz * bp can be put back on queue and it will 3856a4aa671eSarutz * be retried when the queue is emptied after command 3857a4aa671eSarutz * completes. But if there is no command in the tranport 3858a4aa671eSarutz * and it still return busy, we have to retry the command 3859a4aa671eSarutz * after some time like 10ms. 3860a4aa671eSarutz */ 3861a4aa671eSarutz /* ARGSUSED0 */ 3862a4aa671eSarutz static void 3863a4aa671eSarutz dcd_handle_tran_busy(struct buf *bp, struct diskhd *dp, struct dcd_disk *un) 3864a4aa671eSarutz { 3865a4aa671eSarutz ASSERT(mutex_owned(DCD_MUTEX)); 3866a4aa671eSarutz 3867a4aa671eSarutz 3868a4aa671eSarutz if (dp->b_forw == NULL || dp->b_forw == bp) { 3869a4aa671eSarutz dp->b_forw = bp; 3870a4aa671eSarutz } else if (dp->b_forw != bp) { 3871a4aa671eSarutz bp->b_actf = dp->b_actf; 3872a4aa671eSarutz dp->b_actf = bp; 3873a4aa671eSarutz 3874a4aa671eSarutz } 3875a4aa671eSarutz if (!un->un_reissued_timeid) { 3876a4aa671eSarutz un->un_reissued_timeid = 3877a4aa671eSarutz timeout(dcdrestart, (caddr_t)un, DCD_BSY_TIMEOUT/500); 3878a4aa671eSarutz } 3879a4aa671eSarutz } 3880a4aa671eSarutz 3881a4aa671eSarutz static int 3882a4aa671eSarutz dcd_write_deviceid(struct dcd_disk *un) 3883a4aa671eSarutz { 3884a4aa671eSarutz 3885a4aa671eSarutz int status; 3886a4aa671eSarutz diskaddr_t blk; 3887a4aa671eSarutz struct udcd_cmd ucmd; 3888a4aa671eSarutz struct dcd_cmd cdb; 3889a4aa671eSarutz struct dk_devid *dkdevid; 3890a4aa671eSarutz uint_t *ip, chksum; 3891a4aa671eSarutz int i; 3892a4aa671eSarutz dev_t dev; 3893a4aa671eSarutz 3894a4aa671eSarutz mutex_exit(DCD_MUTEX); 3895a4aa671eSarutz if (cmlb_get_devid_block(un->un_dklbhandle, &blk, 0)) { 3896a4aa671eSarutz mutex_enter(DCD_MUTEX); 3897a4aa671eSarutz return (EINVAL); 3898a4aa671eSarutz } 3899a4aa671eSarutz mutex_enter(DCD_MUTEX); 3900a4aa671eSarutz 3901a4aa671eSarutz /* Allocate the buffer */ 3902a4aa671eSarutz dkdevid = kmem_zalloc(un->un_secsize, KM_SLEEP); 3903a4aa671eSarutz 3904a4aa671eSarutz /* Fill in the revision */ 3905a4aa671eSarutz dkdevid->dkd_rev_hi = DK_DEVID_REV_MSB; 3906a4aa671eSarutz dkdevid->dkd_rev_lo = DK_DEVID_REV_LSB; 3907a4aa671eSarutz 3908a4aa671eSarutz /* Copy in the device id */ 3909a4aa671eSarutz bcopy(un->un_devid, &dkdevid->dkd_devid, 3910a4aa671eSarutz ddi_devid_sizeof(un->un_devid)); 3911a4aa671eSarutz 3912a4aa671eSarutz /* Calculate the chksum */ 3913a4aa671eSarutz chksum = 0; 3914a4aa671eSarutz ip = (uint_t *)dkdevid; 3915a4aa671eSarutz for (i = 0; i < ((un->un_secsize - sizeof (int))/sizeof (int)); i++) 3916a4aa671eSarutz chksum ^= ip[i]; 3917a4aa671eSarutz 3918a4aa671eSarutz /* Fill in the checksum */ 3919a4aa671eSarutz DKD_FORMCHKSUM(chksum, dkdevid); 3920a4aa671eSarutz 3921a4aa671eSarutz (void) bzero((caddr_t)&ucmd, sizeof (ucmd)); 3922a4aa671eSarutz (void) bzero((caddr_t)&cdb, sizeof (struct dcd_cmd)); 3923a4aa671eSarutz 3924a4aa671eSarutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) { 3925a4aa671eSarutz cdb.cmd = ATA_WRITE_DMA; 3926a4aa671eSarutz } else { 3927a4aa671eSarutz if (un->un_dp->options & BLOCK_MODE) 3928a4aa671eSarutz cdb.cmd = ATA_WRITE_MULTIPLE; 3929a4aa671eSarutz else 3930a4aa671eSarutz cdb.cmd = ATA_WRITE; 3931a4aa671eSarutz } 3932a4aa671eSarutz cdb.size = un->un_secsize; 3933a4aa671eSarutz cdb.sector_num.lba_num = blk; 3934a4aa671eSarutz cdb.address_mode = ADD_LBA_MODE; 3935a4aa671eSarutz cdb.direction = DATA_WRITE; 3936a4aa671eSarutz 3937a4aa671eSarutz ucmd.udcd_flags = UDCD_WRITE; 3938a4aa671eSarutz ucmd.udcd_cmd = &cdb; 3939a4aa671eSarutz ucmd.udcd_bufaddr = (caddr_t)dkdevid; 3940a4aa671eSarutz ucmd.udcd_buflen = un->un_secsize; 3941a4aa671eSarutz ucmd.udcd_flags |= UDCD_SILENT; 3942a4aa671eSarutz dev = makedevice(ddi_driver_major(DCD_DEVINFO), 3943a4aa671eSarutz ddi_get_instance(DCD_DEVINFO) << DCDUNIT_SHIFT); 3944a4aa671eSarutz mutex_exit(DCD_MUTEX); 3945a4aa671eSarutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE); 3946a4aa671eSarutz mutex_enter(DCD_MUTEX); 3947a4aa671eSarutz 3948a4aa671eSarutz kmem_free(dkdevid, un->un_secsize); 3949a4aa671eSarutz return (status); 3950a4aa671eSarutz } 3951a4aa671eSarutz 3952a4aa671eSarutz static int 3953a4aa671eSarutz dcd_read_deviceid(struct dcd_disk *un) 3954a4aa671eSarutz { 3955a4aa671eSarutz int status; 3956a4aa671eSarutz diskaddr_t blk; 3957a4aa671eSarutz struct udcd_cmd ucmd; 3958a4aa671eSarutz struct dcd_cmd cdb; 3959a4aa671eSarutz struct dk_devid *dkdevid; 3960a4aa671eSarutz uint_t *ip; 3961a4aa671eSarutz int chksum; 3962a4aa671eSarutz int i, sz; 3963a4aa671eSarutz dev_t dev; 3964a4aa671eSarutz 3965a4aa671eSarutz mutex_exit(DCD_MUTEX); 3966a4aa671eSarutz if (cmlb_get_devid_block(un->un_dklbhandle, &blk, 0)) { 3967a4aa671eSarutz mutex_enter(DCD_MUTEX); 3968a4aa671eSarutz return (EINVAL); 3969a4aa671eSarutz } 3970a4aa671eSarutz mutex_enter(DCD_MUTEX); 3971a4aa671eSarutz 3972a4aa671eSarutz dkdevid = kmem_alloc(un->un_secsize, KM_SLEEP); 3973a4aa671eSarutz 3974a4aa671eSarutz (void) bzero((caddr_t)&ucmd, sizeof (ucmd)); 3975a4aa671eSarutz (void) bzero((caddr_t)&cdb, sizeof (cdb)); 3976a4aa671eSarutz 3977a4aa671eSarutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) { 3978a4aa671eSarutz cdb.cmd = ATA_READ_DMA; 3979a4aa671eSarutz } else { 3980a4aa671eSarutz if (un->un_dp->options & BLOCK_MODE) 3981a4aa671eSarutz cdb.cmd = ATA_READ_MULTIPLE; 3982a4aa671eSarutz else 3983a4aa671eSarutz cdb.cmd = ATA_READ; 3984a4aa671eSarutz } 3985a4aa671eSarutz cdb.size = un->un_secsize; 3986a4aa671eSarutz cdb.sector_num.lba_num = blk; 3987a4aa671eSarutz cdb.address_mode = ADD_LBA_MODE; 3988a4aa671eSarutz cdb.direction = DATA_READ; 3989a4aa671eSarutz 3990a4aa671eSarutz ucmd.udcd_flags = UDCD_READ; 3991a4aa671eSarutz ucmd.udcd_cmd = &cdb; 3992a4aa671eSarutz ucmd.udcd_bufaddr = (caddr_t)dkdevid; 3993a4aa671eSarutz ucmd.udcd_buflen = un->un_secsize; 3994a4aa671eSarutz ucmd.udcd_flags |= UDCD_SILENT; 3995a4aa671eSarutz dev = makedevice(ddi_driver_major(DCD_DEVINFO), 3996a4aa671eSarutz ddi_get_instance(DCD_DEVINFO) << DCDUNIT_SHIFT); 3997a4aa671eSarutz mutex_exit(DCD_MUTEX); 3998a4aa671eSarutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE); 3999a4aa671eSarutz mutex_enter(DCD_MUTEX); 4000a4aa671eSarutz 4001a4aa671eSarutz if (status != 0) { 4002a4aa671eSarutz kmem_free((caddr_t)dkdevid, un->un_secsize); 4003a4aa671eSarutz return (status); 4004a4aa671eSarutz } 4005a4aa671eSarutz 4006a4aa671eSarutz /* Validate the revision */ 4007a4aa671eSarutz 4008a4aa671eSarutz if ((dkdevid->dkd_rev_hi != DK_DEVID_REV_MSB) || 4009a4aa671eSarutz (dkdevid->dkd_rev_lo != DK_DEVID_REV_LSB)) { 4010a4aa671eSarutz kmem_free((caddr_t)dkdevid, un->un_secsize); 4011a4aa671eSarutz return (EINVAL); 4012a4aa671eSarutz } 4013a4aa671eSarutz 4014a4aa671eSarutz /* Calculate the checksum */ 4015a4aa671eSarutz chksum = 0; 4016a4aa671eSarutz ip = (uint_t *)dkdevid; 4017a4aa671eSarutz for (i = 0; i < ((un->un_secsize - sizeof (int))/sizeof (int)); i++) 4018a4aa671eSarutz chksum ^= ip[i]; 4019a4aa671eSarutz 4020a4aa671eSarutz /* Compare the checksums */ 4021a4aa671eSarutz 4022a4aa671eSarutz if (DKD_GETCHKSUM(dkdevid) != chksum) { 4023a4aa671eSarutz kmem_free((caddr_t)dkdevid, un->un_secsize); 4024a4aa671eSarutz return (EINVAL); 4025a4aa671eSarutz } 4026a4aa671eSarutz 4027a4aa671eSarutz /* VAlidate the device id */ 4028a4aa671eSarutz if (ddi_devid_valid((ddi_devid_t)&dkdevid->dkd_devid) != DDI_SUCCESS) { 4029a4aa671eSarutz kmem_free((caddr_t)dkdevid, un->un_secsize); 4030a4aa671eSarutz return (EINVAL); 4031a4aa671eSarutz } 4032a4aa671eSarutz 4033a4aa671eSarutz /* return a copy of the device id */ 4034a4aa671eSarutz sz = ddi_devid_sizeof((ddi_devid_t)&dkdevid->dkd_devid); 4035a4aa671eSarutz un->un_devid = (ddi_devid_t)kmem_alloc(sz, KM_SLEEP); 4036a4aa671eSarutz bcopy(&dkdevid->dkd_devid, un->un_devid, sz); 4037a4aa671eSarutz kmem_free((caddr_t)dkdevid, un->un_secsize); 4038a4aa671eSarutz 4039a4aa671eSarutz return (0); 4040a4aa671eSarutz } 4041a4aa671eSarutz 4042a4aa671eSarutz /* 4043a4aa671eSarutz * Return the device id for the device. 4044a4aa671eSarutz * 1. If the device ID exists then just return it - nothing to do in that case. 4045a4aa671eSarutz * 2. Build one from the drives model number and serial number. 4046a4aa671eSarutz * 3. If there is a problem in building it from serial/model #, then try 4047a4aa671eSarutz * to read it from the acyl region of the disk. 4048a4aa671eSarutz * Note: If this function is unable to return a valid ID then the calling 4049a4aa671eSarutz * point will invoke the routine to create a fabricated ID ans stor it on the 4050a4aa671eSarutz * acyl region of the disk. 4051a4aa671eSarutz */ 4052a4aa671eSarutz static ddi_devid_t 4053a4aa671eSarutz dcd_get_devid(struct dcd_disk *un) 4054a4aa671eSarutz { 4055a4aa671eSarutz int rc; 4056a4aa671eSarutz 4057a4aa671eSarutz /* If already registered, return that value */ 4058a4aa671eSarutz if (un->un_devid != NULL) 4059a4aa671eSarutz return (un->un_devid); 4060a4aa671eSarutz 4061a4aa671eSarutz /* Build a devid from model and serial number, if present */ 4062a4aa671eSarutz rc = dcd_make_devid_from_serial(un); 4063a4aa671eSarutz 4064a4aa671eSarutz if (rc != DDI_SUCCESS) { 4065a4aa671eSarutz /* Read the devid from the disk. */ 4066a4aa671eSarutz if (dcd_read_deviceid(un)) 4067a4aa671eSarutz return (NULL); 4068a4aa671eSarutz } 4069a4aa671eSarutz 4070a4aa671eSarutz (void) ddi_devid_register(DCD_DEVINFO, un->un_devid); 4071a4aa671eSarutz return (un->un_devid); 4072a4aa671eSarutz } 4073a4aa671eSarutz 4074a4aa671eSarutz 4075a4aa671eSarutz static ddi_devid_t 4076a4aa671eSarutz dcd_create_devid(struct dcd_disk *un) 4077a4aa671eSarutz { 4078a4aa671eSarutz if (ddi_devid_init(DCD_DEVINFO, DEVID_FAB, 0, NULL, (ddi_devid_t *) 4079a4aa671eSarutz &un->un_devid) == DDI_FAILURE) 4080a4aa671eSarutz return (NULL); 4081a4aa671eSarutz 4082a4aa671eSarutz if (dcd_write_deviceid(un)) { 4083a4aa671eSarutz ddi_devid_free(un->un_devid); 4084a4aa671eSarutz un->un_devid = NULL; 4085a4aa671eSarutz return (NULL); 4086a4aa671eSarutz } 4087a4aa671eSarutz 4088a4aa671eSarutz (void) ddi_devid_register(DCD_DEVINFO, un->un_devid); 4089a4aa671eSarutz return (un->un_devid); 4090a4aa671eSarutz } 4091a4aa671eSarutz 4092a4aa671eSarutz /* 4093a4aa671eSarutz * Build a devid from the model and serial number, if present 4094a4aa671eSarutz * Return DDI_SUCCESS or DDI_FAILURE. 4095a4aa671eSarutz */ 4096a4aa671eSarutz static int 4097a4aa671eSarutz dcd_make_devid_from_serial(struct dcd_disk *un) 4098a4aa671eSarutz { 4099a4aa671eSarutz int rc = DDI_SUCCESS; 4100a4aa671eSarutz char *hwid; 4101a4aa671eSarutz char *model; 4102a4aa671eSarutz int model_len; 4103a4aa671eSarutz char *serno; 4104a4aa671eSarutz int serno_len; 4105a4aa671eSarutz int total_len; 4106a4aa671eSarutz 4107a4aa671eSarutz /* initialize the model and serial number information */ 4108a4aa671eSarutz model = un->un_dcd->dcd_ident->dcd_model; 4109a4aa671eSarutz model_len = DCD_MODEL_NUMBER_LENGTH; 4110a4aa671eSarutz serno = un->un_dcd->dcd_ident->dcd_drvser; 4111a4aa671eSarutz serno_len = DCD_SERIAL_NUMBER_LENGTH; 4112a4aa671eSarutz 4113a4aa671eSarutz /* Verify the model and serial number */ 4114a4aa671eSarutz dcd_validate_model_serial(model, &model_len, model_len); 4115a4aa671eSarutz if (model_len == 0) { 4116a4aa671eSarutz rc = DDI_FAILURE; 4117a4aa671eSarutz goto out; 4118a4aa671eSarutz } 4119a4aa671eSarutz dcd_validate_model_serial(serno, &serno_len, serno_len); 4120a4aa671eSarutz if (serno_len == 0) { 4121a4aa671eSarutz rc = DDI_FAILURE; 4122a4aa671eSarutz goto out; 4123a4aa671eSarutz } 4124a4aa671eSarutz 4125a4aa671eSarutz /* 4126a4aa671eSarutz * The device ID will be concatenation of the model number, 4127a4aa671eSarutz * the '=' separator, the serial number. Allocate 4128a4aa671eSarutz * the string and concatenate the components. 4129a4aa671eSarutz */ 4130a4aa671eSarutz total_len = model_len + 1 + serno_len; 4131a4aa671eSarutz hwid = kmem_alloc(total_len, KM_SLEEP); 4132a4aa671eSarutz bcopy((caddr_t)model, (caddr_t)hwid, model_len); 4133a4aa671eSarutz bcopy((caddr_t)"=", (caddr_t)&hwid[model_len], 1); 4134a4aa671eSarutz bcopy((caddr_t)serno, (caddr_t)&hwid[model_len + 1], serno_len); 4135a4aa671eSarutz 4136a4aa671eSarutz /* Initialize the device ID, trailing NULL not included */ 4137a4aa671eSarutz rc = ddi_devid_init(DCD_DEVINFO, DEVID_ATA_SERIAL, total_len, 4138a4aa671eSarutz hwid, (ddi_devid_t *)&un->un_devid); 4139a4aa671eSarutz 4140a4aa671eSarutz /* Free the allocated string */ 4141a4aa671eSarutz kmem_free(hwid, total_len); 4142a4aa671eSarutz 4143a4aa671eSarutz out: return (rc); 4144a4aa671eSarutz } 4145a4aa671eSarutz 4146a4aa671eSarutz /* 4147a4aa671eSarutz * Test for a valid model or serial number. Assume that a valid representation 4148a4aa671eSarutz * contains at least one character that is neither a space, 0 digit, or NULL. 4149a4aa671eSarutz * Trim trailing blanks and NULLS from returned length. 4150a4aa671eSarutz */ 4151a4aa671eSarutz static void 4152a4aa671eSarutz dcd_validate_model_serial(char *str, int *retlen, int totallen) 4153a4aa671eSarutz { 4154a4aa671eSarutz char ch; 4155a4aa671eSarutz boolean_t ret = B_FALSE; 4156a4aa671eSarutz int i; 4157a4aa671eSarutz int tb; 4158a4aa671eSarutz 4159a4aa671eSarutz for (i = 0, tb = 0; i < totallen; i++) { 4160a4aa671eSarutz ch = *str++; 4161a4aa671eSarutz if ((ch != ' ') && (ch != '\0') && (ch != '0')) 4162a4aa671eSarutz ret = B_TRUE; 4163a4aa671eSarutz if ((ch == ' ') || (ch == '\0')) 4164a4aa671eSarutz tb++; 4165a4aa671eSarutz else 4166a4aa671eSarutz tb = 0; 4167a4aa671eSarutz } 4168a4aa671eSarutz 4169a4aa671eSarutz if (ret == B_TRUE) { 4170a4aa671eSarutz /* Atleast one non 0 or blank character. */ 4171a4aa671eSarutz *retlen = totallen - tb; 4172a4aa671eSarutz } else { 4173a4aa671eSarutz *retlen = 0; 4174a4aa671eSarutz } 4175a4aa671eSarutz } 4176a4aa671eSarutz 4177a4aa671eSarutz #ifndef lint 4178a4aa671eSarutz void 4179a4aa671eSarutz clean_print(dev_info_t *dev, char *label, uint_t level, 4180a4aa671eSarutz char *title, char *data, int len) 4181a4aa671eSarutz { 4182a4aa671eSarutz int i; 4183a4aa671eSarutz char buf[256]; 4184a4aa671eSarutz 4185a4aa671eSarutz (void) sprintf(buf, "%s:", title); 4186a4aa671eSarutz for (i = 0; i < len; i++) { 4187a4aa671eSarutz (void) sprintf(&buf[strlen(buf)], "0x%x ", (data[i] & 0xff)); 4188a4aa671eSarutz } 4189a4aa671eSarutz (void) sprintf(&buf[strlen(buf)], "\n"); 4190a4aa671eSarutz 4191a4aa671eSarutz dcd_log(dev, label, level, "%s", buf); 4192a4aa671eSarutz } 4193a4aa671eSarutz #endif /* Not lint */ 4194a4aa671eSarutz 4195a4aa671eSarutz #ifndef lint 4196a4aa671eSarutz /* 4197a4aa671eSarutz * Print a piece of inquiry data- cleaned up for non-printable characters 4198a4aa671eSarutz * and stopping at the first space character after the beginning of the 4199a4aa671eSarutz * passed string; 4200a4aa671eSarutz */ 4201a4aa671eSarutz 4202a4aa671eSarutz void 4203a4aa671eSarutz inq_fill(char *p, int l, char *s) 4204a4aa671eSarutz { 4205a4aa671eSarutz unsigned i = 0; 4206a4aa671eSarutz char c; 4207a4aa671eSarutz 4208a4aa671eSarutz while (i++ < l) { 4209a4aa671eSarutz if ((c = *p++) < ' ' || c >= 0177) { 4210a4aa671eSarutz c = '*'; 4211a4aa671eSarutz } else if (i != 1 && c == ' ') { 4212a4aa671eSarutz break; 4213a4aa671eSarutz } 4214a4aa671eSarutz *s++ = c; 4215a4aa671eSarutz } 4216a4aa671eSarutz *s++ = 0; 4217a4aa671eSarutz } 4218a4aa671eSarutz #endif /* Not lint */ 4219a4aa671eSarutz 4220a4aa671eSarutz char * 4221a4aa671eSarutz dcd_sname(uchar_t status) 4222a4aa671eSarutz { 4223a4aa671eSarutz switch (status & STATUS_ATA_MASK) { 4224a4aa671eSarutz case STATUS_GOOD: 4225a4aa671eSarutz return ("good status"); 4226a4aa671eSarutz 4227a4aa671eSarutz case STATUS_ATA_BUSY: 4228a4aa671eSarutz return ("busy"); 4229a4aa671eSarutz 4230a4aa671eSarutz default: 4231a4aa671eSarutz return ("<unknown status>"); 4232a4aa671eSarutz } 4233a4aa671eSarutz } 4234a4aa671eSarutz 4235a4aa671eSarutz /* ARGSUSED0 */ 4236a4aa671eSarutz char * 4237a4aa671eSarutz dcd_rname(int reason) 4238a4aa671eSarutz { 4239a4aa671eSarutz static char *rnames[] = { 4240a4aa671eSarutz "cmplt", 4241a4aa671eSarutz "incomplete", 4242a4aa671eSarutz "dma_derr", 4243a4aa671eSarutz "tran_err", 4244a4aa671eSarutz "reset", 4245a4aa671eSarutz "aborted", 4246a4aa671eSarutz "timeout", 4247a4aa671eSarutz "data_ovr", 4248a4aa671eSarutz }; 4249a4aa671eSarutz if (reason > CMD_DATA_OVR) { 4250a4aa671eSarutz return ("<unknown reason>"); 4251a4aa671eSarutz } else { 4252a4aa671eSarutz return (rnames[reason]); 4253a4aa671eSarutz } 4254a4aa671eSarutz } 4255a4aa671eSarutz 4256a4aa671eSarutz 4257a4aa671eSarutz 4258a4aa671eSarutz /* ARGSUSED0 */ 4259a4aa671eSarutz int 4260a4aa671eSarutz dcd_check_wp(dev_t dev) 4261a4aa671eSarutz { 4262a4aa671eSarutz 4263a4aa671eSarutz return (0); 4264a4aa671eSarutz } 4265a4aa671eSarutz 4266a4aa671eSarutz /* 4267a4aa671eSarutz * Create device error kstats 4268a4aa671eSarutz */ 4269a4aa671eSarutz static int 4270a4aa671eSarutz dcd_create_errstats(struct dcd_disk *un, int instance) 4271a4aa671eSarutz { 4272a4aa671eSarutz 4273a4aa671eSarutz char kstatname[KSTAT_STRLEN]; 4274a4aa671eSarutz 4275a4aa671eSarutz if (un->un_errstats == (kstat_t *)0) { 4276a4aa671eSarutz (void) sprintf(kstatname, "dad%d,error", instance); 4277a4aa671eSarutz un->un_errstats = kstat_create("daderror", instance, kstatname, 4278a4aa671eSarutz "device_error", KSTAT_TYPE_NAMED, 4279a4aa671eSarutz sizeof (struct dcd_errstats)/ sizeof (kstat_named_t), 4280a4aa671eSarutz KSTAT_FLAG_PERSISTENT); 4281a4aa671eSarutz 4282a4aa671eSarutz if (un->un_errstats) { 4283a4aa671eSarutz struct dcd_errstats *dtp; 4284a4aa671eSarutz 4285a4aa671eSarutz dtp = (struct dcd_errstats *)un->un_errstats->ks_data; 4286a4aa671eSarutz kstat_named_init(&dtp->dcd_softerrs, "Soft Errors", 4287a4aa671eSarutz KSTAT_DATA_UINT32); 4288a4aa671eSarutz kstat_named_init(&dtp->dcd_harderrs, "Hard Errors", 4289a4aa671eSarutz KSTAT_DATA_UINT32); 4290a4aa671eSarutz kstat_named_init(&dtp->dcd_transerrs, 4291a4aa671eSarutz "Transport Errors", KSTAT_DATA_UINT32); 4292a4aa671eSarutz kstat_named_init(&dtp->dcd_model, "Model", 4293a4aa671eSarutz KSTAT_DATA_CHAR); 4294a4aa671eSarutz kstat_named_init(&dtp->dcd_revision, "Revision", 4295a4aa671eSarutz KSTAT_DATA_CHAR); 4296a4aa671eSarutz kstat_named_init(&dtp->dcd_serial, "Serial No", 4297a4aa671eSarutz KSTAT_DATA_CHAR); 4298a4aa671eSarutz kstat_named_init(&dtp->dcd_capacity, "Size", 4299a4aa671eSarutz KSTAT_DATA_ULONGLONG); 4300a4aa671eSarutz kstat_named_init(&dtp->dcd_rq_media_err, "Media Error", 4301a4aa671eSarutz KSTAT_DATA_UINT32); 4302a4aa671eSarutz kstat_named_init(&dtp->dcd_rq_ntrdy_err, 4303a4aa671eSarutz "Device Not Ready", KSTAT_DATA_UINT32); 4304a4aa671eSarutz kstat_named_init(&dtp->dcd_rq_nodev_err, " No Device", 4305a4aa671eSarutz KSTAT_DATA_UINT32); 4306a4aa671eSarutz kstat_named_init(&dtp->dcd_rq_recov_err, "Recoverable", 4307a4aa671eSarutz KSTAT_DATA_UINT32); 4308a4aa671eSarutz kstat_named_init(&dtp->dcd_rq_illrq_err, 4309a4aa671eSarutz "Illegal Request", KSTAT_DATA_UINT32); 4310a4aa671eSarutz 4311a4aa671eSarutz un->un_errstats->ks_private = un; 4312a4aa671eSarutz un->un_errstats->ks_update = nulldev; 4313a4aa671eSarutz kstat_install(un->un_errstats); 4314a4aa671eSarutz 4315a4aa671eSarutz (void) strncpy(&dtp->dcd_model.value.c[0], 4316a4aa671eSarutz un->un_dcd->dcd_ident->dcd_model, 16); 4317a4aa671eSarutz (void) strncpy(&dtp->dcd_serial.value.c[0], 4318a4aa671eSarutz un->un_dcd->dcd_ident->dcd_drvser, 16); 4319a4aa671eSarutz (void) strncpy(&dtp->dcd_revision.value.c[0], 4320a4aa671eSarutz un->un_dcd->dcd_ident->dcd_fw, 8); 4321a4aa671eSarutz dtp->dcd_capacity.value.ui64 = 4322a4aa671eSarutz (uint64_t)((uint64_t)un->un_diskcapacity * 4323a4aa671eSarutz (uint64_t)un->un_lbasize); 4324a4aa671eSarutz } 4325a4aa671eSarutz } 4326a4aa671eSarutz return (0); 4327a4aa671eSarutz } 4328a4aa671eSarutz 4329a4aa671eSarutz 4330a4aa671eSarutz /* 4331a4aa671eSarutz * This has been moved from DADA layer as this does not do anything other than 4332a4aa671eSarutz * retrying the command when it is busy or it does not complete 4333a4aa671eSarutz */ 4334a4aa671eSarutz int 4335a4aa671eSarutz dcd_poll(struct dcd_pkt *pkt) 4336a4aa671eSarutz { 4337a4aa671eSarutz int busy_count, rval = -1, savef; 4338a4aa671eSarutz clock_t savet; 4339a4aa671eSarutz void (*savec)(); 4340a4aa671eSarutz 4341a4aa671eSarutz 4342a4aa671eSarutz /* 4343a4aa671eSarutz * Save old flags 4344a4aa671eSarutz */ 4345a4aa671eSarutz savef = pkt->pkt_flags; 4346a4aa671eSarutz savec = pkt->pkt_comp; 4347a4aa671eSarutz savet = pkt->pkt_time; 4348a4aa671eSarutz 4349a4aa671eSarutz pkt->pkt_flags |= FLAG_NOINTR; 4350a4aa671eSarutz 4351a4aa671eSarutz 4352a4aa671eSarutz /* 4353a4aa671eSarutz * Set the Pkt_comp to NULL 4354a4aa671eSarutz */ 4355a4aa671eSarutz 4356a4aa671eSarutz pkt->pkt_comp = 0; 4357a4aa671eSarutz 4358a4aa671eSarutz /* 4359a4aa671eSarutz * Set the Pkt time for the polled command 4360a4aa671eSarutz */ 4361a4aa671eSarutz if (pkt->pkt_time == 0) { 4362a4aa671eSarutz pkt->pkt_time = DCD_POLL_TIMEOUT; 4363a4aa671eSarutz } 4364a4aa671eSarutz 4365a4aa671eSarutz 4366a4aa671eSarutz /* Now transport the command */ 4367a4aa671eSarutz for (busy_count = 0; busy_count < dcd_poll_busycnt; busy_count++) { 4368a4aa671eSarutz if ((rval = dcd_transport(pkt)) == TRAN_ACCEPT) { 4369a4aa671eSarutz if (pkt->pkt_reason == CMD_INCOMPLETE && 4370a4aa671eSarutz pkt->pkt_state == 0) { 4371a4aa671eSarutz delay(100); 4372a4aa671eSarutz } else if (pkt->pkt_reason == CMD_CMPLT) { 4373a4aa671eSarutz rval = 0; 4374a4aa671eSarutz break; 4375a4aa671eSarutz } 4376a4aa671eSarutz } 4377a4aa671eSarutz if (rval == TRAN_BUSY) { 4378a4aa671eSarutz delay(100); 4379a4aa671eSarutz continue; 4380a4aa671eSarutz } 4381a4aa671eSarutz } 4382a4aa671eSarutz 4383a4aa671eSarutz pkt->pkt_flags = savef; 4384a4aa671eSarutz pkt->pkt_comp = savec; 4385a4aa671eSarutz pkt->pkt_time = savet; 4386a4aa671eSarutz return (rval); 4387a4aa671eSarutz } 4388a4aa671eSarutz 4389a4aa671eSarutz 4390a4aa671eSarutz void 4391a4aa671eSarutz dcd_translate(struct dadkio_status32 *statp, struct udcd_cmd *cmdp) 4392a4aa671eSarutz { 4393a4aa671eSarutz if (cmdp->udcd_status_reg & STATUS_ATA_BUSY) 4394a4aa671eSarutz statp->status = DADKIO_STAT_NOT_READY; 4395a4aa671eSarutz else if (cmdp->udcd_status_reg & STATUS_ATA_DWF) 4396a4aa671eSarutz statp->status = DADKIO_STAT_HARDWARE_ERROR; 4397a4aa671eSarutz else if (cmdp->udcd_status_reg & STATUS_ATA_CORR) 4398a4aa671eSarutz statp->status = DADKIO_STAT_SOFT_ERROR; 4399a4aa671eSarutz else if (cmdp->udcd_status_reg & STATUS_ATA_ERR) { 4400a4aa671eSarutz /* 4401a4aa671eSarutz * The error register is valid only when BSY and DRQ not set 4402a4aa671eSarutz * Assumed that HBA has checked this before it gives the data 4403a4aa671eSarutz */ 4404a4aa671eSarutz if (cmdp->udcd_error_reg & ERR_AMNF) 4405a4aa671eSarutz statp->status = DADKIO_STAT_NOT_FORMATTED; 4406a4aa671eSarutz else if (cmdp->udcd_error_reg & ERR_TKONF) 4407a4aa671eSarutz statp->status = DADKIO_STAT_NOT_FORMATTED; 4408a4aa671eSarutz else if (cmdp->udcd_error_reg & ERR_ABORT) 4409a4aa671eSarutz statp->status = DADKIO_STAT_ILLEGAL_REQUEST; 4410a4aa671eSarutz else if (cmdp->udcd_error_reg & ERR_IDNF) 4411a4aa671eSarutz statp->status = DADKIO_STAT_NOT_FORMATTED; 4412a4aa671eSarutz else if (cmdp->udcd_error_reg & ERR_UNC) 4413a4aa671eSarutz statp->status = DADKIO_STAT_BUS_ERROR; 4414a4aa671eSarutz else if (cmdp->udcd_error_reg & ERR_BBK) 4415a4aa671eSarutz statp->status = DADKIO_STAT_MEDIUM_ERROR; 4416a4aa671eSarutz } else 4417a4aa671eSarutz statp->status = DADKIO_STAT_NO_ERROR; 4418a4aa671eSarutz } 4419a4aa671eSarutz 4420a4aa671eSarutz static void 4421a4aa671eSarutz dcd_flush_cache(struct dcd_disk *un) 4422a4aa671eSarutz { 4423a4aa671eSarutz struct dcd_pkt *pkt; 4424a4aa671eSarutz int retry_count; 4425a4aa671eSarutz 4426a4aa671eSarutz 4427a4aa671eSarutz if ((pkt = dcd_init_pkt(ROUTE, NULL, NULL, 4428a4aa671eSarutz (uint32_t)sizeof (struct dcd_cmd), 2, PP_LEN, 4429a4aa671eSarutz PKT_CONSISTENT, NULL_FUNC, NULL)) == NULL) { 4430a4aa671eSarutz return; 4431a4aa671eSarutz } 4432a4aa671eSarutz 4433a4aa671eSarutz makecommand(pkt, 0, ATA_FLUSH_CACHE, 0, ADD_LBA_MODE, 0, 4434a4aa671eSarutz NO_DATA_XFER, 0); 4435a4aa671eSarutz 4436a4aa671eSarutz /* 4437a4aa671eSarutz * Send the command. There are chances it might fail on some 4438a4aa671eSarutz * disks since it is not a mandatory command as per ata-4. Try 4439a4aa671eSarutz * 3 times if it fails. The retry count has been randomly selected. 4440a4aa671eSarutz * There is a need for retry since as per the spec FLUSH CACHE can fail 4441a4aa671eSarutz * as a result of unrecoverable error encountered during execution 4442a4aa671eSarutz * of writing data and subsequent command should continue flushing 4443a4aa671eSarutz * cache. 4444a4aa671eSarutz */ 4445a4aa671eSarutz for (retry_count = 0; retry_count < 3; retry_count++) { 4446a4aa671eSarutz /* 4447a4aa671eSarutz * Set the packet fields. 4448a4aa671eSarutz */ 4449a4aa671eSarutz pkt->pkt_comp = 0; 4450a4aa671eSarutz pkt->pkt_time = DCD_POLL_TIMEOUT; 4451a4aa671eSarutz pkt->pkt_flags |= FLAG_FORCENOINTR; 4452a4aa671eSarutz pkt->pkt_flags |= FLAG_NOINTR; 4453a4aa671eSarutz if (dcd_transport(pkt) == TRAN_ACCEPT) { 4454a4aa671eSarutz if (pkt->pkt_reason == CMD_CMPLT) { 4455a4aa671eSarutz break; 4456a4aa671eSarutz } 4457a4aa671eSarutz } 4458a4aa671eSarutz /* 4459a4aa671eSarutz * Note the wait time value of 100ms is same as in the 4460a4aa671eSarutz * dcd_poll routine. 4461a4aa671eSarutz */ 4462a4aa671eSarutz drv_usecwait(1000000); 4463a4aa671eSarutz } 4464a4aa671eSarutz (void) dcd_destroy_pkt(pkt); 4465a4aa671eSarutz } 4466a4aa671eSarutz 4467a4aa671eSarutz static int 4468a4aa671eSarutz dcd_send_lb_rw_cmd(dev_info_t *devi, void *bufaddr, 4469a4aa671eSarutz diskaddr_t start_block, size_t reqlength, uchar_t cmd) 4470a4aa671eSarutz { 4471a4aa671eSarutz struct dcd_pkt *pkt; 4472a4aa671eSarutz struct buf *bp; 4473a4aa671eSarutz diskaddr_t real_addr = start_block; 4474a4aa671eSarutz size_t buffer_size = reqlength; 4475a4aa671eSarutz uchar_t command, tmp; 4476a4aa671eSarutz int i, rval = 0; 4477a4aa671eSarutz struct dcd_disk *un; 4478a4aa671eSarutz 4479a4aa671eSarutz un = ddi_get_soft_state(dcd_state, ddi_get_instance(devi)); 4480a4aa671eSarutz if (un == NULL) 4481a4aa671eSarutz return (ENXIO); 4482a4aa671eSarutz 4483a4aa671eSarutz bp = dcd_alloc_consistent_buf(ROUTE, (struct buf *)NULL, 4484a4aa671eSarutz buffer_size, B_READ, NULL_FUNC, NULL); 4485a4aa671eSarutz if (!bp) { 4486a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 4487a4aa671eSarutz "no bp for disk label\n"); 4488a4aa671eSarutz return (ENOMEM); 4489a4aa671eSarutz } 4490a4aa671eSarutz 4491a4aa671eSarutz pkt = dcd_init_pkt(ROUTE, (struct dcd_pkt *)NULL, 4492a4aa671eSarutz bp, (uint32_t)sizeof (struct dcd_cmd), 2, PP_LEN, 4493a4aa671eSarutz PKT_CONSISTENT, NULL_FUNC, NULL); 4494a4aa671eSarutz 4495a4aa671eSarutz if (!pkt) { 4496a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 4497a4aa671eSarutz "no memory for disk label\n"); 4498a4aa671eSarutz dcd_free_consistent_buf(bp); 4499a4aa671eSarutz return (ENOMEM); 4500a4aa671eSarutz } 4501a4aa671eSarutz 4502a4aa671eSarutz if (cmd == TG_READ) { 4503a4aa671eSarutz bzero(bp->b_un.b_addr, buffer_size); 4504a4aa671eSarutz tmp = DATA_READ; 4505a4aa671eSarutz } else { 4506a4aa671eSarutz bcopy((caddr_t)bufaddr, bp->b_un.b_addr, buffer_size); 4507a4aa671eSarutz tmp = DATA_WRITE; 4508a4aa671eSarutz } 4509a4aa671eSarutz 4510a4aa671eSarutz mutex_enter(DCD_MUTEX); 4511a4aa671eSarutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) { 4512a4aa671eSarutz if (cmd == TG_READ) { 4513a4aa671eSarutz command = ATA_READ_DMA; 4514a4aa671eSarutz } else { 4515a4aa671eSarutz command = ATA_WRITE_DMA; 4516a4aa671eSarutz } 4517a4aa671eSarutz } else { 4518a4aa671eSarutz if (cmd == TG_READ) { 4519a4aa671eSarutz if (un->un_dp->options & BLOCK_MODE) 4520a4aa671eSarutz command = ATA_READ_MULTIPLE; 4521a4aa671eSarutz else 4522a4aa671eSarutz command = ATA_READ; 4523a4aa671eSarutz } else { 4524a4aa671eSarutz if (un->un_dp->options & BLOCK_MODE) 4525a4aa671eSarutz command = ATA_READ_MULTIPLE; 4526a4aa671eSarutz else 4527a4aa671eSarutz command = ATA_WRITE; 4528a4aa671eSarutz } 4529a4aa671eSarutz } 4530a4aa671eSarutz mutex_exit(DCD_MUTEX); 4531a4aa671eSarutz (void) makecommand(pkt, 0, command, real_addr, ADD_LBA_MODE, 4532a4aa671eSarutz buffer_size, tmp, 0); 4533a4aa671eSarutz 4534a4aa671eSarutz for (i = 0; i < 3; i++) { 4535a4aa671eSarutz if (dcd_poll(pkt) || SCBP_C(pkt) != STATUS_GOOD || 4536a4aa671eSarutz (pkt->pkt_state & STATE_XFERRED_DATA) == 0 || 4537a4aa671eSarutz (pkt->pkt_resid != 0)) { 4538a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 4539a4aa671eSarutz "Status %x, state %x, resid %lx\n", 4540a4aa671eSarutz SCBP_C(pkt), pkt->pkt_state, pkt->pkt_resid); 4541a4aa671eSarutz rval = EIO; 4542a4aa671eSarutz } else { 4543a4aa671eSarutz break; 4544a4aa671eSarutz } 4545a4aa671eSarutz } 4546a4aa671eSarutz 4547a4aa671eSarutz if (rval != 0) { 4548a4aa671eSarutz dcd_destroy_pkt(pkt); 4549a4aa671eSarutz dcd_free_consistent_buf(bp); 4550a4aa671eSarutz return (EIO); 4551a4aa671eSarutz } 4552a4aa671eSarutz 4553a4aa671eSarutz if (cmd == TG_READ) { 4554a4aa671eSarutz bcopy(bp->b_un.b_addr, bufaddr, reqlength); 4555a4aa671eSarutz rval = 0; 4556a4aa671eSarutz } 4557a4aa671eSarutz 4558a4aa671eSarutz dcd_destroy_pkt(pkt); 4559a4aa671eSarutz dcd_free_consistent_buf(bp); 4560a4aa671eSarutz return (rval); 4561a4aa671eSarutz } 4562a4aa671eSarutz 4563a4aa671eSarutz static int dcd_compute_dk_capacity(struct dcd_device *devp, 4564a4aa671eSarutz diskaddr_t *capacity) 4565a4aa671eSarutz { 4566a4aa671eSarutz diskaddr_t cap; 4567a4aa671eSarutz diskaddr_t no_of_lbasec; 4568a4aa671eSarutz 4569a4aa671eSarutz cap = devp->dcd_ident->dcd_fixcyls * 4570a4aa671eSarutz devp->dcd_ident->dcd_heads * 4571a4aa671eSarutz devp->dcd_ident->dcd_sectors; 4572a4aa671eSarutz no_of_lbasec = devp->dcd_ident->dcd_addrsec[1]; 4573a4aa671eSarutz no_of_lbasec = no_of_lbasec << 16; 4574a4aa671eSarutz no_of_lbasec = no_of_lbasec | devp->dcd_ident->dcd_addrsec[0]; 4575a4aa671eSarutz 4576a4aa671eSarutz if (no_of_lbasec > cap) { 4577a4aa671eSarutz cap = no_of_lbasec; 4578a4aa671eSarutz } 4579a4aa671eSarutz 4580a4aa671eSarutz if (cap != ((uint32_t)-1)) 4581a4aa671eSarutz *capacity = cap; 4582a4aa671eSarutz else 4583a4aa671eSarutz return (EINVAL); 4584a4aa671eSarutz return (0); 4585a4aa671eSarutz } 4586a4aa671eSarutz 4587a4aa671eSarutz /*ARGSUSED5*/ 4588a4aa671eSarutz static int 4589a4aa671eSarutz dcd_lb_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr, 4590a4aa671eSarutz diskaddr_t start_block, size_t reqlength, void *tg_cookie) 4591a4aa671eSarutz { 4592a4aa671eSarutz if (cmd != TG_READ && cmd != TG_WRITE) 4593a4aa671eSarutz return (EINVAL); 4594a4aa671eSarutz 4595a4aa671eSarutz return (dcd_send_lb_rw_cmd(devi, bufaddr, start_block, 4596a4aa671eSarutz reqlength, cmd)); 4597a4aa671eSarutz } 4598a4aa671eSarutz 4599a4aa671eSarutz static int 4600a4aa671eSarutz dcd_lb_getphygeom(dev_info_t *devi, cmlb_geom_t *phygeomp) 4601a4aa671eSarutz { 4602a4aa671eSarutz struct dcd_device *devp; 4603a4aa671eSarutz uint32_t no_of_lbasec, capacity, calculated_cylinders; 4604a4aa671eSarutz 4605a4aa671eSarutz devp = ddi_get_driver_private(devi); 4606a4aa671eSarutz 4607a4aa671eSarutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) { 4608a4aa671eSarutz if (devp->dcd_ident->dcd_config & ATANON_REMOVABLE) { 4609a4aa671eSarutz phygeomp->g_ncyl = devp->dcd_ident->dcd_fixcyls - 2; 4610a4aa671eSarutz phygeomp->g_acyl = 2; 4611a4aa671eSarutz phygeomp->g_nhead = devp->dcd_ident->dcd_heads; 4612a4aa671eSarutz phygeomp->g_nsect = devp->dcd_ident->dcd_sectors; 4613a4aa671eSarutz 4614a4aa671eSarutz no_of_lbasec = devp->dcd_ident->dcd_addrsec[1]; 4615a4aa671eSarutz no_of_lbasec = no_of_lbasec << 16; 4616a4aa671eSarutz no_of_lbasec = no_of_lbasec | 4617a4aa671eSarutz devp->dcd_ident->dcd_addrsec[0]; 4618a4aa671eSarutz capacity = devp->dcd_ident->dcd_fixcyls * 4619a4aa671eSarutz devp->dcd_ident->dcd_heads * 4620a4aa671eSarutz devp->dcd_ident->dcd_sectors; 4621a4aa671eSarutz if (no_of_lbasec > capacity) { 4622a4aa671eSarutz capacity = no_of_lbasec; 4623a4aa671eSarutz if (capacity > NUM_SECTORS_32G) { 4624a4aa671eSarutz /* 4625a4aa671eSarutz * if the capacity is greater than 32G, 4626a4aa671eSarutz * then 255 is the sectors per track. 4627a4aa671eSarutz * This should be good until 128G disk 4628a4aa671eSarutz * capacity, which is the current ATA-4 4629a4aa671eSarutz * limitation. 4630a4aa671eSarutz */ 4631a4aa671eSarutz phygeomp->g_nsect = 255; 4632a4aa671eSarutz } 4633a4aa671eSarutz 4634a4aa671eSarutz /* 4635a4aa671eSarutz * If the disk capacity is >= 128GB then no. of 4636a4aa671eSarutz * addressable sectors will be set to 0xfffffff 4637a4aa671eSarutz * in the IDENTIFY info. In that case set the 4638a4aa671eSarutz * no. of pcyl to the Max. 16bit value. 4639a4aa671eSarutz */ 4640a4aa671eSarutz 4641a4aa671eSarutz calculated_cylinders = (capacity) / 4642a4aa671eSarutz (phygeomp->g_nhead * phygeomp->g_nsect); 4643a4aa671eSarutz if (calculated_cylinders >= USHRT_MAX) { 4644a4aa671eSarutz phygeomp->g_ncyl = USHRT_MAX - 2; 4645a4aa671eSarutz } else { 4646a4aa671eSarutz phygeomp->g_ncyl = 4647a4aa671eSarutz calculated_cylinders - 2; 4648a4aa671eSarutz } 4649a4aa671eSarutz } 4650a4aa671eSarutz 4651a4aa671eSarutz phygeomp->g_capacity = capacity; 4652a4aa671eSarutz phygeomp->g_intrlv = 0; 4653a4aa671eSarutz phygeomp->g_rpm = 5400; 4654a4aa671eSarutz phygeomp->g_secsize = devp->dcd_ident->dcd_secsiz; 4655a4aa671eSarutz 4656a4aa671eSarutz return (0); 4657a4aa671eSarutz } else 4658a4aa671eSarutz return (ENOTSUP); 4659a4aa671eSarutz } else { 4660a4aa671eSarutz return (EINVAL); 4661a4aa671eSarutz } 4662a4aa671eSarutz } 4663a4aa671eSarutz 4664a4aa671eSarutz 4665a4aa671eSarutz /*ARGSUSED3*/ 4666a4aa671eSarutz static int 4667a4aa671eSarutz dcd_lb_getinfo(dev_info_t *devi, int cmd, void *arg, void *tg_cookie) 4668a4aa671eSarutz { 4669a4aa671eSarutz struct dcd_disk *un; 4670a4aa671eSarutz 4671a4aa671eSarutz un = ddi_get_soft_state(dcd_state, ddi_get_instance(devi)); 4672a4aa671eSarutz 4673a4aa671eSarutz if (un == NULL) 4674a4aa671eSarutz return (ENXIO); 4675a4aa671eSarutz 4676a4aa671eSarutz switch (cmd) { 4677a4aa671eSarutz case TG_GETPHYGEOM: 4678a4aa671eSarutz return (dcd_lb_getphygeom(devi, (cmlb_geom_t *)arg)); 4679a4aa671eSarutz 4680a4aa671eSarutz case TG_GETVIRTGEOM: 4681a4aa671eSarutz return (-1); 4682a4aa671eSarutz 4683a4aa671eSarutz case TG_GETCAPACITY: 4684a4aa671eSarutz case TG_GETBLOCKSIZE: 4685a4aa671eSarutz mutex_enter(DCD_MUTEX); 4686a4aa671eSarutz if (un->un_diskcapacity <= 0) { 4687a4aa671eSarutz mutex_exit(DCD_MUTEX); 4688a4aa671eSarutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, 4689a4aa671eSarutz "invalid disk capacity\n"); 4690a4aa671eSarutz return (EIO); 4691a4aa671eSarutz } 4692a4aa671eSarutz if (cmd == TG_GETCAPACITY) 4693a4aa671eSarutz *(diskaddr_t *)arg = un->un_diskcapacity; 4694a4aa671eSarutz else 4695a4aa671eSarutz *(uint32_t *)arg = DEV_BSIZE; 4696a4aa671eSarutz 4697a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "capacity %x\n", 4698a4aa671eSarutz un->un_diskcapacity); 4699a4aa671eSarutz mutex_exit(DCD_MUTEX); 4700a4aa671eSarutz return (0); 4701a4aa671eSarutz 4702a4aa671eSarutz case TG_GETATTR: 4703a4aa671eSarutz mutex_enter(DCD_MUTEX); 4704a4aa671eSarutz *(tg_attribute_t *)arg = un->un_tgattribute; 4705a4aa671eSarutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, 4706a4aa671eSarutz "media_is_writable %x\n", 4707a4aa671eSarutz un->un_tgattribute.media_is_writable); 4708a4aa671eSarutz mutex_exit(DCD_MUTEX); 4709a4aa671eSarutz return (0); 4710a4aa671eSarutz default: 4711a4aa671eSarutz return (ENOTTY); 4712a4aa671eSarutz } 4713a4aa671eSarutz } 4714