dad.c revision a4aa671e336d5c717aff15808ab91a6bee5e6e41
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * CDDL HEADER START
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * The contents of this file are subject to the terms of the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Common Development and Distribution License (the "License").
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * You may not use this file except in compliance with the License.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * See the License for the specific language governing permissions
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * and limitations under the License.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * When distributing Covered Code, include this CDDL HEADER in each
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If applicable, add the following below this CDDL HEADER, with the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * fields enclosed by brackets "[]" replaced with your own identifying
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * information: Portions Copyright [yyyy] [name of copyright owner]
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * CDDL HEADER END
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Use is subject to license terms.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#pragma ident "%Z%%M% %I% %E% SMI"
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Direct Attached disk driver for SPARC machines.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Includes, Declarations and Local Data
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Global Error Levels for Error Reporting
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Local Static Data
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Local Function Prototypes
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcdopen(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcdclose(dev_t dev, int flag, int otyp, cred_t *cred_p);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcddump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcdioctl(dev_t, int, intptr_t, int, cred_t *, int *);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcdread(dev_t dev, struct uio *uio, cred_t *cred_p);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcdwrite(dev_t dev, struct uio *uio, cred_t *cred_p);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz char *, caddr_t, int *);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcdaread(dev_t dev, struct aio_req *aio, cred_t *cred_p);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcdawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic void dcd_free_softstate(struct dcd_disk *un, dev_info_t *devi);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic ddi_devid_t dcd_create_devid(struct dcd_disk *un);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_make_devid_from_serial(struct dcd_disk *un);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic void dcd_validate_model_serial(char *str, int *retlen, int totallen);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_compute_dk_capacity(struct dcd_device *devp,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_send_lb_rw_cmd(dev_info_t *devinfo, void *bufaddr,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz diskaddr_t start_block, size_t reqlength, uchar_t cmd);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic void dcddone_and_mutex_exit(struct dcd_disk *un, struct buf *bp);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic void make_dcd_cmd(struct dcd_disk *un, struct buf *bp, int (*f)());
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic void dcd_handle_tran_busy(struct buf *bp, struct diskhd *dp,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_handle_incomplete(struct dcd_disk *un, struct buf *bp);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic void dcd_offline(struct dcd_disk *un, int bechatty);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_ready_and_valid(dev_t dev, struct dcd_disk *un);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic void dcd_reset_disk(struct dcd_disk *un, struct dcd_pkt *pkt);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic void dcd_translate(struct dadkio_status32 *statp, struct udcd_cmd *cmdp);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* Function prototypes for cmlb */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_lb_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz diskaddr_t start_block, size_t reqlength, void *tg_cookie);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_lb_getphygeom(dev_info_t *devi, cmlb_geom_t *phygeomp);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_lb_getinfo(dev_info_t *devi, int cmd, void *arg,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Error and Logging Functions
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic void clean_print(dev_info_t *dev, char *label, uint_t level,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#endif /* lint */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_check_error(struct dcd_disk *un, struct buf *bp);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Error statistics create/update functions
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_create_errstats(struct dcd_disk *, int);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/*PRINTFLIKE4*/
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzextern void dcd_log(dev_info_t *, char *, uint_t, const char *, ...)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzextern void makecommand(struct dcd_pkt *, int, uchar_t, uint32_t,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Configuration Routines
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcdinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcdattach(dev_info_t *devi, ddi_attach_cmd_t cmd);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcddetach(dev_info_t *devi, ddi_detach_cmd_t cmd);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcdreset(dev_info_t *dip, ddi_reset_cmd_t cmd);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcdpower(dev_info_t *devi, int component, int level);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic void *dcd_state;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Debugging macros
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcddebug = 0;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#else /* DCDDEBUG */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * we use pkt_private area for storing bp and retry_count
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * XXX: Really is this usefull.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz_NOTE(SCHEME_PROTECTS_DATA("Unique per pkt", dcd_pkt_private buf))
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_bp = bp
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_bp)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_retry_count = n
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_retry_count)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_retry_count += n
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_victim_retry_count \
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_victim_retry_count)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz ((struct dcd_pkt_private *)pkt->pkt_private)->dcdpp_victim_retry_count \
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#define DISK_NOT_READY_RETRY_COUNT (dcd_retry_count / 2)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#define IO_PARTITION_STATS un->un_pstats[DCDPART(bp->b_edev)]
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#define IOSP_PARTITION KSTAT_IO_PTR(IO_PARTITION_STATS)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz dtp = (struct dcd_errstats *)un->un_errstats->ks_data; \
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((un = ddi_get_soft_state(dcd_state, instance)) == NULL) \
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * After the following number of sectors, the cylinder number spills over
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * 0xFFFF if sectors = 63 and heads = 16.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Configuration Data
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Device driver ops vector
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz 0, /* streamtab */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz D_64BIT | D_MP | D_NEW, /* Driver compatibility flag */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz 0, /* refcnt */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This is the loadable module wrapper.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz &mod_driverops, /* Type of module. This one is a driver */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the dcd_attach_mutex only protects dcd_max_instance in multi-threaded
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * attach situations
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((e = ddi_soft_state_init(&dcd_state, sizeof (struct dcd_disk),
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (e);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz mutex_init(&dcd_attach_mutex, NULL, MUTEX_DRIVER, NULL);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (e != 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (e);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (e);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (e);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (e);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Keep a count of how many disks (ie. highest instance no) we have
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * XXX currently not used but maybe useful later again
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcdprobe:\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Turn around and call utility probe routine
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * to see whether we actually have a disk at
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Check whether it is a ATA device and then
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * return SUCCESS.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/*ARGSUSED*/
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz { "NAME=ide-disk", "0=standby", "1=idle", "2=active" };
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* CONSTCOND */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG2(devp->dcd_dev, dcd_label, DCD_DEBUG, "Attach Started\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz switch (cmd) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Restore the state which was saved to give the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the right state in un_last_state
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Raise the power level of the device to active.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (void) pm_raise_power(DCD_DEVINFO, 0, DCD_DEVICE_ACTIVE);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * start unit - if this is a low-activity device
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * commands in queue will have to wait until new
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * commands come in, which may take awhile.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Also, we specifically don't check un_ncmds
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * because we know that there really are no
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * commands in progress after the unit was suspended
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * and we could have reached the throttle level, been
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * suspended, and have no new commands coming in for
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * awhile. Highly unlikely, but so is the low-
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * activity disk scenario.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Add a zero-length attribute to tell the world we support
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * kernel ioctls (for layered drivers)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (void) ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Since the dad device does not have the 'reg' property,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * cpr will not call its DDI_SUSPEND/DDI_RESUME entries.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * The following code is to tell cpr that this device
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * does need to be suspended and resumed.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "pm-hardware-state", (caddr_t)"needs-suspend-resume");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Initialize power management bookkeeping;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Create components - In IDE case there are 3 levels and one
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * component. The levels being - active, idle, standby.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Ignore the return value of pm_raise_power
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Even if we check the return values and
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * remove the property created above, PM
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * framework will not honour the change after
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * first call to pm_raise_power. Hence, the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * removal of that property does not help if
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * pm_raise_power fails.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (void) pm_raise_power(DCD_DEVINFO, 0, DCD_DEVICE_ACTIVE);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Get devid; create a devid ONLY IF could not get ID */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Create the fab'd devid */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcd_free_softstate(struct dcd_disk *un, dev_info_t *devi)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Deallocate command packet resources.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Unregister the devid and free devid resources allocated
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Delete kstats. Kstats for non CD devices are deleted
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * in dcdclose.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Cleanup scsi_device resources.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* unprobe scsi device */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Remove properties created during attach */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz switch (cmd) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Save the last state first
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * wait till current operation completed. If we are
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * in the resource wait state (with an intr outstanding)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * then we need to wait till the intr completes and
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * starts the next cmd. We wait for
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * DCD_WAIT_CMDS_COMPLETE seconds before failing the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * DDI_SUSPEND.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * commands Didn't finish in the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * specified time, fail the DDI_SUSPEND.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "failed due to outstanding cmds\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * The reset entry point gets invoked at the system shutdown time or through
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * CPR code at system suspend.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Will be flushing the cache and expect this to be last I/O operation to the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * disk before system reset/power off.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/*ARGSUSED*/
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Get scsi_device structure for this instance.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Get dcd_disk structure containing target 'private' information
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Verify there are NO outstanding commands issued to this device.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * ie, un_ncmds == 0.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * It's possible to have outstanding commands through the physio
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * code path, even though everything's closed.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Lower the power state of the device
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * i.e. the minimum power consumption state - sleep.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (void) pm_lower_power(DCD_DEVINFO, 0, DCD_DEVICE_STANDBY);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * at this point there are no competing threads anymore
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * release active MT locks and all device resources.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (!(un = ddi_get_soft_state(dcd_state, instance)) ||
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (DCD_DEVICE_STANDBY > level) || (level > DCD_DEVICE_ACTIVE) ||
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * if there are active commands for the device or device will be
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * active soon. At the same time there is request to lower power
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * return failure.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * No need to fire any command, just set the state structure
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * to indicate previous state and set the level to active
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Issue the appropriate command
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((dcd_poll(pkt)) || (SCBP_C(pkt) != STATUS_GOOD)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz int km_flags = (canwait != NULL_FUNC)? KM_SLEEP : KM_NOSLEEP;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Call the routine scsi_probe to do some of the dirty work.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If the INQUIRY command succeeds, the field dcd_inq in the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * device structure will be filled in. The dcd_sense structure
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * will also be allocated.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (ddi_soft_state_zalloc(dcd_state, instance) != DDI_SUCCESS) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz sema_init(&un->un_semoclose, 1, NULL, SEMA_DRIVER, NULL);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Initialize power management conditional variable */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Assume CCS drive, assume parity, but call
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * it a CDROM if it is a RODIRECT device.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Allow I/O requests at un_secsize offset in multiple of un_secsize.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If the device is not a removable media device, make sure that
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * that the device is ready, by issuing the another identify but
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * not needed. Get the capacity from identify data and store here.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "Geometry Data\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "cyls %x, heads %x",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "sectors %x,",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "capacity %llx\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcdprobe: drive selected\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Check for the property target<n>-dcd-options to find the option
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * set by the HBA driver for this target so that we can set the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Unit structure variable so that we can send commands accordingly.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz options = ddi_prop_get_int(DDI_DEV_T_ANY, devi, DDI_PROP_NOTPROM,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "No per target properties");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * set default max_xfer_size - This should depend on whether the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Block mode is supported by the device or not.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Set write cache enable softstate
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * WCE is only supported in ATAPI-4 or higher; for
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * lower rev devices, must assume write cache is
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz un->un_write_cache_enabled = (devp->dcd_ident->dcd_majvers == 0xffff) ||
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz ((devp->dcd_ident->dcd_majvers & IDENTIFY_80_ATAPI_4) == 0) ||
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (devp->dcd_ident->dcd_features85 & IDENTIFY_85_WCE) != 0;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcd_doattach returns good\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcd_doattach failed\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This routine is used to set the block mode of operation by issuing the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Set Block mode ata command with the maximum block mode possible
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Zero all the required structure */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Here we should pass what needs to go into sector count REGISTER.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Eventhough this field indicates the number of bytes to read we
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * need to specify the block factor in terms of bytes so that it
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * will be programmed by the HBA driver into the sector count register.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * The following routine is used only for setting the transfer mode
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * and it is not designed for transferring any other features subcommand.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Zero all the required structure */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Here we need to pass what needs to go into the sector count register
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * But in the case of SET FEATURES command the value taken in the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * sector count register depends what type of subcommand is
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * passed in the features register. Since we have defined the size to
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * be the size in bytes in this context it does not indicate bytes
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * instead it indicates the mode to be programmed.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "size %x, features %x, cmd %x\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Validate the geometry for this disk, e.g.,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * see whether it has a valid label.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcd_validate_geometry: started \n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * take a log base 2 of sector size (sorry)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Only DIRECT ACCESS devices will have Sun labels.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * CD's supposedly have a Sun label, too
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) &&
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz else if (rval != 0)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* it should never get here. */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * take a log base 2 of logical block size
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * take a log base 2 of the multiple of DEV_BSIZE blocks that
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * make up one logical block
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Unix Entry Points
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* ARGSUSED3 */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcdopen(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * We use a semaphore here in order to serialize
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * open and close requests on the device.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((un->un_state & DCD_STATE_FATAL) == DCD_STATE_FATAL) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((un->un_state == DCD_STATE_PM_SUSPENDED) && (!nodelay)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * set make_dcd_cmd() flags and stat_size here since these
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * are unlikely to change
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdopen un=0x%p\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * check for previous exclusive open
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "exclopen=%x, flag=%x, regopen=%x\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Exclusive open flag %x, partmask %x\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "exclusive open fails\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Check Write Protect handled\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Fail if device is not ready or if the number of disk
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * blocks is zero or negative for non CD devices.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * set up open and exclusive open flags
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "open of part %d type %d\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Kstats getting updated\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * only create kstats for disks, CD kstats created in dcdattach
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * set up partition statistics for each partition
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * with number of blocks > 0
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz for (i = 0; i < NDKMAP; i++) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "partition",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * set up error kstats
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "Open success\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Test if disk is ready and has a valid geometry.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * cmds outstanding
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If device is not yet ready here, inform it is offline
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * check if geometry was valid. We don't check the validity of
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * geometry for CDROMS.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the state has changed; inform the media watch routines
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/*ARGSUSED*/
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcdclose(dev_t dev, int flag, int otyp, cred_t *cred_p)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "close of part %d type %d\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "last close\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz for (i = 0; i < NDKMAP; i++) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, "offline\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Given the device number return the devinfo pointer
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * from the scsi_device structure.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/*ARGSUSED*/
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcdinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((un = ddi_get_soft_state(dcd_state, instance)) == NULL)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * property operation routine. return the number of blocks for the partition
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * in question or forward the request to the propery facilities.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Our dynamic properties are all device specific and size oriented.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Requests issued under conditions where size is valid are passed
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * to ddi_prop_op_nblocks with the size information, otherwise the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * request is passed to ddi_prop_op. Size depends on valid geometry.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* get nblocks value */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * These routines perform raw i/o operations.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/*ARGSUSED*/
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* ARGSUSED2 */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#endif /* lint */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "file offset not modulo %d\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (physio(dcdstrategy, (struct buf *)0, dev, B_READ, dcdmin, uio));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* ARGSUSED2 */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcdaread(dev_t dev, struct aio_req *aio, cred_t *cred_p)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#endif /* lint */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "file offset not modulo %d\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (aphysio(dcdstrategy, anocancel, dev, B_READ, dcdmin, aio));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* ARGSUSED2 */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#endif /* lint */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "file offset not modulo %d\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (physio(dcdstrategy, (struct buf *)0, dev, B_WRITE, dcdmin,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* ARGSUSED2 */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcdawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#endif /* lint */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "file offset not modulo %d\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (aphysio(dcdstrategy, anocancel, dev, B_WRITE, dcdmin, aio));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * strategy routine
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz ((un->un_state & DCD_STATE_FATAL) == DCD_STATE_FATAL)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If the request size (buf->b_bcount)is greater than the size
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * (un->un_max_xfer_size) supported by the target driver fail
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the request with EINVAL error code.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * We are not supposed to receive requests exceeding
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * un->un_max_xfer_size size because the caller is expected to
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * check what is the maximum size that is supported by this
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * driver either through ioctl or dcdmin routine(which is private
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * to this driver).
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * But we have seen cases (like meta driver(md))where dcdstrategy
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * called with more than supported size and cause data corruption.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Commands may sneak in while we released the mutex in
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * DDI_SUSPEND, we should block new commands.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Map-in the buffer in case starting address is not word aligned.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (bn < 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * For proper comparison, file system block
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * number has to be scaled to actual CD
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * transfer size.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Since all the CDROM operations
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * that have Sun Labels are in the correct
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * block size this will work for CD's. This
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * will have to change when we have different
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * sector sizes.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * if bn == lblocks,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Not an error, resid == count
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This should really be:
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * ... if (bp->b_bcount & (un->un_lbasize-1))
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * sort by absolute block number.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * zero out av_back - this will be a signal
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * to dcdstart to go and fetch the resources
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Check to see whether or not we are done
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * (with or without errors).
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (i != 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (i < 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * opened in NDELAY/NONBLOCK mode?
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Check if disk is ready and has a valid geometry
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "i/o to invalid geometry\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This indicates that it is a special buffer
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This could be a udcd-cmd and hence call bp_mapin just
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * in case that it could be a PIO command issued.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((tcmdp->cmd != ATA_READ_DMA) && (tcmdp->cmd != 0xc9) &&
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (tcmdp->cmd != ATA_WRITE_DMA) && (tcmdp->cmd != 0xcb) &&
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * We are doing it a bit non-standard. That is, the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * head of the b_actf chain is *not* the active command-
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * it is just the head of the wait queue. The reason
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * we do this is that the head of the b_actf chain is
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * guaranteed to not be moved by disksort(), so that
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * our restart command (pointed to by
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * b_forw) and the head of the wait queue (b_actf) can
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * have resources granted without it getting lost in
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the queue at some later point (where we would have
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * to go and look for it).
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcdstrategy_disksort_start: dp 0x%p bp 0x%p un 0x%p",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcdstrategy_disksort_end");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "ncmd %x , throttle %x, forw 0x%p\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((un->un_ncmds < un->un_throttle) && (dp->b_forw == NULL)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * try and map this one
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz TRACE_0(TR_FAC_DADA, TR_DCDSTRATEGY_SMALL_WINDOW_START,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcdstrategy_small_window_call (begin)");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcdstrategy_small_window_call (end)");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * there is a small window where the active cmd
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * completes before make_dcd_cmd returns.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * consequently, this cmd never gets started so
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * we start it from here
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz TRACE_0(TR_FAC_DADA, TR_DCDSTRATEGY_END, "dcdstrategy_end");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Unit start and Completion
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * NOTE: we assume that the caller has at least checked for:
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * (un->un_ncmds < un->un_throttle)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * if not, there is no real harm done, dcd_transport() will
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * return BUSY
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz TRACE_1(TR_FAC_DADA, TR_DCDSTART_START, "dcdstart_start: un 0x%p", un);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (((bp = dp->b_actf) == NULL) || (bp->av_back == ALLOCATING_PKT) ||
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcdstart_end (no work)");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * remove from active queue
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * increment ncmds before calling dcd_transport because dcdintr
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * may be called before we return from dcd_transport!
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If measuring stats, mark exit from wait queue and
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * entrance into run 'queue' if and only if we are
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * going to actually start a command.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Normally the bp already has a packet at this point
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcdstart_end (No Resources)");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * restore old state
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Restore resid from the packet, b_resid had been the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * disksort key.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "bp->b_resid %lx, pkt_resid %lx\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * We used to check whether or not to try and link commands here.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Since we have found that there is no performance improvement
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * for linked commands, this has not made much sense.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((status = dcd_transport((struct dcd_pkt *)BP_PKT(bp)))
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "transport rejected (%d)\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * try and map this one
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcdstart_small_window_start");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcdstart_small_window_end");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * there is a small window where the active cmd
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * completes before make_dcd_cmd returns.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * consequently, this cmd never gets started so
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * we start it from here
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz TRACE_0(TR_FAC_DADA, TR_DCDSTART_END, "dcdstart_end");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * make_dcd_cmd: create a pkt
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzmake_dcd_cmd(struct dcd_disk *un, struct buf *bp, int (*func)())
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "make_dcd_cmd_start: un 0x%p bp 0x%p un 0x%p", un, bp, un);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Make sure we don't run off the end of a partition.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Put this test here so that we can adjust b_count
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * to accurately reflect the actual amount we are
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * goint to transfer.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * First, compute partition-relative block number
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz secnt = (bp->b_bcount + (un->un_secsize - 1)) >> un->un_secdiv;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * We have an overrun
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "overrun by %ld sectors\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Adjust block number to absolute
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This is for devices having block size different from
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * from DEV_BSIZE (e.g. 2K CDROMs).
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "make_dcd_cmd_init_pkt_call (begin)");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "make_dcd_cmd_end (NO_PKT_ALLOCATED1)");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Save the resid in the packet, temporarily until
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * we transport the command.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz struct udcd_cmd *scmd = (struct udcd_cmd *)bp->b_forw;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * set options
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((scmd->udcd_flags & UDCD_SILENT) && !(DEBUGGING)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* UDAD interface should be decided. */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "udcd interface\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz TRACE_0(TR_FAC_DADA, TR_MAKE_DCD_CMD_END, "make_dcd_cmd_end");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Command completion processing
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz un = ddi_get_soft_state(dcd_state, DCDUNIT(bp->b_edev));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz TRACE_1(TR_FAC_DADA, TR_DCDINTR_START, "dcdintr_start: un 0x%p", un);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdintr\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "reason %x and Status %x\n", pkt->pkt_reason, SCBP_C(pkt));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * do most common case first
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((pkt->pkt_reason == CMD_CMPLT) && (SCBP_C(pkt) == 0)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (const char *) diskokay);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If the command is a read or a write, and we have
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * a non-zero pkt_resid, that is an error. We should
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * attempt to retry the operation if possible.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (pkt->pkt_resid && (com == ATA_READ || com == ATA_WRITE)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * if we have exhausted retries
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * a command with a residual is in error in
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * this case.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "giving up");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * pkt_resid will reflect, at this point, a residual
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * of how many bytes left to be transferred there were
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * from the actual scsi command. Add this to b_resid i.e
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the amount this driver could not see to transfer,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * to get the total number of bytes not transfered.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If we are in the middle of syncing or dumping, we have got
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * here because dcd_transport has called us explictly after
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * completing the command in a polled mode. We don't want to
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * have a recursive call into dcd_transport again.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * save pkt reason; consecutive failures are not reported unless
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * do not reset last_pkt_reason when the cmd was retried and
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * succeeded because
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * there maybe more commands comming back with last_pkt_reason
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz struct dcd_cmd *cdbp = (struct dcd_cmd *)pkt->pkt_cdbp;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /*FALLTHROUGH*/
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dcdintr_end (COMMAND_DONE)");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* reset the pkt reason again */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((status = dcd_transport(BP_PKT(bp))) != TRAN_ACCEPT) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Done with a command.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcddone_and_mutex_exit(struct dcd_disk *un, register struct buf *bp)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz TRACE_1(TR_FAC_DADA, TR_DCDONE_START, "dcddone_start: un 0x%p", un);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz _NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(&un->un_dcd->dcd_mutex));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Start the next one before releasing resources on this one
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz } else if (dp->b_actf && (un->un_ncmds < un->un_throttle) &&
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (dp->b_forw == NULL && un->un_state != DCD_STATE_SUSPENDED)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz TRACE_0(TR_FAC_DADA, TR_DCDDONE_BIODONE_CALL, "dcddone_biodone_call");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * reset the disk unless the transport layer has already
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * cleared the problem
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#define C1 (STAT_ATA_BUS_RESET|STAT_ATA_DEV_RESET|STAT_ATA_ABORTED)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcd_reset_disk(struct dcd_disk *un, struct dcd_pkt *pkt)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Reset failed");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcd_handle_incomplete(struct dcd_disk *un, struct buf *bp)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz static char *fail = "ATA transport failed: reason '%s': %s\n";
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz static char *notresp = "disk not responding to selection\n";
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz int be_chatty = (un->un_state != DCD_STATE_SUSPENDED) &&
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (bp != un->un_sbufp || !(pkt->pkt_flags & FLAG_SILENT));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This Indicates the already the HBA would have reset
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * so Just indicate to retry the command
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Something drastic has gone wrong
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* FALLTHROUGH */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the target may still be running the command,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * so we should try and reset that target.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If pkt_reason is CMD_RESET/ABORTED, chances are that this pkt got
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * reset/aborted because another disk on this bus caused it.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * The disk that caused it, should get CMD_TIMEOUT with pkt_statistics
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((pkt->pkt_reason == CMD_RESET) ||(pkt->pkt_reason == CMD_ABORTED)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* To be written : XXX */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Command aborted\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (bp == un->un_sbufp && (pkt->pkt_flags & FLAG_DIAGNOSE)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (pkt->pkt_reason == CMD_INCOMPLETE && rval == COMMAND_DONE_ERROR) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Looks like someone turned off this shoebox.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (const char *) notresp);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Suppressing the following message for the time being
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * dcd_log(DCD_DEVINFO, dcd_label, CE_WARN,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * (const char *) notresp);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz } else if (be_chatty) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "retrycount=%x\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz unsigned char status;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz unsigned char error;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz TRACE_0(TR_FAC_DADA, TR_DCD_CHECK_ERROR_START, "dcd_check_error_start");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Here we need to check status first and then if error is indicated
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Then the error register.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * There has been a Device Fault - reason for such error
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * is vendor specific
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Action to be taken is - Indicate error and reset device.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz dcd_log(DCD_DEVINFO, dcd_label, CE_WARN, "Device Fault\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz } else if ((status & STATUS_ATA_CORR) == STATUS_ATA_CORR) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * The sector read or written is marginal and hence ECC
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Correction has been applied. Indicate to repair
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Here we need to probably re-assign based on the badblock
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Soft Error on block %x\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz ((struct dcd_cmd *)pkt->pkt_cdbp)->sector_num.lba_num);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz } else if ((status & STATUS_ATA_ERR) == STATUS_ATA_ERR) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Command:0x%x,Error:0x%x,Status:0x%x\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Address make not found */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Address Mark Not Found");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Track 0 Not found */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Track 0 Not found \n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz " ID not found \n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Uncorrectable data Error: Block %x\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz ((struct dcd_cmd *)pkt->pkt_cdbp)->sector_num.lba_num);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Bad block detected: Block %x\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz ((struct dcd_cmd *)pkt->pkt_cdbp)->sector_num.lba_num);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Aborted Command */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz " Aborted Command \n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Return the soft error so that the command
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * will be retried.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz TRACE_0(TR_FAC_DADA, TR_DCD_CHECK_ERROR_END, "dcd_check_error_end");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * System Crash Dump routine
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcddump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz unsigned char com;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#endif /* lint */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((un->un_state & DCD_STATE_FATAL) == DCD_STATE_FATAL)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * When cpr calls dcddump, we know that dad is in a
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * a good state, so no bus reset is required
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Reset the bus. I'd like to not have to do this,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * but this is the safest thing to do...
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * It should be safe to call the allocator here without
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * worrying about being locked for DVMA mapping because
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the address we're passed is already a DVMA mapping
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * We are also not going to worry about semaphore ownership
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * in the dump buffer. Dumping is single threaded at present.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz for (i = 0; i < NDUMP_RETRIES; i++) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (i == 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "no resources for dumping; "
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "error code: 0x%x, retrying",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "no resources for dumping; retrying");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "resources for dumping; error code: 0x%x, "
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "no resources for dumping; "
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "error code: 0x%x, retries failed, "
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "no resources for dumping; "
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "retries failed, giving up.\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz for (err = EIO, i = 0; i < NDUMP_RETRIES && err == EIO; i++) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This routine implements the ioctl calls. It is called
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * from the device switch at normal priority.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* ARGSUSED3 */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#endif /* lint */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz switch (cmd) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Following ioctl are for testing RESET/ABORTS
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "DKIOCABORT:\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Controller Information
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz info->dki_cnum = ddi_get_instance(ddi_get_parent(DCD_DEVINFO));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Unit Information
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (void) strcpy(info->dki_dname, ddi_driver_name(DCD_DEVINFO));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Max Transfer size of this device in blocks
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz info->dki_maxtransfer = un->un_max_xfer_size / DEV_BSIZE;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * We can't get from here to there yet
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz i = sizeof (struct dk_cinfo);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (ddi_copyout((caddr_t)data, (caddr_t)arg, i, flag))
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * As dad target driver is used for IDE disks only
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Can keep the return value hardcoded to FIXED_DISK
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz rwcmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmd.bufaddr;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Convert the dadkio_rwcmd structure to udcd_cmd so that
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * it can take the normal path to get the io done
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz scmd->udcd_bufaddr = (caddr_t)(uintptr_t)rwcmd32.bufaddr;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz i = dcdioctl_cmd(dev, scmd, UIO_SYSSPACE, UIO_USERSPACE);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * After return convert the status from scmd to
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * dadkio_status
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Copy out the result back to the user program */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (i != 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Copy out the result back to the user program */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (i != 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Copy out the result back to the user program */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (i != 0)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (i);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * For use when a 32 bit app makes a call into a
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * 64 bit ioctl
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#endif /* _MULTI_DATAMODEL */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz switch (model = ddi_model_convert_from(flag & FMODELS)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Convert the ILP32 uscsi data from the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * application to LP64 for internal use.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#else /* ! _MULTI_DATAMODEL */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#endif /* ! _MULTI_DATAMODEL */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz uioseg = (flag & FKIOCTL)? UIO_SYSSPACE: UIO_USERSPACE;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Convert back to ILP32 before copyout to the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * application
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (i != 0)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (i != 0)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#else /* ! _MULTI_DATAMODE */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (i != 0)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (i);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If a callback was requested: a callback will
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * always be done if the caller saw the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * DKIOCFLUSHWRITECACHE ioctl return 0, and
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * never done if the caller saw the ioctl return
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * an error.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Did callback and reported error.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Since we did a callback, ioctl
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * should return 0.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (i);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Get the special buffer
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz ATA_FLUSH_CACHE, 0, ADD_LBA_MODE, 0, NO_DATA_XFER, 0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (i);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz struct dk_callback *dkc = (struct dk_callback *)bp->b_list;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Tell anybody who cares that the buffer is now free
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * dcdrunout:
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the callback function for resource allocation
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * XXX it would be preferable that dcdrunout() scans the whole
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * list for possible candidates for dcdstart(); this avoids
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * that a bp at the head of the list whose request cannot be
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * satisfied is retried again and again
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/*ARGSUSED*/
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz TRACE_1(TR_FAC_DADA, TR_DCDRUNOUT_START, "dcdrunout_start: arg 0x%p",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * We now support passing a structure to the callback
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((un->un_ncmds < un->un_throttle) && (dp->b_forw == NULL)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This routine called to see whether unit is (still) there. Must not
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * be called when un->un_sbufp is in use, and must not be called with
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * an unattached disk. Soft state of disk is restored to what it was
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * upon entry- up to caller to set the correct state.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * We enter with the disk mutex held.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* ARGSUSED0 */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Now that we protect the special buffer with
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * a mutex, we could probably do a mutex_tryenter
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * on it here and return failure if it were held...
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* ARGSUSED0 */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcdioctl_cmd(dev_t devp, struct udcd_cmd *in, enum uio_seg cdbspace,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Is this a request to reset the bus?
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * if so, we need to do reseting.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Do some sanity checks */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Make a copy of the dcd_cmd passed */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (ddi_copyin((void *)scmd->udcd_cmd, cdb, sizeof (struct dcd_cmd),
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz scmd = (struct udcd_cmd *)kmem_alloc(sizeof (*scmd), KM_SLEEP);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz rw = (scmd->udcd_flags & UDCD_READ) ? B_READ: B_WRITE;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Get the special buffer
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If we are going to do actual I/O, let physio do all the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Let physio do the rest...
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz err = physio(dcdstrategy, bp, devp, rw, dcdudcdmin, uio);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * We have to mimic what physio would do here.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* we need to update the completion status of udcd command */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* XXX: we need to give error_reg also */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Tell anybody who cares that the buffer is now free
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * restart a cmd from timeout() context
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the cmd is expected to be in un_utab.b_forw. If this pointer is non-zero
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * a restart timeout request has been issued and no new timeouts should
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * be requested. b_forw is reset when the cmd eventually completes in
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * dcddone_and_mutex_exit()
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdrestart\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* XXX : To be checked */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * if (un->un_throttle > 1) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * ASSERT(un->un_ncmds >= 0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * un->un_throttle = un->un_ncmds;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG(DCD_DEVINFO, dcd_label, DCD_DEBUG, "dcdrestart done\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This routine gets called to reset the throttle to its saved
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * value wheneven we lower the throttle.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * start any commands that didn't start while throttling.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This routine handles the case when a TRAN_BUSY is
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * returned by HBA.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If there are some commands already in the transport, the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * bp can be put back on queue and it will
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * be retried when the queue is emptied after command
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * completes. But if there is no command in the tranport
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * and it still return busy, we have to retry the command
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * after some time like 10ms.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* ARGSUSED0 */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcd_handle_tran_busy(struct buf *bp, struct diskhd *dp, struct dcd_disk *un)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz timeout(dcdrestart, (caddr_t)un, DCD_BSY_TIMEOUT/500);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (cmlb_get_devid_block(un->un_dklbhandle, &blk, 0)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Allocate the buffer */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Fill in the revision */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Copy in the device id */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Calculate the chksum */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz for (i = 0; i < ((un->un_secsize - sizeof (int))/sizeof (int)); i++)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Fill in the checksum */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (cmlb_get_devid_block(un->un_dklbhandle, &blk, 0)) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz status = dcdioctl_cmd(dev, &ucmd, UIO_SYSSPACE, UIO_SYSSPACE);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (status != 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Validate the revision */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Calculate the checksum */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz for (i = 0; i < ((un->un_secsize - sizeof (int))/sizeof (int)); i++)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Compare the checksums */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* VAlidate the device id */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (ddi_devid_valid((ddi_devid_t)&dkdevid->dkd_devid) != DDI_SUCCESS) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* return a copy of the device id */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz sz = ddi_devid_sizeof((ddi_devid_t)&dkdevid->dkd_devid);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Return the device id for the device.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * 1. If the device ID exists then just return it - nothing to do in that case.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * 2. Build one from the drives model number and serial number.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * 3. If there is a problem in building it from serial/model #, then try
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * to read it from the acyl region of the disk.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Note: If this function is unable to return a valid ID then the calling
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * point will invoke the routine to create a fabricated ID ans stor it on the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * acyl region of the disk.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* If already registered, return that value */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Build a devid from model and serial number, if present */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Read the devid from the disk. */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (ddi_devid_init(DCD_DEVINFO, DEVID_FAB, 0, NULL, (ddi_devid_t *)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Build a devid from the model and serial number, if present
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Return DDI_SUCCESS or DDI_FAILURE.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* initialize the model and serial number information */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Verify the model and serial number */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz dcd_validate_model_serial(model, &model_len, model_len);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz dcd_validate_model_serial(serno, &serno_len, serno_len);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * The device ID will be concatenation of the model number,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the '=' separator, the serial number. Allocate
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * the string and concatenate the components.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz bcopy((caddr_t)serno, (caddr_t)&hwid[model_len + 1], serno_len);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Initialize the device ID, trailing NULL not included */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz rc = ddi_devid_init(DCD_DEVINFO, DEVID_ATA_SERIAL, total_len,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Free the allocated string */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Test for a valid model or serial number. Assume that a valid representation
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * contains at least one character that is neither a space, 0 digit, or NULL.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Trim trailing blanks and NULLS from returned length.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcd_validate_model_serial(char *str, int *retlen, int totallen)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Atleast one non 0 or blank character. */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzclean_print(dev_info_t *dev, char *label, uint_t level,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz for (i = 0; i < len; i++) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (void) sprintf(&buf[strlen(buf)], "0x%x ", (data[i] & 0xff));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#endif /* Not lint */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Print a piece of inquiry data- cleaned up for non-printable characters
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * and stopping at the first space character after the beginning of the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * passed string;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzinq_fill(char *p, int l, char *s)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz unsigned i = 0;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz while (i++ < l) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz#endif /* Not lint */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return ("good status");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return ("busy");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return ("<unknown status>");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* ARGSUSED0 */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz static char *rnames[] = {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "incomplete",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "dma_derr",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "tran_err",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "data_ovr",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return ("<unknown reason>");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/* ARGSUSED0 */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Create device error kstats
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz un->un_errstats = kstat_create("daderror", instance, kstatname,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz dtp = (struct dcd_errstats *)un->un_errstats->ks_data;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz kstat_named_init(&dtp->dcd_rq_media_err, "Media Error",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz kstat_named_init(&dtp->dcd_rq_nodev_err, " No Device",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz kstat_named_init(&dtp->dcd_rq_recov_err, "Recoverable",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This has been moved from DADA layer as this does not do anything other than
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * retrying the command when it is busy or it does not complete
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Save old flags
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Set the Pkt_comp to NULL
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Set the Pkt time for the polled command
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz /* Now transport the command */
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz for (busy_count = 0; busy_count < dcd_poll_busycnt; busy_count++) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcd_translate(struct dadkio_status32 *statp, struct udcd_cmd *cmdp)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * The error register is valid only when BSY and DRQ not set
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Assumed that HBA has checked this before it gives the data
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz makecommand(pkt, 0, ATA_FLUSH_CACHE, 0, ADD_LBA_MODE, 0,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Send the command. There are chances it might fail on some
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * disks since it is not a mandatory command as per ata-4. Try
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * 3 times if it fails. The retry count has been randomly selected.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * There is a need for retry since as per the spec FLUSH CACHE can fail
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * as a result of unrecoverable error encountered during execution
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * of writing data and subsequent command should continue flushing
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz for (retry_count = 0; retry_count < 3; retry_count++) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Set the packet fields.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * Note the wait time value of 100ms is same as in the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * dcd_poll routine.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz diskaddr_t start_block, size_t reqlength, uchar_t cmd)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz int i, rval = 0;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz un = ddi_get_soft_state(dcd_state, ddi_get_instance(devi));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz bp = dcd_alloc_consistent_buf(ROUTE, (struct buf *)NULL,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "no bp for disk label\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "no memory for disk label\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz bcopy((caddr_t)bufaddr, bp->b_un.b_addr, buffer_size);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((un->un_dp->options & DMA_SUPPORTTED) == DMA_SUPPORTTED) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz (void) makecommand(pkt, 0, command, real_addr, ADD_LBA_MODE,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz for (i = 0; i < 3; i++) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "Status %x, state %x, resid %lx\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if (rval != 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzstatic int dcd_compute_dk_capacity(struct dcd_device *devp,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz no_of_lbasec = no_of_lbasec | devp->dcd_ident->dcd_addrsec[0];
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/*ARGSUSED5*/
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcd_lb_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz diskaddr_t start_block, size_t reqlength, void *tg_cookie)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (dcd_send_lb_rw_cmd(devi, bufaddr, start_block,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcd_lb_getphygeom(dev_info_t *devi, cmlb_geom_t *phygeomp)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz uint32_t no_of_lbasec, capacity, calculated_cylinders;
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz if ((devp->dcd_ident->dcd_config & ATAPI_DEVICE) == 0) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * if the capacity is greater than 32G,
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * then 255 is the sectors per track.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * This should be good until 128G disk
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * capacity, which is the current ATA-4
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * limitation.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * If the disk capacity is >= 128GB then no. of
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * addressable sectors will be set to 0xfffffff
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * in the IDENTIFY info. In that case set the
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz * no. of pcyl to the Max. 16bit value.
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz/*ARGSUSED3*/
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutzdcd_lb_getinfo(dev_info_t *devi, int cmd, void *arg, void *tg_cookie)
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz un = ddi_get_soft_state(dcd_state, ddi_get_instance(devi));
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz switch (cmd) {
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (-1);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "invalid disk capacity\n");
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz DAD_DEBUG2(DCD_DEVINFO, dcd_label, DCD_DEBUG, "capacity %x\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz "media_is_writable %x\n",
a4aa671e336d5c717aff15808ab91a6bee5e6e41arutz return (0);