10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7656SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License").
6*7656SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * ATA disk driver
300Sstevel@tonic-gate *
310Sstevel@tonic-gate * Handles the standard PCMCIA ATA interface
320Sstevel@tonic-gate *
330Sstevel@tonic-gate */
340Sstevel@tonic-gate #include <sys/errno.h>
350Sstevel@tonic-gate #include <sys/param.h>
360Sstevel@tonic-gate #include <sys/systm.h>
370Sstevel@tonic-gate #include <sys/user.h>
380Sstevel@tonic-gate #include <sys/buf.h>
390Sstevel@tonic-gate #include <sys/ioctl.h>
400Sstevel@tonic-gate #include <sys/file.h>
410Sstevel@tonic-gate #include <sys/uio.h>
420Sstevel@tonic-gate #include <sys/fcntl.h>
430Sstevel@tonic-gate #include <sys/cmn_err.h>
440Sstevel@tonic-gate #include <sys/kmem.h>
450Sstevel@tonic-gate #include <sys/sysmacros.h>
460Sstevel@tonic-gate #include <sys/stat.h>
470Sstevel@tonic-gate #include <sys/scsi/scsi.h>
480Sstevel@tonic-gate
490Sstevel@tonic-gate #include <sys/fdio.h>
500Sstevel@tonic-gate
510Sstevel@tonic-gate #include <sys/errno.h>
520Sstevel@tonic-gate #include <sys/open.h>
530Sstevel@tonic-gate #include <sys/varargs.h>
540Sstevel@tonic-gate #include <sys/fs/pc_label.h>
550Sstevel@tonic-gate
560Sstevel@tonic-gate #include <sys/hdio.h>
570Sstevel@tonic-gate #include <sys/dkio.h>
580Sstevel@tonic-gate #include <sys/dktp/dadkio.h>
590Sstevel@tonic-gate
600Sstevel@tonic-gate #include <sys/dklabel.h>
610Sstevel@tonic-gate
620Sstevel@tonic-gate #include <sys/vtoc.h>
630Sstevel@tonic-gate
640Sstevel@tonic-gate #include <sys/types.h>
650Sstevel@tonic-gate #include <sys/conf.h>
660Sstevel@tonic-gate #include <sys/dditypes.h>
670Sstevel@tonic-gate #include <sys/ddi.h>
680Sstevel@tonic-gate #include <sys/sunddi.h>
690Sstevel@tonic-gate #include <sys/dktp/cm.h>
700Sstevel@tonic-gate
710Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
720Sstevel@tonic-gate
730Sstevel@tonic-gate #include <sys/fs/pc_label.h>
740Sstevel@tonic-gate
750Sstevel@tonic-gate #include <sys/pctypes.h>
760Sstevel@tonic-gate
770Sstevel@tonic-gate
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate * PCMCIA and DDI related header files
800Sstevel@tonic-gate */
810Sstevel@tonic-gate #include <sys/pccard.h>
820Sstevel@tonic-gate
830Sstevel@tonic-gate #include <sys/pcmcia/pcata.h>
840Sstevel@tonic-gate
850Sstevel@tonic-gate int pcata_debug = 0;
860Sstevel@tonic-gate
870Sstevel@tonic-gate static int pcata_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
880Sstevel@tonic-gate static int pcata_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
890Sstevel@tonic-gate static int pcata_att1(dev_info_t *dip, ata_soft_t *softp);
900Sstevel@tonic-gate static int pcata_go(ata_unit_t *unitp);
910Sstevel@tonic-gate static int pcata_wait(uint32_t port, ushort_t onbits, ushort_t offbits,
920Sstevel@tonic-gate ata_soft_t *softp);
930Sstevel@tonic-gate static int pcata_wait1(uint32_t port, ushort_t onbits, ushort_t offbits,
940Sstevel@tonic-gate int interval, ata_soft_t *softp);
950Sstevel@tonic-gate static void pcata_wait_complete(ata_soft_t *softp);
960Sstevel@tonic-gate static uchar_t pcata_drive_type(ata_soft_t *softp, ushort_t *secbuf);
970Sstevel@tonic-gate static int pcata_setpar(int drive, int heads, int sectors, ata_soft_t *softp);
980Sstevel@tonic-gate static int pcata_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
990Sstevel@tonic-gate static int pcata_print(dev_t dev, char *str);
1000Sstevel@tonic-gate static int pcata_rdrw(dev_t dev, struct uio *uio, int flag);
1010Sstevel@tonic-gate static int pcata_read(dev_t dev, struct uio *uio, cred_t *cred_p);
1020Sstevel@tonic-gate static int pcata_write(dev_t dev, struct uio *uio, cred_t *cred_p);
1030Sstevel@tonic-gate #ifdef ATA_DEBUG
1040Sstevel@tonic-gate static void pcata_print_sttflag(int svalue);
1050Sstevel@tonic-gate #endif
1060Sstevel@tonic-gate static void pcata_clear_queues(ata_unit_t *unitp);
1070Sstevel@tonic-gate static void pcata_nack_packet(struct ata_cmpkt *pktp);
1080Sstevel@tonic-gate static void pcata_iosetup(ata_unit_t *unitp, struct ata_cmpkt *pktp);
1090Sstevel@tonic-gate static int pcata_send_data(ata_unit_t *unitp, int count);
1100Sstevel@tonic-gate static int pcata_get_data(ata_unit_t *unitp, int count);
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate struct cb_ops pcata_cb_ops = {
1130Sstevel@tonic-gate pcata_open, /* driver open routine */
1140Sstevel@tonic-gate pcata_close, /* driver close routine */
1150Sstevel@tonic-gate pcata_strategy, /* driver strategy routine */
1160Sstevel@tonic-gate pcata_print, /* driver print routine */
1170Sstevel@tonic-gate pcata_dump, /* driver dump routine */
1180Sstevel@tonic-gate pcata_read, /* driver read routine */
1190Sstevel@tonic-gate pcata_write, /* driver write routine */
1200Sstevel@tonic-gate pcata_ioctl, /* driver ioctl routine */
1210Sstevel@tonic-gate nodev, /* driver devmap routine */
1220Sstevel@tonic-gate nodev, /* driver mmap routine */
1230Sstevel@tonic-gate nodev, /* driver segmap routine */
1240Sstevel@tonic-gate nochpoll, /* driver chpoll routine */
1250Sstevel@tonic-gate pcata_prop_op, /* driver prop_op routine */
1260Sstevel@tonic-gate 0, /* driver cb_str - STREAMS only */
1270Sstevel@tonic-gate D_NEW | D_MTSAFE, /* driver compatibility flag */
1280Sstevel@tonic-gate };
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate static struct dev_ops ata_ops = {
1310Sstevel@tonic-gate DEVO_REV, /* devo_rev, */
1320Sstevel@tonic-gate 0, /* refcnt */
1330Sstevel@tonic-gate pcata_getinfo, /* info */
1340Sstevel@tonic-gate nulldev, /* identify */
1350Sstevel@tonic-gate nulldev, /* probe */
1360Sstevel@tonic-gate pcata_attach, /* attach */
1370Sstevel@tonic-gate pcata_detach, /* detach */
1380Sstevel@tonic-gate nulldev, /* reset */
1390Sstevel@tonic-gate &pcata_cb_ops, /* driver operations */
140*7656SSherry.Moore@Sun.COM NULL, /* bus operations */
141*7656SSherry.Moore@Sun.COM NULL, /* power */
142*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */
1430Sstevel@tonic-gate };
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate void *pcata_soft = NULL;
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate #include <sys/modctl.h>
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate extern struct mod_ops mod_driverops;
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate static struct modldrv modldrv = {
1550Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */
156*7656SSherry.Moore@Sun.COM "PCMCIA ATA disk controller",
1570Sstevel@tonic-gate &ata_ops, /* driver ops */
1580Sstevel@tonic-gate };
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate static struct modlinkage modlinkage = {
1610Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL
1620Sstevel@tonic-gate };
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate int
_init(void)1650Sstevel@tonic-gate _init(void)
1660Sstevel@tonic-gate {
1670Sstevel@tonic-gate int status;
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate status = mod_install(&modlinkage);
1700Sstevel@tonic-gate if (status)
1710Sstevel@tonic-gate return (status);
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate status = ddi_soft_state_init(&pcata_soft, sizeof (ata_soft_t), 1);
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate return (status);
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate int
_fini(void)1800Sstevel@tonic-gate _fini(void)
1810Sstevel@tonic-gate {
1820Sstevel@tonic-gate int status;
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate status = mod_remove(&modlinkage);
1850Sstevel@tonic-gate if (!status)
1860Sstevel@tonic-gate ddi_soft_state_fini(&pcata_soft);
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate return (status);
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1930Sstevel@tonic-gate _info(struct modinfo *modinfop)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate static int
pcata_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1990Sstevel@tonic-gate pcata_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2000Sstevel@tonic-gate {
2010Sstevel@tonic-gate int instance = ddi_get_instance(dip);
2020Sstevel@tonic-gate ata_soft_t *softp;
2030Sstevel@tonic-gate int ret;
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate /* resume from a checkpoint */
2060Sstevel@tonic-gate if (cmd == DDI_RESUME)
207*7656SSherry.Moore@Sun.COM return (DDI_SUCCESS);
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate if (cmd != DDI_ATTACH) {
2100Sstevel@tonic-gate #ifdef ATA_DEBUG
2110Sstevel@tonic-gate cmn_err(CE_CONT, "_attach returning FAILURE\n");
2120Sstevel@tonic-gate #endif
2130Sstevel@tonic-gate return (DDI_FAILURE);
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate /* Allocate soft state associated with this instance. */
2170Sstevel@tonic-gate ret = ddi_soft_state_zalloc(pcata_soft, ddi_get_instance(dip));
2180Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
2190Sstevel@tonic-gate #ifdef ATA_DEBUG
2200Sstevel@tonic-gate cmn_err(CE_CONT, "_attach: Unable to alloc state\n");
2210Sstevel@tonic-gate #endif
2220Sstevel@tonic-gate return (DDI_FAILURE);
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate softp = ddi_get_soft_state(pcata_soft, instance);
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate #ifdef ATA_DEBUG
2280Sstevel@tonic-gate if (pcata_debug & DINIT)
2290Sstevel@tonic-gate cmn_err(CE_CONT, "_attach softp=%p\n", (void *)softp);
2300Sstevel@tonic-gate #endif
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate softp->dip = dip;
2330Sstevel@tonic-gate softp->instance = instance;
2340Sstevel@tonic-gate softp->ab_dip = dip;
2350Sstevel@tonic-gate softp->crashbuf = getrbuf(KM_SLEEP);
2360Sstevel@tonic-gate softp->flags = 0;
2370Sstevel@tonic-gate softp->card_state = 0;
2380Sstevel@tonic-gate softp->intr_pending = 0;
2390Sstevel@tonic-gate softp->softint_pending = 0;
2400Sstevel@tonic-gate softp->write_in_progress = 0;
2410Sstevel@tonic-gate softp->blk_open = 0;
2420Sstevel@tonic-gate softp->chr_open = 0;
2430Sstevel@tonic-gate softp->ejected_while_mounted = 0;
2440Sstevel@tonic-gate bzero(softp->lyr_open, sizeof (softp->lyr_open[NUM_PARTS]));
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate * Initialize to 0 until it is incremented in pcram_check_media
2480Sstevel@tonic-gate */
2490Sstevel@tonic-gate softp->checkmedia_flag = 0;
2500Sstevel@tonic-gate softp->ejected_media_flag = 0;
2510Sstevel@tonic-gate softp->media_state = DKIO_NONE;
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate /*
2540Sstevel@tonic-gate * if attach fails, Solaris won't call detach
2550Sstevel@tonic-gate * so we call detach here to release all flagged resources
2560Sstevel@tonic-gate */
2570Sstevel@tonic-gate ret = pcata_att1(dip, softp);
2580Sstevel@tonic-gate if (ret == DDI_FAILURE) {
2590Sstevel@tonic-gate (void) pcata_detach(dip, DDI_DETACH);
2600Sstevel@tonic-gate return (DDI_FAILURE);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate return (DDI_SUCCESS);
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate static int
pcata_att1(dev_info_t * dip,ata_soft_t * softp)2670Sstevel@tonic-gate pcata_att1(dev_info_t *dip, ata_soft_t *softp)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate int ret;
2700Sstevel@tonic-gate client_reg_t client_reg;
2710Sstevel@tonic-gate sockmask_t sockmask;
2720Sstevel@tonic-gate map_log_socket_t map_log_socket;
2730Sstevel@tonic-gate cs_ddi_info_t cs_ddi_info;
2740Sstevel@tonic-gate get_status_t get_status;
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate /*
2780Sstevel@tonic-gate * create ata_mutex
2790Sstevel@tonic-gate */
2800Sstevel@tonic-gate ret = ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_MED,
281*7656SSherry.Moore@Sun.COM &softp->soft_blk_cookie);
2820Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
2830Sstevel@tonic-gate #ifdef ATA_DEBUG
2840Sstevel@tonic-gate cmn_err(CE_CONT, "_attach: unable to get iblock cookie\n");
2850Sstevel@tonic-gate #endif
2860Sstevel@tonic-gate return (ret);
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate
2900Sstevel@tonic-gate /*
2910Sstevel@tonic-gate * Setup the mutexii and condition variables.
2920Sstevel@tonic-gate * Initialize the mutex that protects the ATA registers.
2930Sstevel@tonic-gate */
2940Sstevel@tonic-gate mutex_init(&softp->ata_mutex, NULL, MUTEX_DRIVER,
295*7656SSherry.Moore@Sun.COM (void *)(softp->soft_blk_cookie));
2960Sstevel@tonic-gate mutex_init(&softp->label_mutex, NULL, MUTEX_DRIVER, NULL);
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate cv_init(&softp->readywait_cv, NULL, CV_DRIVER, NULL);
2990Sstevel@tonic-gate /* for DKIOCSTATE ioctl() */
3000Sstevel@tonic-gate cv_init(&softp->condvar_mediastate, NULL, CV_DRIVER, NULL);
3010Sstevel@tonic-gate softp->flags |= PCATA_DIDLOCKS;
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate /*
3050Sstevel@tonic-gate * link in soft interrupt
3060Sstevel@tonic-gate */
3070Sstevel@tonic-gate ret = ddi_add_softintr(dip, DDI_SOFTINT_MED, &softp->softint_id,
308*7656SSherry.Moore@Sun.COM NULL, NULL, pcata_intr, (caddr_t)softp);
3090Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
3100Sstevel@tonic-gate #ifdef ATA_DEBUG
3110Sstevel@tonic-gate cmn_err(CE_CONT, "_attach: unable to get soft interrupt\n");
3120Sstevel@tonic-gate #endif
3130Sstevel@tonic-gate return (DDI_FAILURE);
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate softp->flags |= PCATA_SOFTINTROK;
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate /*
3190Sstevel@tonic-gate * Register with Card Services
3200Sstevel@tonic-gate */
3210Sstevel@tonic-gate client_reg.Attributes =
322*7656SSherry.Moore@Sun.COM INFO_IO_CLIENT | INFO_CARD_SHARE | INFO_CARD_EXCL;
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate client_reg.EventMask =
325*7656SSherry.Moore@Sun.COM CS_EVENT_CARD_INSERTION |
326*7656SSherry.Moore@Sun.COM CS_EVENT_CARD_REMOVAL |
327*7656SSherry.Moore@Sun.COM CS_EVENT_CARD_REMOVAL_LOWP |
328*7656SSherry.Moore@Sun.COM CS_EVENT_PM_RESUME |
329*7656SSherry.Moore@Sun.COM CS_EVENT_CLIENT_INFO |
330*7656SSherry.Moore@Sun.COM CS_EVENT_PM_SUSPEND |
331*7656SSherry.Moore@Sun.COM CS_EVENT_REGISTRATION_COMPLETE;
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate client_reg.event_handler = (csfunction_t *)pcata_event;
3340Sstevel@tonic-gate client_reg.event_callback_args.client_data = softp;
3350Sstevel@tonic-gate client_reg.Version = _VERSION(2, 1);
3360Sstevel@tonic-gate client_reg.dip = dip;
3370Sstevel@tonic-gate (void) strcpy(client_reg.driver_name, pcata_name);
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate ret = csx_RegisterClient(&softp->client_handle, &client_reg);
3400Sstevel@tonic-gate if (ret != CS_SUCCESS) {
3410Sstevel@tonic-gate #ifdef ATA_DEBUG
3420Sstevel@tonic-gate cmn_err(CE_CONT, "_attach RegisterClient failed %s\n",
343*7656SSherry.Moore@Sun.COM pcata_CS_etext(ret));
3440Sstevel@tonic-gate #endif
3450Sstevel@tonic-gate return (DDI_FAILURE);
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate mutex_init(&softp->event_hilock, NULL, MUTEX_DRIVER,
349*7656SSherry.Moore@Sun.COM *(client_reg.iblk_cookie));
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate softp->flags |= PCATA_REGCLIENT;
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate * Get logical socket number and store in softp struct
3560Sstevel@tonic-gate */
3570Sstevel@tonic-gate ret = csx_MapLogSocket(softp->client_handle, &map_log_socket);
3580Sstevel@tonic-gate if (ret != CS_SUCCESS) {
3590Sstevel@tonic-gate #ifdef ATA_DEBUG
3600Sstevel@tonic-gate cmn_err(CE_CONT, "_attach: MapLogSocket failed %s\n",
361*7656SSherry.Moore@Sun.COM pcata_CS_etext(ret));
3620Sstevel@tonic-gate #endif
3630Sstevel@tonic-gate return (DDI_FAILURE);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate softp->sn = map_log_socket.PhySocket;
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate /*
3690Sstevel@tonic-gate *
3700Sstevel@tonic-gate */
3710Sstevel@tonic-gate cs_ddi_info.Socket = softp->sn;
3720Sstevel@tonic-gate cs_ddi_info.driver_name = pcata_name;
3730Sstevel@tonic-gate cs_ddi_info.dip = dip;
3740Sstevel@tonic-gate cs_ddi_info.instance = softp->instance;
3750Sstevel@tonic-gate if ((ret = csx_CS_DDI_Info(&cs_ddi_info)) != CS_SUCCESS) {
3760Sstevel@tonic-gate #ifdef ATA_DEBUG
3770Sstevel@tonic-gate cmn_err(CE_CONT, "_attach: socket %d CS_DDI_Info failed %s\n",
378*7656SSherry.Moore@Sun.COM softp->sn, pcata_CS_etext(ret));
3790Sstevel@tonic-gate #endif
3800Sstevel@tonic-gate return (DDI_FAILURE);
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate /*
3840Sstevel@tonic-gate * After the RequestSocketMask call, we start receiving events
3850Sstevel@tonic-gate */
3860Sstevel@tonic-gate sockmask.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL;
3870Sstevel@tonic-gate ret = csx_RequestSocketMask(softp->client_handle, &sockmask);
3880Sstevel@tonic-gate if (ret != CS_SUCCESS) {
3890Sstevel@tonic-gate #ifdef ATA_DEBUG
3900Sstevel@tonic-gate cmn_err(CE_CONT, "_attach: RequestSocketMask failed %s\n",
391*7656SSherry.Moore@Sun.COM pcata_CS_etext(ret));
3920Sstevel@tonic-gate #endif
3930Sstevel@tonic-gate return (DDI_FAILURE);
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate softp->flags |= PCATA_REQSOCKMASK;
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate * We may not get the CARD_READY event
3990Sstevel@tonic-gate * until after we leave this function.
4000Sstevel@tonic-gate */
4010Sstevel@tonic-gate mutex_enter(&softp->event_hilock);
4020Sstevel@tonic-gate softp->card_state |= PCATA_READY_WAIT;
4030Sstevel@tonic-gate mutex_exit(&softp->event_hilock);
4040Sstevel@tonic-gate
4050Sstevel@tonic-gate (void) csx_GetStatus(softp->client_handle, &get_status);
4060Sstevel@tonic-gate if (get_status.raw_CardState & CS_STATUS_CARD_INSERTED) {
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate /* wait for drive to be initialized */
4090Sstevel@tonic-gate (void) pcata_readywait(softp);
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate if ((softp->card_state & PCATA_CARD_INSERTED) == 0 ||
412*7656SSherry.Moore@Sun.COM (softp->flags & PCATA_READY) == 0) {
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate mutex_enter(&softp->ata_mutex);
4150Sstevel@tonic-gate mutex_enter(&softp->event_hilock);
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate softp->card_state &= ~PCATA_READY_WAIT;
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate mutex_exit(&softp->event_hilock);
4200Sstevel@tonic-gate mutex_exit(&softp->ata_mutex);
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate /*
4250Sstevel@tonic-gate * Wait for minor node creation before returning
4260Sstevel@tonic-gate */
4270Sstevel@tonic-gate pcata_minor_wait(softp);
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate /*
4300Sstevel@tonic-gate * print banner to announce device
4310Sstevel@tonic-gate */
4320Sstevel@tonic-gate ddi_report_dev(dip);
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate return (DDI_SUCCESS);
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate static int
pcata_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)4380Sstevel@tonic-gate pcata_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
4390Sstevel@tonic-gate {
4400Sstevel@tonic-gate int instance = ddi_get_instance(devi);
4410Sstevel@tonic-gate ata_soft_t *softp;
4420Sstevel@tonic-gate int ret;
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate if (cmd == DDI_SUSPEND)
445*7656SSherry.Moore@Sun.COM return (DDI_SUCCESS);
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate if (cmd != DDI_DETACH)
4480Sstevel@tonic-gate return (DDI_FAILURE);
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate softp = ddi_get_soft_state(pcata_soft, instance);
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate /*
4540Sstevel@tonic-gate * Call the card_removal routine to do any final card cleanup
4550Sstevel@tonic-gate */
4560Sstevel@tonic-gate if (CARD_PRESENT_VALID(softp)) {
4570Sstevel@tonic-gate (void) pcata_card_removal(softp, CS_EVENT_PRI_LOW);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate /*
4620Sstevel@tonic-gate * Release our socket mask - note that we can't do much
4630Sstevel@tonic-gate * if we fail these calls other than to note that
4640Sstevel@tonic-gate * the system will probably panic shortly. Perhaps
4650Sstevel@tonic-gate * we should fail the detach in the case where these
4660Sstevel@tonic-gate * CS calls fail?
4670Sstevel@tonic-gate */
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate if (softp->flags & PCATA_REQSOCKMASK) {
4700Sstevel@tonic-gate release_socket_mask_t rsm;
4710Sstevel@tonic-gate ret = csx_ReleaseSocketMask(softp->client_handle, &rsm);
4720Sstevel@tonic-gate if (ret != CS_SUCCESS) {
4730Sstevel@tonic-gate #ifdef ATA_DEBUG
4740Sstevel@tonic-gate cmn_err(CE_CONT, "_detach "
475*7656SSherry.Moore@Sun.COM "ReleaseSocketMask failed %s\n",
476*7656SSherry.Moore@Sun.COM pcata_CS_etext(ret));
4770Sstevel@tonic-gate #endif
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate /*
4830Sstevel@tonic-gate * Deregister with Card Services - we will stop getting
4840Sstevel@tonic-gate * events at this point.
4850Sstevel@tonic-gate */
4860Sstevel@tonic-gate if (softp->flags & PCATA_REGCLIENT) {
4870Sstevel@tonic-gate ret = csx_DeregisterClient(softp->client_handle);
4880Sstevel@tonic-gate if (ret != CS_SUCCESS) {
4890Sstevel@tonic-gate #ifdef ATA_DEBUG
4900Sstevel@tonic-gate cmn_err(CE_CONT, "_detach: "
491*7656SSherry.Moore@Sun.COM "DeregisterClient failed %s\n",
492*7656SSherry.Moore@Sun.COM pcata_CS_etext(ret));
4930Sstevel@tonic-gate #endif
4940Sstevel@tonic-gate return (DDI_FAILURE);
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate softp->flags &= ~PCATA_REGCLIENT;
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate /* unregister the softintrrupt handler */
5020Sstevel@tonic-gate if (softp->flags & PCATA_SOFTINTROK) {
5030Sstevel@tonic-gate ddi_remove_softintr(softp->softint_id);
5040Sstevel@tonic-gate softp->flags &= ~PCATA_SOFTINTROK;
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate }
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate if (softp->flags & PCATA_DIDLOCKS) {
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate /*
5110Sstevel@tonic-gate * XXX/lcl make sure no threads are blocked
5120Sstevel@tonic-gate */
5130Sstevel@tonic-gate mutex_destroy(&softp->ata_mutex);
5140Sstevel@tonic-gate mutex_destroy(&softp->event_hilock);
5150Sstevel@tonic-gate mutex_destroy(&softp->label_mutex);
5160Sstevel@tonic-gate cv_destroy(&softp->readywait_cv);
5170Sstevel@tonic-gate /* for DKIOCSTATE ioctl() */
5180Sstevel@tonic-gate cv_destroy(&softp->condvar_mediastate);
5190Sstevel@tonic-gate softp->flags &= ~PCATA_DIDLOCKS;
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate /* Free various structures and memory here. */
5230Sstevel@tonic-gate if (softp && softp->crashbuf)
5240Sstevel@tonic-gate freerbuf(softp->crashbuf);
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate /* Free the soft state structure here */
5270Sstevel@tonic-gate ddi_soft_state_free(pcata_soft, instance);
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate #ifdef ATA_DEBUG
5300Sstevel@tonic-gate if (pcata_debug & DPCM)
5310Sstevel@tonic-gate cmn_err(CE_NOTE, "successful detach\n");
5320Sstevel@tonic-gate #endif
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate return (DDI_SUCCESS);
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate /*
5390Sstevel@tonic-gate * Common controller object interface
5400Sstevel@tonic-gate */
5410Sstevel@tonic-gate /*
5420Sstevel@tonic-gate * initiate a new I/O request
5430Sstevel@tonic-gate * either start it or add it to the request queue
5440Sstevel@tonic-gate */
5450Sstevel@tonic-gate int
pcata_start(ata_unit_t * unitp,buf_t * bp,int blkno)5460Sstevel@tonic-gate pcata_start(ata_unit_t *unitp, buf_t *bp, int blkno)
5470Sstevel@tonic-gate {
5480Sstevel@tonic-gate ata_soft_t *softp = unitp->a_blkp;
5490Sstevel@tonic-gate struct ata_cmpkt *pktp;
5500Sstevel@tonic-gate int ret;
5510Sstevel@tonic-gate int kf = 0;
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate ASSERT(mutex_owned(&softp->ata_mutex));
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate #ifdef ATA_DEBUG
5560Sstevel@tonic-gate if (pcata_debug & DENT) {
5570Sstevel@tonic-gate cmn_err(CE_CONT, "_start unitp=%p, bp=%p bp->b_private=%p\n",
558*7656SSherry.Moore@Sun.COM (void *)unitp,
559*7656SSherry.Moore@Sun.COM (void *)bp,
560*7656SSherry.Moore@Sun.COM bp->b_private);
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate #endif
5630Sstevel@tonic-gate
5640Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp))
5650Sstevel@tonic-gate return (CTL_SEND_FAILURE);
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate /* XXX/lcl why is this different from CARD_PRESENT_VALID */
5680Sstevel@tonic-gate if (softp->ab_status_flag & ATA_OFFLINE) {
5690Sstevel@tonic-gate return (CTL_SEND_FAILURE);
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate
5720Sstevel@tonic-gate pktp = (struct ata_cmpkt *)kmem_zalloc(sizeof (*pktp), kf);
5730Sstevel@tonic-gate if (!pktp) {
5740Sstevel@tonic-gate cmn_err(CE_NOTE, "_start kmem_zalloc failed\n");
5750Sstevel@tonic-gate return (CTL_SEND_FAILURE);
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate #ifdef ATA_DEBUG
5790Sstevel@tonic-gate if (pcata_debug & DENT)
5800Sstevel@tonic-gate cmn_err(CE_CONT, "_start pktp=%p\n", (void *)pktp);
5810Sstevel@tonic-gate #endif
5820Sstevel@tonic-gate
5830Sstevel@tonic-gate if ((bp->b_flags & B_PAGEIO) || (bp->b_flags & B_PHYS))
5840Sstevel@tonic-gate bp_mapin(bp);
5850Sstevel@tonic-gate
5860Sstevel@tonic-gate pktp->ac_bytes_per_block = unitp->au_bytes_per_block;
5870Sstevel@tonic-gate pktp->ac_start_v_addr = bp->b_un.b_addr; /* xfer address */
5880Sstevel@tonic-gate pktp->cp_bytexfer = bp->b_bcount;
5890Sstevel@tonic-gate pktp->cp_bp = bp;
5900Sstevel@tonic-gate pktp->cp_ctl_private = unitp;
5910Sstevel@tonic-gate pktp->cp_srtsec = blkno;
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate if (bp->b_flags & B_READ) {
5940Sstevel@tonic-gate pktp->ac_direction = AT_IN;
5950Sstevel@tonic-gate pktp->ac_cdb = DCMD_READ;
5960Sstevel@tonic-gate } else {
5970Sstevel@tonic-gate pktp->ac_direction = AT_OUT;
5980Sstevel@tonic-gate pktp->ac_cdb = DCMD_WRITE;
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate /*
6020Sstevel@tonic-gate * b_private is set to 0xBEE by pcata_buf_setup
6030Sstevel@tonic-gate * which is called by an ioctl DIOCTL_RWCMD with a subcommand
6040Sstevel@tonic-gate * of either DADKIO_RWCMD_READ or DADKIO_RWCMD_WRITE
6050Sstevel@tonic-gate *
6060Sstevel@tonic-gate * these commands are used to do I/O through the IOCTL interface
6070Sstevel@tonic-gate *
6080Sstevel@tonic-gate * b_back contains a pointer to the ioctl packet struct (dadkio_rwcmd)
6090Sstevel@tonic-gate */
6100Sstevel@tonic-gate if (bp->b_private == (void *)0xBEE)
6110Sstevel@tonic-gate pktp->cp_passthru = bp->b_back;
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate #ifdef ATA_DEBUG
6140Sstevel@tonic-gate if (pcata_debug & DIO) {
6150Sstevel@tonic-gate cmn_err(CE_CONT, "passthru command seen: 0x%p\n",
616*7656SSherry.Moore@Sun.COM pktp->cp_passthru);
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate #endif
6190Sstevel@tonic-gate
6200Sstevel@tonic-gate pcata_iosetup(unitp, pktp); /* fill a packet */
6210Sstevel@tonic-gate pktp->pkt_forw = 0;
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate #ifdef ATA_DEBUG
6240Sstevel@tonic-gate if (pcata_debug & DIO) {
6250Sstevel@tonic-gate cmn_err(CE_CONT, "_start: active: %c head: %c\n",
626*7656SSherry.Moore@Sun.COM (softp->ab_active == NULL ? 'N' : 'Y'),
627*7656SSherry.Moore@Sun.COM (softp->ab_head == NULL ? 'N' : 'Y'));
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate #endif
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate if (softp->ab_active == NULL) {
6320Sstevel@tonic-gate /*
6330Sstevel@tonic-gate * The controller is idle.
6340Sstevel@tonic-gate * Put the packet in ab_active....
6350Sstevel@tonic-gate */
6360Sstevel@tonic-gate softp->ab_active = pktp;
6370Sstevel@tonic-gate /*
6380Sstevel@tonic-gate * ... and start it off
6390Sstevel@tonic-gate */
6400Sstevel@tonic-gate ret = PCATA_GO_RETRY;
6410Sstevel@tonic-gate while (ret == PCATA_GO_RETRY) {
6420Sstevel@tonic-gate ret = pcata_go(unitp);
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate if (ret == DDI_FAILURE) {
6450Sstevel@tonic-gate cmn_err(CE_NOTE, "start_cmd failure \n");
6460Sstevel@tonic-gate softp->ab_active = NULL;
6470Sstevel@tonic-gate return (CTL_SEND_FAILURE);
6480Sstevel@tonic-gate }
6490Sstevel@tonic-gate
6500Sstevel@tonic-gate } else {
6510Sstevel@tonic-gate /*
6520Sstevel@tonic-gate * the controller is busy now so put the packet
6530Sstevel@tonic-gate * on ab_head or ab_last.
6540Sstevel@tonic-gate */
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate if (softp->ab_head == NULL)
6570Sstevel@tonic-gate softp->ab_head = pktp;
6580Sstevel@tonic-gate else
6590Sstevel@tonic-gate softp->ab_last->pkt_forw = pktp;
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate softp->ab_last = pktp;
6620Sstevel@tonic-gate }
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate return (CTL_SEND_SUCCESS);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate
6680Sstevel@tonic-gate /*
6690Sstevel@tonic-gate * initiate I/O for packet linked on ab_active
6700Sstevel@tonic-gate */
6710Sstevel@tonic-gate static int
pcata_go(ata_unit_t * unitp)6720Sstevel@tonic-gate pcata_go(ata_unit_t *unitp)
6730Sstevel@tonic-gate {
6740Sstevel@tonic-gate ata_soft_t *softp = unitp->a_blkp;
6750Sstevel@tonic-gate struct ata_cmpkt *pktp = softp->ab_active;
6760Sstevel@tonic-gate uint32_t nbytes;
6770Sstevel@tonic-gate uint32_t start_sec;
6780Sstevel@tonic-gate uint32_t cyl;
6790Sstevel@tonic-gate uint32_t resid;
6800Sstevel@tonic-gate uchar_t head;
6810Sstevel@tonic-gate uchar_t drvheads;
6820Sstevel@tonic-gate uchar_t drvsectors;
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate uchar_t ac_devctl;
6850Sstevel@tonic-gate uchar_t ac_sec;
6860Sstevel@tonic-gate uchar_t ac_count;
6870Sstevel@tonic-gate uchar_t ac_lwcyl;
6880Sstevel@tonic-gate uchar_t ac_hicyl;
6890Sstevel@tonic-gate uchar_t ac_hd;
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate ASSERT(mutex_owned(&softp->ata_mutex));
6920Sstevel@tonic-gate
6930Sstevel@tonic-gate if (pktp == NULL)
6940Sstevel@tonic-gate return (DDI_SUCCESS);
6950Sstevel@tonic-gate
6960Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp)) {
6970Sstevel@tonic-gate pktp->ac_scb = DERR_ABORT;
6980Sstevel@tonic-gate pktp->cp_reason = CPS_CHKERR;
6990Sstevel@tonic-gate return (DDI_FAILURE);
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate #ifdef ATA_DEBUG
7030Sstevel@tonic-gate if (pcata_debug & DENT) {
7040Sstevel@tonic-gate cmn_err(CE_CONT, "_go (%p) altstatus %x error %x\n",
705*7656SSherry.Moore@Sun.COM (void *)unitp,
706*7656SSherry.Moore@Sun.COM csx_Get8(softp->handle, AT_ALTSTATUS),
707*7656SSherry.Moore@Sun.COM csx_Get8(softp->handle, AT_ERROR));
7080Sstevel@tonic-gate cmn_err(CE_CONT, "_go handle=%p\n", softp->handle);
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate #endif
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate /*
7130Sstevel@tonic-gate * calculate drive address based on pktp->cp_srtsec
7140Sstevel@tonic-gate */
7150Sstevel@tonic-gate start_sec = pktp->cp_srtsec;
7160Sstevel@tonic-gate drvheads = unitp->au_hd;
7170Sstevel@tonic-gate drvsectors = unitp->au_sec;
7180Sstevel@tonic-gate resid = start_sec / drvsectors;
7190Sstevel@tonic-gate head = resid % drvheads;
7200Sstevel@tonic-gate cyl = resid / drvheads;
7210Sstevel@tonic-gate nbytes = min(pktp->cp_resid, pktp->ac_bytes_per_block);
7220Sstevel@tonic-gate ac_count = (nbytes >> SCTRSHFT);
7230Sstevel@tonic-gate ac_devctl = unitp->au_ctl_bits;
7240Sstevel@tonic-gate ac_sec = (start_sec % drvsectors) + 1;
7250Sstevel@tonic-gate ac_hd = head | unitp->au_drive_bits;
7260Sstevel@tonic-gate ac_lwcyl = cyl;
7270Sstevel@tonic-gate ac_hicyl = (cyl >> 8);
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate #ifdef ATA_DEBUG
7300Sstevel@tonic-gate if (pcata_debug & DIO) {
7310Sstevel@tonic-gate cmn_err(CE_CONT,
732*7656SSherry.Moore@Sun.COM "_go %s at lba=%d (%uc %uh %us) "
733*7656SSherry.Moore@Sun.COM "%d sectors cmd=%x ctl=%x\n",
734*7656SSherry.Moore@Sun.COM (pktp->ac_direction == AT_OUT) ? "WT" : "RD",
735*7656SSherry.Moore@Sun.COM start_sec, cyl, head, ac_sec,
736*7656SSherry.Moore@Sun.COM ac_count,
737*7656SSherry.Moore@Sun.COM pktp->ac_cmd, ac_devctl);
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate #endif
7400Sstevel@tonic-gate
7410Sstevel@tonic-gate if (pcata_wait(AT_ALTSTATUS, ATS_DRDY, ATS_BSY, softp))
7420Sstevel@tonic-gate return (DDI_FAILURE);
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate pcata_wait_complete(softp);
7450Sstevel@tonic-gate
7460Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_DEVCTL, ac_devctl);
7470Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_SECT, ac_sec);
7480Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_COUNT, ac_count);
7490Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_LCYL, ac_lwcyl);
7500Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_HCYL, ac_hicyl);
7510Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_DRVHD, ac_hd);
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate /*
7540Sstevel@tonic-gate * the command should make the controller status show BSY
7550Sstevel@tonic-gate * the ISR intr_hi will not record status while the controller is BSY
7560Sstevel@tonic-gate * therefore set interrupt expected state now
7570Sstevel@tonic-gate * the next time we receive an interrupt and the controller is not BSY
7580Sstevel@tonic-gate * the ISR will do the right thing
7590Sstevel@tonic-gate */
7600Sstevel@tonic-gate
7610Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
7620Sstevel@tonic-gate softp->intr_pending++;
7630Sstevel@tonic-gate if (pktp->ac_direction == AT_OUT)
7640Sstevel@tonic-gate softp->write_in_progress++;
7650Sstevel@tonic-gate csx_Put8(softp->handle, AT_CMD, pktp->ac_cmd);
7660Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
7670Sstevel@tonic-gate
7680Sstevel@tonic-gate /*
7690Sstevel@tonic-gate * If there's data to go along with the command, send it now.
7700Sstevel@tonic-gate */
7710Sstevel@tonic-gate if (pktp->ac_direction == AT_OUT) {
7720Sstevel@tonic-gate if (pcata_send_data(unitp, nbytes) == DDI_FAILURE) {
7730Sstevel@tonic-gate if (pktp->cp_retry >= RETRY_CNT) {
7740Sstevel@tonic-gate pcata_clear_queues(unitp);
7750Sstevel@tonic-gate return (DDI_FAILURE);
7760Sstevel@tonic-gate } else {
7770Sstevel@tonic-gate pktp->cp_retry++;
7780Sstevel@tonic-gate cmn_err(CE_CONT, "_go: write failure,"
7790Sstevel@tonic-gate " retry=%d \n", pktp->cp_retry);
7800Sstevel@tonic-gate cmn_err(CE_CONT,
7810Sstevel@tonic-gate "_go at lba=%d (%uc %uh %us) "
7820Sstevel@tonic-gate "%d sectors cmd=%x ctl=%x \n",
7830Sstevel@tonic-gate start_sec, cyl, head, ac_sec,
7840Sstevel@tonic-gate ac_count,
7850Sstevel@tonic-gate pktp->ac_cmd, ac_devctl);
7860Sstevel@tonic-gate return (PCATA_GO_RETRY);
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate }
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate
7910Sstevel@tonic-gate return (DDI_SUCCESS);
7920Sstevel@tonic-gate }
7930Sstevel@tonic-gate
7940Sstevel@tonic-gate /*
7950Sstevel@tonic-gate * return value
7960Sstevel@tonic-gate * success means go on o next block
7970Sstevel@tonic-gate * failure means continue with current block
7980Sstevel@tonic-gate */
7990Sstevel@tonic-gate static void
pcata_iocmpl(ata_soft_t * softp)8000Sstevel@tonic-gate pcata_iocmpl(ata_soft_t *softp)
8010Sstevel@tonic-gate {
8020Sstevel@tonic-gate struct ata_cmpkt *pktp;
8030Sstevel@tonic-gate ata_unit_t *unitp;
8040Sstevel@tonic-gate int nbytes;
8050Sstevel@tonic-gate int ret;
8060Sstevel@tonic-gate uchar_t status;
8070Sstevel@tonic-gate uchar_t error;
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate ASSERT(mutex_owned(&softp->ata_mutex));
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp)) {
8120Sstevel@tonic-gate cmn_err(CE_CONT, "?_iocmpl Device not present\n");
8130Sstevel@tonic-gate return;
8140Sstevel@tonic-gate }
8150Sstevel@tonic-gate
8160Sstevel@tonic-gate pktp = softp->ab_active;
8170Sstevel@tonic-gate
8180Sstevel@tonic-gate error = pktp->ac_error;
8190Sstevel@tonic-gate status = pktp->ac_status;
8200Sstevel@tonic-gate
8210Sstevel@tonic-gate unitp = (ata_unit_t *)pktp->cp_ctl_private;
8220Sstevel@tonic-gate
8230Sstevel@tonic-gate /*
8240Sstevel@tonic-gate * If there was an error, quit now
8250Sstevel@tonic-gate * XXX/lcl no retry is attempted?
8260Sstevel@tonic-gate */
8270Sstevel@tonic-gate if ((status & ATS_ERR) || (error & ATE_ABORT)) {
8280Sstevel@tonic-gate #ifdef ATA_DEBUG
8290Sstevel@tonic-gate if (pcata_debug & DIO)
8300Sstevel@tonic-gate cmn_err(CE_CONT,
831*7656SSherry.Moore@Sun.COM "_iocmpl I/O error status=%04x error=%04x\n",
832*7656SSherry.Moore@Sun.COM status,
833*7656SSherry.Moore@Sun.COM error);
8340Sstevel@tonic-gate #endif
8350Sstevel@tonic-gate pktp->cp_reason = CPS_CHKERR;
8360Sstevel@tonic-gate return;
8370Sstevel@tonic-gate }
8380Sstevel@tonic-gate
8390Sstevel@tonic-gate nbytes = min(pktp->cp_resid, pktp->ac_bytes_per_block);
8400Sstevel@tonic-gate
8410Sstevel@tonic-gate if (pktp->ac_direction == AT_IN) {
8420Sstevel@tonic-gate /*
8430Sstevel@tonic-gate * do the read of the block
8440Sstevel@tonic-gate */
8450Sstevel@tonic-gate ret = pcata_get_data(unitp, nbytes);
8460Sstevel@tonic-gate if (ret == DDI_FAILURE) {
8470Sstevel@tonic-gate /*
8480Sstevel@tonic-gate * If the controller never presented the data
8490Sstevel@tonic-gate * and the error bit isn't set,
8500Sstevel@tonic-gate * there's a real problem. Kill it now.
8510Sstevel@tonic-gate */
8520Sstevel@tonic-gate pcata_clear_queues(unitp);
8530Sstevel@tonic-gate return;
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate /*
8580Sstevel@tonic-gate * update counts...
8590Sstevel@tonic-gate */
8600Sstevel@tonic-gate pktp->ac_v_addr += nbytes;
8610Sstevel@tonic-gate pktp->cp_resid -= nbytes;
8620Sstevel@tonic-gate pktp->cp_reason = CPS_SUCCESS;
8630Sstevel@tonic-gate pktp->cp_srtsec += (nbytes >> SCTRSHFT);
8640Sstevel@tonic-gate
8650Sstevel@tonic-gate /* If last command was a GET_DEFECTS delay a bit */
8660Sstevel@tonic-gate if (pktp->ac_cmd == ATC_READDEFECTS)
8670Sstevel@tonic-gate drv_usecwait(1000);
8680Sstevel@tonic-gate }
8690Sstevel@tonic-gate
8700Sstevel@tonic-gate int
pcata_intr_hi(ata_soft_t * softp)8710Sstevel@tonic-gate pcata_intr_hi(ata_soft_t *softp)
8720Sstevel@tonic-gate {
8730Sstevel@tonic-gate /*
8740Sstevel@tonic-gate * In ata there is no hardware support to tell if the interrupt
8750Sstevel@tonic-gate * belongs to ata or not. So no checks necessary here. Later
8760Sstevel@tonic-gate * will check the buffer and see if we have started a transaction.
8770Sstevel@tonic-gate */
8780Sstevel@tonic-gate
8790Sstevel@tonic-gate int rval = DDI_INTR_UNCLAIMED;
8800Sstevel@tonic-gate struct ata_cmpkt *pktp;
8810Sstevel@tonic-gate uchar_t status;
8820Sstevel@tonic-gate uchar_t error;
8830Sstevel@tonic-gate
8840Sstevel@tonic-gate #ifdef ATA_DEBUG
8850Sstevel@tonic-gate if (pcata_debug & DENT) {
8860Sstevel@tonic-gate cmn_err(CE_CONT,
8870Sstevel@tonic-gate "_intr_hi sn=%d status=%x intr_pending=%d "
8880Sstevel@tonic-gate "softint_pending=%d wr_in_prog=%d\n",
8890Sstevel@tonic-gate softp->sn, csx_Get8(softp->handle, AT_ALTSTATUS),
8900Sstevel@tonic-gate softp->intr_pending, softp->softint_pending,
8910Sstevel@tonic-gate softp->write_in_progress);
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate #endif
8940Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
8950Sstevel@tonic-gate
8960Sstevel@tonic-gate /*
8970Sstevel@tonic-gate * this test is not redundant (don't remove it)
8980Sstevel@tonic-gate * it is part of card removal processing
8990Sstevel@tonic-gate * and prevents losing interrupt threads
9000Sstevel@tonic-gate */
9010Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp)) {
9020Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
9030Sstevel@tonic-gate return (rval);
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate status = csx_Get8(softp->handle, AT_ALTSTATUS);
9070Sstevel@tonic-gate
9080Sstevel@tonic-gate /*
9090Sstevel@tonic-gate * this is a shared interrupt
9100Sstevel@tonic-gate * if the controller is NOT busy,
9110Sstevel@tonic-gate * and an interrupt is expected
9120Sstevel@tonic-gate */
9130Sstevel@tonic-gate
9140Sstevel@tonic-gate if ((status & ATS_ERR) &&
9150Sstevel@tonic-gate ((status & ATS_BSY) == 0) &&
9160Sstevel@tonic-gate (softp->intr_pending > 0)) {
9170Sstevel@tonic-gate cmn_err(CE_CONT,
918*7656SSherry.Moore@Sun.COM "?_intr_hi sn=%d status=%x\n",
919*7656SSherry.Moore@Sun.COM softp->sn, status);
9200Sstevel@tonic-gate /* handle aborted commands */
9210Sstevel@tonic-gate error = csx_Get8(softp->handle, AT_ERROR);
9220Sstevel@tonic-gate if ((error & ATE_ABORT) &&
9230Sstevel@tonic-gate (softp->write_in_progress > 0)) {
9240Sstevel@tonic-gate softp->write_in_progress = 0;
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate if ((status & ATS_BSY) == 0 &&
9290Sstevel@tonic-gate (softp->write_in_progress == 0) &&
9300Sstevel@tonic-gate (softp->intr_pending > 0)) {
9310Sstevel@tonic-gate /*
9320Sstevel@tonic-gate * Read the status register,
9330Sstevel@tonic-gate * this clears an interrupt from the ata device
9340Sstevel@tonic-gate */
9350Sstevel@tonic-gate status = csx_Get8(softp->handle, AT_STATUS);
9360Sstevel@tonic-gate error = csx_Get8(softp->handle, AT_ERROR);
9370Sstevel@tonic-gate rval = DDI_INTR_CLAIMED;
9380Sstevel@tonic-gate softp->intr_pending--;
9390Sstevel@tonic-gate /*
9400Sstevel@tonic-gate * Make sure the interrupt is cleared, occasionally it is not
9410Sstevel@tonic-gate * cleared by the first status read.
9420Sstevel@tonic-gate */
9430Sstevel@tonic-gate status = csx_Get8(softp->handle, AT_STATUS);
9440Sstevel@tonic-gate /* put the error status in the right place */
9450Sstevel@tonic-gate if ((pktp = softp->ab_active) != 0) {
9460Sstevel@tonic-gate pktp->ac_error = error;
9470Sstevel@tonic-gate pktp->ac_status = status;
9480Sstevel@tonic-gate }
9490Sstevel@tonic-gate }
9500Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
9510Sstevel@tonic-gate
9520Sstevel@tonic-gate #ifdef ATA_DEBUG
9530Sstevel@tonic-gate if (pcata_debug & DENT)
9540Sstevel@tonic-gate cmn_err(CE_CONT,
955*7656SSherry.Moore@Sun.COM "_intr_hi status=%x error=%x claimed=%d pending=%d\n",
956*7656SSherry.Moore@Sun.COM status, error,
957*7656SSherry.Moore@Sun.COM (rval == DDI_INTR_CLAIMED),
958*7656SSherry.Moore@Sun.COM softp->intr_pending);
9590Sstevel@tonic-gate #endif
9600Sstevel@tonic-gate
9610Sstevel@tonic-gate if ((rval == DDI_INTR_CLAIMED) &&
9620Sstevel@tonic-gate (softp->ab_active != NULL)) {
9630Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
9640Sstevel@tonic-gate softp->softint_pending++;
9650Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
9660Sstevel@tonic-gate ddi_trigger_softintr(softp->softint_id);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate
9690Sstevel@tonic-gate return (rval);
9700Sstevel@tonic-gate }
9710Sstevel@tonic-gate
9720Sstevel@tonic-gate uint32_t
pcata_intr(char * parm)9730Sstevel@tonic-gate pcata_intr(char *parm)
9740Sstevel@tonic-gate {
9750Sstevel@tonic-gate ata_soft_t *softp = (ata_soft_t *)parm;
9760Sstevel@tonic-gate ata_unit_t *unitp;
9770Sstevel@tonic-gate struct ata_cmpkt *pktp;
9780Sstevel@tonic-gate buf_t *bp;
9790Sstevel@tonic-gate uint32_t nbytes;
9800Sstevel@tonic-gate uint32_t start_sec;
9810Sstevel@tonic-gate uint32_t cyl;
9820Sstevel@tonic-gate uint32_t resid;
9830Sstevel@tonic-gate uchar_t head;
9840Sstevel@tonic-gate uchar_t drvheads;
9850Sstevel@tonic-gate uchar_t drvsectors;
9860Sstevel@tonic-gate uchar_t ac_devctl;
9870Sstevel@tonic-gate uchar_t ac_sec;
9880Sstevel@tonic-gate uchar_t ac_count;
9890Sstevel@tonic-gate int ret;
9900Sstevel@tonic-gate
9910Sstevel@tonic-gate #ifdef ATA_DEBUG
9920Sstevel@tonic-gate if (pcata_debug & DENT) {
9930Sstevel@tonic-gate cmn_err(CE_CONT, "_intr entry (%p) sn=%d softint_pending=%d\n",
9940Sstevel@tonic-gate (void *)softp, softp->sn, softp->softint_pending);
9950Sstevel@tonic-gate }
9960Sstevel@tonic-gate #endif
9970Sstevel@tonic-gate
9980Sstevel@tonic-gate
9990Sstevel@tonic-gate if (softp->softint_pending == 0) {
10000Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED);
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate mutex_enter(&softp->ata_mutex);
10040Sstevel@tonic-gate
10050Sstevel@tonic-gate if (softp->ab_active == NULL) {
10060Sstevel@tonic-gate cmn_err(CE_CONT, "?_intr No outstanding I/O\n");
10070Sstevel@tonic-gate goto done;
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate
10100Sstevel@tonic-gate /* perform I/O completion */
10110Sstevel@tonic-gate pcata_iocmpl(softp);
10120Sstevel@tonic-gate
10130Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp))
10140Sstevel@tonic-gate goto done;
10150Sstevel@tonic-gate
10160Sstevel@tonic-gate /*
10170Sstevel@tonic-gate * if packet is done (either errors or all bytes transfered)
10180Sstevel@tonic-gate * pktp points to current packet
10190Sstevel@tonic-gate * ab_active is cleared
10200Sstevel@tonic-gate * else
10210Sstevel@tonic-gate * pktp is null
10220Sstevel@tonic-gate * ab_active is unchanged
10230Sstevel@tonic-gate */
10240Sstevel@tonic-gate pktp = softp->ab_active;
10250Sstevel@tonic-gate if (pktp != NULL) {
10260Sstevel@tonic-gate if (pktp->cp_resid == 0 || pktp->cp_reason != CPS_SUCCESS) {
10270Sstevel@tonic-gate #ifdef ATA_DEBUG
10280Sstevel@tonic-gate if (pcata_debug & DENT) {
10290Sstevel@tonic-gate cmn_err(CE_CONT, "_intr retry=%d reason=%d"
10300Sstevel@tonic-gate " CPS_SUCCESS=%d pkpt=%p cp_resid = %d\n",
10310Sstevel@tonic-gate pktp->cp_retry, pktp->cp_reason,
10320Sstevel@tonic-gate CPS_SUCCESS, (void *)pktp,
10330Sstevel@tonic-gate pktp->cp_resid);
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate #endif
10360Sstevel@tonic-gate if ((pktp->cp_retry < RETRY_CNT) &&
10370Sstevel@tonic-gate (pktp->cp_reason != CPS_SUCCESS)) {
10380Sstevel@tonic-gate pktp->cp_retry++;
10390Sstevel@tonic-gate unitp = softp->ab_active->cp_ctl_private;
10400Sstevel@tonic-gate
10410Sstevel@tonic-gate /*
10420Sstevel@tonic-gate * calculate drive address based on
10430Sstevel@tonic-gate * pktp->cp_srtsec
10440Sstevel@tonic-gate */
10450Sstevel@tonic-gate start_sec = pktp->cp_srtsec;
10460Sstevel@tonic-gate drvheads = unitp->au_hd;
10470Sstevel@tonic-gate drvsectors = unitp->au_sec;
10480Sstevel@tonic-gate resid = start_sec / drvsectors;
10490Sstevel@tonic-gate head = resid % drvheads;
10500Sstevel@tonic-gate cyl = resid / drvheads;
10510Sstevel@tonic-gate nbytes = min(pktp->cp_resid,
10520Sstevel@tonic-gate pktp->ac_bytes_per_block);
10530Sstevel@tonic-gate ac_count = (nbytes >> SCTRSHFT);
10540Sstevel@tonic-gate ac_devctl = unitp->au_ctl_bits;
10550Sstevel@tonic-gate ac_sec = (start_sec % drvsectors) + 1;
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate cmn_err(CE_CONT, "_intr I/O failure,"
10580Sstevel@tonic-gate " retry %d\n", pktp->cp_retry);
10590Sstevel@tonic-gate cmn_err(CE_CONT,
10600Sstevel@tonic-gate "_intr %s at lba=%d (%uc %uh %us) "
10610Sstevel@tonic-gate "%d sectors cmd=%x ctl=%x\n",
10620Sstevel@tonic-gate (pktp->ac_direction == AT_OUT) ?
10630Sstevel@tonic-gate "write" : "read",
10640Sstevel@tonic-gate start_sec, cyl, head, ac_sec,
10650Sstevel@tonic-gate ac_count,
10660Sstevel@tonic-gate pktp->ac_cmd, ac_devctl);
10670Sstevel@tonic-gate
10680Sstevel@tonic-gate pktp = 0;
10690Sstevel@tonic-gate } else {
10700Sstevel@tonic-gate /* I/O is complete or an error has occured */
10710Sstevel@tonic-gate softp->ab_active = NULL;
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate } else {
10740Sstevel@tonic-gate /* I/O is still in progress */
10750Sstevel@tonic-gate pktp = 0;
10760Sstevel@tonic-gate }
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate
10790Sstevel@tonic-gate /*
10800Sstevel@tonic-gate * packet which caused this interrupt is now complete
10810Sstevel@tonic-gate */
10820Sstevel@tonic-gate if (pktp) {
10830Sstevel@tonic-gate if ((pktp->ac_status & ATS_ERR) || (pktp->ac_error)) {
10840Sstevel@tonic-gate bioerror(pktp->cp_bp, EIO);
10850Sstevel@tonic-gate #ifdef ATA_DEBUG
10860Sstevel@tonic-gate cmn_err(CE_NOTE, "_intr ATA ERROR status=%x error=%x\n",
10870Sstevel@tonic-gate pktp->ac_status, pktp->ac_error);
10880Sstevel@tonic-gate #endif
10890Sstevel@tonic-gate }
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate bp = pktp->cp_bp;
10920Sstevel@tonic-gate bp->b_resid = bp->b_bcount - pktp->cp_bytexfer;
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate /* release the thread for the I/O just completed */
10950Sstevel@tonic-gate biodone(bp);
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate kmem_free((void *)pktp, sizeof (*pktp));
10980Sstevel@tonic-gate }
10990Sstevel@tonic-gate
11000Sstevel@tonic-gate
11010Sstevel@tonic-gate /* if ab_active is NULL attempt to dequeue next I/O request */
11020Sstevel@tonic-gate if (softp->ab_active == NULL && softp->ab_head != NULL) {
11030Sstevel@tonic-gate softp->ab_active = softp->ab_head;
11040Sstevel@tonic-gate softp->ab_head = softp->ab_head->pkt_forw;
11050Sstevel@tonic-gate
11060Sstevel@tonic-gate #ifdef ATA_DEBUG
11070Sstevel@tonic-gate if (pcata_debug & DIO) {
11080Sstevel@tonic-gate cmn_err(CE_CONT,
1109*7656SSherry.Moore@Sun.COM "_start_next_cmd current:%p head:%p\n",
1110*7656SSherry.Moore@Sun.COM (void *)softp->ab_active,
1111*7656SSherry.Moore@Sun.COM (void *)softp->ab_head);
11120Sstevel@tonic-gate }
11130Sstevel@tonic-gate #endif
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate
11160Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
11170Sstevel@tonic-gate softp->softint_pending--;
11180Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
11190Sstevel@tonic-gate
11200Sstevel@tonic-gate /* if ab_active is not NULL, attempt to initiate I/O */
11210Sstevel@tonic-gate if (softp->ab_active != NULL) {
11220Sstevel@tonic-gate unitp = softp->ab_active->cp_ctl_private;
11230Sstevel@tonic-gate
11240Sstevel@tonic-gate ret = PCATA_GO_RETRY;
11250Sstevel@tonic-gate while (ret == PCATA_GO_RETRY) {
11260Sstevel@tonic-gate ret = pcata_go(unitp);
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate }
11290Sstevel@tonic-gate goto exit;
11300Sstevel@tonic-gate
11310Sstevel@tonic-gate done:
11320Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
11330Sstevel@tonic-gate softp->softint_pending--;
11340Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
11350Sstevel@tonic-gate exit:
11360Sstevel@tonic-gate mutex_exit(&softp->ata_mutex);
11370Sstevel@tonic-gate #ifdef ATA_DEBUG
11380Sstevel@tonic-gate if (pcata_debug & DENT)
11390Sstevel@tonic-gate cmn_err(CE_CONT, "_intr exit (%p)\n", (void *)softp);
11400Sstevel@tonic-gate #endif
11410Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
11420Sstevel@tonic-gate }
11430Sstevel@tonic-gate
11440Sstevel@tonic-gate
11450Sstevel@tonic-gate /*
11460Sstevel@tonic-gate * XXX/lcl need determine if all drives or a single drive is to be cleared
11470Sstevel@tonic-gate * if all drives then eliminate tests for pktp->cp_ctl_private == unitp
11480Sstevel@tonic-gate * if single drive then examine usage of flag ATA_OFFLINE
11490Sstevel@tonic-gate */
11500Sstevel@tonic-gate static void
pcata_clear_queues(ata_unit_t * unitp)11510Sstevel@tonic-gate pcata_clear_queues(ata_unit_t *unitp)
11520Sstevel@tonic-gate {
11530Sstevel@tonic-gate ata_soft_t *softp = unitp->a_blkp;
11540Sstevel@tonic-gate struct ata_cmpkt *pktp;
11550Sstevel@tonic-gate buf_t *bp;
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate ASSERT(mutex_owned(&softp->ata_mutex));
11580Sstevel@tonic-gate
11590Sstevel@tonic-gate #ifdef ATA_DEBUG
11600Sstevel@tonic-gate if (pcata_debug & DENT) {
11610Sstevel@tonic-gate cmn_err(CE_CONT, "_clear_queues (%p)\n", (void *)unitp);
11620Sstevel@tonic-gate }
11630Sstevel@tonic-gate #endif
11640Sstevel@tonic-gate /*
11650Sstevel@tonic-gate * nack the active request
11660Sstevel@tonic-gate */
11670Sstevel@tonic-gate softp->ab_status_flag |= ATA_OFFLINE;
11680Sstevel@tonic-gate
11690Sstevel@tonic-gate pktp = softp->ab_active;
11700Sstevel@tonic-gate if (pktp && pktp->cp_ctl_private == unitp)
11710Sstevel@tonic-gate pcata_nack_packet(pktp);
11720Sstevel@tonic-gate
11730Sstevel@tonic-gate /*
11740Sstevel@tonic-gate * now nack all queued requests
11750Sstevel@tonic-gate */
11760Sstevel@tonic-gate for (pktp = softp->ab_head; pktp; pktp = pktp->pkt_forw) {
11770Sstevel@tonic-gate bp = pktp->cp_bp;
11780Sstevel@tonic-gate if (bp && ((bp->b_flags & B_DONE) == 0)) {
11790Sstevel@tonic-gate if ((pktp->ac_status & ATS_ERR) || (pktp->ac_error)) {
11800Sstevel@tonic-gate bioerror(bp, EIO);
11810Sstevel@tonic-gate }
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate /* release the thread for the I/O */
11840Sstevel@tonic-gate biodone(bp);
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate if (pktp->cp_ctl_private == unitp)
11870Sstevel@tonic-gate pcata_nack_packet(pktp);
11880Sstevel@tonic-gate }
11890Sstevel@tonic-gate }
11900Sstevel@tonic-gate
11910Sstevel@tonic-gate static void
pcata_nack_packet(struct ata_cmpkt * pktp)11920Sstevel@tonic-gate pcata_nack_packet(struct ata_cmpkt *pktp)
11930Sstevel@tonic-gate {
11940Sstevel@tonic-gate #ifdef ATA_DEBUG
11950Sstevel@tonic-gate if (pcata_debug & DENT)
11960Sstevel@tonic-gate cmn_err(CE_CONT, "pcata_nack_packet (%p)\n", (void *)pktp);
11970Sstevel@tonic-gate #endif
11980Sstevel@tonic-gate if (pktp != NULL) {
11990Sstevel@tonic-gate pktp->cp_reason = CPS_CHKERR;
12000Sstevel@tonic-gate pktp->ac_scb = DERR_ABORT;
12010Sstevel@tonic-gate }
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate
12040Sstevel@tonic-gate /*
12050Sstevel@tonic-gate * pcata_wait -- wait for a register of a controller to achieve a
12060Sstevel@tonic-gate * specific state. Arguments are a mask of bits we care about,
12070Sstevel@tonic-gate * and two sub-masks. To return normally, all the bits in the
12080Sstevel@tonic-gate * first sub-mask must be ON, all the bits in the second sub-
12090Sstevel@tonic-gate * mask must be OFF. If 5 seconds pass without the controller
12100Sstevel@tonic-gate * achieving the desired bit configuration, we return 1, else
12110Sstevel@tonic-gate * 0.
12120Sstevel@tonic-gate */
12130Sstevel@tonic-gate static int
pcata_wait(uint32_t port,ushort_t onbits,ushort_t offbits,ata_soft_t * softp)12140Sstevel@tonic-gate pcata_wait(uint32_t port, ushort_t onbits, ushort_t offbits, ata_soft_t *softp)
12150Sstevel@tonic-gate {
12160Sstevel@tonic-gate register int i;
12170Sstevel@tonic-gate register ushort_t maskval;
12180Sstevel@tonic-gate int ival = csx_Get8(softp->handle, port);
12190Sstevel@tonic-gate
12200Sstevel@tonic-gate for (i = 400000; i && (CARD_PRESENT_VALID(softp)); i--) {
12210Sstevel@tonic-gate maskval = csx_Get8(softp->handle, port);
12220Sstevel@tonic-gate if (((maskval & onbits) == onbits) &&
1223*7656SSherry.Moore@Sun.COM ((maskval & offbits) == 0))
12240Sstevel@tonic-gate return (0);
12250Sstevel@tonic-gate drv_usecwait(10);
12260Sstevel@tonic-gate }
12270Sstevel@tonic-gate #ifdef ATA_DEBUG
12280Sstevel@tonic-gate cmn_err(CE_CONT, "_wait timeout: "
12290Sstevel@tonic-gate "sn=%d port=%x on: 0x%x off: 0x%x ival: 0x%x eval: 0x%x\n",
12300Sstevel@tonic-gate softp->sn, port, onbits, offbits, ival, maskval);
12310Sstevel@tonic-gate #endif
12320Sstevel@tonic-gate return (1);
12330Sstevel@tonic-gate }
12340Sstevel@tonic-gate
12350Sstevel@tonic-gate
12360Sstevel@tonic-gate /*
12370Sstevel@tonic-gate * Similar to pcata_wait but the timeout is much shorter. It is only used
12380Sstevel@tonic-gate * during initialization when long delays are noticable.
12390Sstevel@tonic-gate */
12400Sstevel@tonic-gate static int
pcata_wait1(uint32_t port,ushort_t onbits,ushort_t offbits,int interval,ata_soft_t * softp)12410Sstevel@tonic-gate pcata_wait1(uint32_t port, ushort_t onbits, ushort_t offbits, int interval,
12420Sstevel@tonic-gate ata_soft_t *softp)
12430Sstevel@tonic-gate {
12440Sstevel@tonic-gate register int i;
12450Sstevel@tonic-gate register ushort_t maskval;
12460Sstevel@tonic-gate
12470Sstevel@tonic-gate for (i = interval; i && (CARD_PRESENT_VALID(softp)); i--) {
12480Sstevel@tonic-gate maskval = csx_Get8(softp->handle, port);
12490Sstevel@tonic-gate if (((maskval & onbits) == onbits) &&
1250*7656SSherry.Moore@Sun.COM ((maskval & offbits) == 0))
12510Sstevel@tonic-gate return (0);
12520Sstevel@tonic-gate drv_usecwait(10);
12530Sstevel@tonic-gate }
12540Sstevel@tonic-gate return (1);
12550Sstevel@tonic-gate }
12560Sstevel@tonic-gate
12570Sstevel@tonic-gate /*
12580Sstevel@tonic-gate * Wait until the command interrupt has been serviced before starting
12590Sstevel@tonic-gate * another command.
12600Sstevel@tonic-gate *
12610Sstevel@tonic-gate */
12620Sstevel@tonic-gate static void
pcata_wait_complete(ata_soft_t * softp)12630Sstevel@tonic-gate pcata_wait_complete(ata_soft_t *softp)
12640Sstevel@tonic-gate {
12650Sstevel@tonic-gate int i;
12660Sstevel@tonic-gate
12670Sstevel@tonic-gate for (i = 0; i < PCATA_WAIT_CNT &&
12680Sstevel@tonic-gate ((softp->intr_pending > 0) || (softp->softint_pending > 0)); i++) {
12690Sstevel@tonic-gate drv_usecwait(10);
12700Sstevel@tonic-gate }
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate
12730Sstevel@tonic-gate static int
pcata_send_data(ata_unit_t * unitp,int count)12740Sstevel@tonic-gate pcata_send_data(ata_unit_t *unitp, int count)
12750Sstevel@tonic-gate {
12760Sstevel@tonic-gate ata_soft_t *softp = unitp->a_blkp;
12770Sstevel@tonic-gate struct ata_cmpkt *pktp = unitp->a_blkp->ab_active;
12780Sstevel@tonic-gate
12790Sstevel@tonic-gate #ifdef ATA_DEBUG
12800Sstevel@tonic-gate if (pcata_debug & DENT) {
12810Sstevel@tonic-gate cmn_err(CE_CONT, "_send_data (%p, %x)\n",
1282*7656SSherry.Moore@Sun.COM (void *)unitp, count);
12830Sstevel@tonic-gate }
12840Sstevel@tonic-gate #endif
12850Sstevel@tonic-gate if (pcata_wait(AT_ALTSTATUS, ATS_DRQ, 0, softp)) {
12860Sstevel@tonic-gate cmn_err(CE_CONT, "_send_data - NOT READY\n");
12870Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
12880Sstevel@tonic-gate softp->write_in_progress = 0;
12890Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
12900Sstevel@tonic-gate return (DDI_FAILURE);
12910Sstevel@tonic-gate }
12920Sstevel@tonic-gate
12930Sstevel@tonic-gate /*
12940Sstevel@tonic-gate * copy count bytes from pktp->v_addr to the data port
12950Sstevel@tonic-gate */
12960Sstevel@tonic-gate #ifdef ATA_DEBUG
12970Sstevel@tonic-gate if (pcata_debug & DIO) {
12980Sstevel@tonic-gate cmn_err(CE_CONT, "_send_data: port=%x addr=0x%p count=0x%x\n",
1299*7656SSherry.Moore@Sun.COM unitp->a_blkp->ab_data,
1300*7656SSherry.Moore@Sun.COM (void *)pktp->ac_v_addr,
1301*7656SSherry.Moore@Sun.COM count);
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate #endif
13040Sstevel@tonic-gate
13050Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp)) {
13060Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
13070Sstevel@tonic-gate softp->write_in_progress = 0;
13080Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
13090Sstevel@tonic-gate return (DDI_FAILURE);
13100Sstevel@tonic-gate }
13110Sstevel@tonic-gate
13120Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
13130Sstevel@tonic-gate csx_RepPut16(softp->handle, (ushort_t *)pktp->ac_v_addr, AT_DATA,
1314*7656SSherry.Moore@Sun.COM (count >> 1), DDI_DEV_NO_AUTOINCR);
13150Sstevel@tonic-gate if (softp->write_in_progress > 0)
13160Sstevel@tonic-gate softp->write_in_progress--;
13170Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
13180Sstevel@tonic-gate
13190Sstevel@tonic-gate #ifdef ATA_DEBUG
13200Sstevel@tonic-gate if (pcata_debug & DIO) {
13210Sstevel@tonic-gate cmn_err(CE_CONT, "_send_data: ");
13220Sstevel@tonic-gate pcata_print_sttflag(csx_Get8(softp->handle, AT_ALTSTATUS));
13230Sstevel@tonic-gate }
13240Sstevel@tonic-gate
13250Sstevel@tonic-gate #endif
13260Sstevel@tonic-gate return (DDI_SUCCESS);
13270Sstevel@tonic-gate }
13280Sstevel@tonic-gate
13290Sstevel@tonic-gate
13300Sstevel@tonic-gate static int
pcata_get_data(ata_unit_t * unitp,int count)13310Sstevel@tonic-gate pcata_get_data(ata_unit_t *unitp, int count)
13320Sstevel@tonic-gate {
13330Sstevel@tonic-gate ata_soft_t *softp = unitp->a_blkp;
13340Sstevel@tonic-gate register struct ata_cmpkt *pktp = unitp->a_blkp->ab_active;
13350Sstevel@tonic-gate
13360Sstevel@tonic-gate if (pcata_wait(AT_ALTSTATUS, ATS_DRQ, 0, softp)) {
13370Sstevel@tonic-gate cmn_err(CE_CONT, "_get_data - NOT READY\n");
13380Sstevel@tonic-gate return (DDI_FAILURE);
13390Sstevel@tonic-gate }
13400Sstevel@tonic-gate /*
13410Sstevel@tonic-gate * copy count bytes from the data port to pktp->ac_v_addr
13420Sstevel@tonic-gate */
13430Sstevel@tonic-gate
13440Sstevel@tonic-gate #ifdef ATA_DEBUG
13450Sstevel@tonic-gate if (pcata_debug & DIO) {
13460Sstevel@tonic-gate cmn_err(CE_CONT, "_get_data port=%x addr=0x%p count=0x%x\n",
13470Sstevel@tonic-gate unitp->a_blkp->ab_data, (void *)pktp->ac_v_addr, count);
13480Sstevel@tonic-gate }
13490Sstevel@tonic-gate #endif
13500Sstevel@tonic-gate
13510Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp))
13520Sstevel@tonic-gate return (DDI_FAILURE);
13530Sstevel@tonic-gate
13540Sstevel@tonic-gate csx_RepGet8(softp->handle, (uchar_t *)pktp->ac_v_addr,
1355*7656SSherry.Moore@Sun.COM AT_DATA, count, DDI_DEV_NO_AUTOINCR);
13560Sstevel@tonic-gate
13570Sstevel@tonic-gate #ifdef ATA_DEBUG
13580Sstevel@tonic-gate if (pcata_debug & DIO)
13590Sstevel@tonic-gate cmn_err(CE_CONT, "_get_data complete\n");
13600Sstevel@tonic-gate #endif
13610Sstevel@tonic-gate return (DDI_SUCCESS);
13620Sstevel@tonic-gate }
13630Sstevel@tonic-gate
13640Sstevel@tonic-gate
13650Sstevel@tonic-gate int
pcata_getedt(ata_soft_t * softp,int dmax)13660Sstevel@tonic-gate pcata_getedt(ata_soft_t *softp, int dmax)
13670Sstevel@tonic-gate {
13680Sstevel@tonic-gate ushort_t *secbuf;
13690Sstevel@tonic-gate struct atarpbuf *rpbp;
13700Sstevel@tonic-gate int drive, dcount;
13710Sstevel@tonic-gate char buf[41];
13720Sstevel@tonic-gate int i;
13730Sstevel@tonic-gate
13740Sstevel@tonic-gate #ifdef ATA_DEBUG
13750Sstevel@tonic-gate if (pcata_debug & DENT) {
13760Sstevel@tonic-gate cmn_err(CE_CONT, "_getedt (%p)\n", (void *)softp);
13770Sstevel@tonic-gate }
13780Sstevel@tonic-gate #endif
13790Sstevel@tonic-gate /* toggle reset bit to trigger a software reset */
13800Sstevel@tonic-gate if (!(CARD_PRESENT_VALID(softp)))
13810Sstevel@tonic-gate return (DDI_FAILURE);
13820Sstevel@tonic-gate csx_Put8(softp->handle, AT_DEVCTL, AT_DEVCTL_D3|AT_SRST);
13830Sstevel@tonic-gate
13840Sstevel@tonic-gate drv_usecwait(1000);
13850Sstevel@tonic-gate if (!(CARD_PRESENT_VALID(softp)))
13860Sstevel@tonic-gate return (DDI_FAILURE);
13870Sstevel@tonic-gate
13880Sstevel@tonic-gate /*
13890Sstevel@tonic-gate * The interrupt disable command does not work reliably with
13900Sstevel@tonic-gate * all PC ATA cards. It is better to leave interupts enabled
13910Sstevel@tonic-gate * and process them as they occur.
13920Sstevel@tonic-gate */
13930Sstevel@tonic-gate
13940Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_DEVCTL, ENABLE_INTERRUPT);
13950Sstevel@tonic-gate
13960Sstevel@tonic-gate secbuf = (ushort_t *)kmem_zalloc(NBPSCTR, KM_NOSLEEP);
13970Sstevel@tonic-gate if (!secbuf) {
13980Sstevel@tonic-gate return (DDI_FAILURE);
13990Sstevel@tonic-gate }
14000Sstevel@tonic-gate
14010Sstevel@tonic-gate for (dcount = drive = 0; drive < dmax; drive++) {
14020Sstevel@tonic-gate if (!(rpbp = (struct atarpbuf *)kmem_zalloc(
1403*7656SSherry.Moore@Sun.COM (sizeof (struct atarpbuf) +
14040Sstevel@tonic-gate sizeof (struct scsi_inquiry)), KM_NOSLEEP))) {
14050Sstevel@tonic-gate kmem_free(secbuf, NBPSCTR);
14060Sstevel@tonic-gate return (DDI_FAILURE);
14070Sstevel@tonic-gate }
14080Sstevel@tonic-gate
14090Sstevel@tonic-gate /*
14100Sstevel@tonic-gate * load up with the drive number
14110Sstevel@tonic-gate */
14120Sstevel@tonic-gate if (drive == 0) {
14130Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_DRVHD, ATDH_DRIVE0);
14140Sstevel@tonic-gate } else {
14150Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_DRVHD, ATDH_DRIVE1);
14160Sstevel@tonic-gate }
14170Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_FEATURE, 0);
14180Sstevel@tonic-gate
14190Sstevel@tonic-gate softp->ab_dev_type[drive] = pcata_drive_type(softp, secbuf);
14200Sstevel@tonic-gate
14210Sstevel@tonic-gate if (softp->ab_dev_type[drive] == ATA_DEV_NONE) {
14220Sstevel@tonic-gate kmem_free(rpbp, (sizeof (struct atarpbuf) +
1423*7656SSherry.Moore@Sun.COM sizeof (struct scsi_inquiry)));
14240Sstevel@tonic-gate continue;
14250Sstevel@tonic-gate }
14260Sstevel@tonic-gate dcount++;
14270Sstevel@tonic-gate bcopy((caddr_t)secbuf, (caddr_t)rpbp, sizeof (struct atarpbuf));
14280Sstevel@tonic-gate
14290Sstevel@tonic-gate mutex_enter(&softp->ata_mutex);
14300Sstevel@tonic-gate if (!(softp->card_state & PCATA_CARD_INSERTED)) {
14310Sstevel@tonic-gate kmem_free(rpbp, (sizeof (struct atarpbuf) +
1432*7656SSherry.Moore@Sun.COM sizeof (struct scsi_inquiry)));
14330Sstevel@tonic-gate dcount--;
14340Sstevel@tonic-gate mutex_exit(&softp->ata_mutex);
14350Sstevel@tonic-gate break;
14360Sstevel@tonic-gate }
14370Sstevel@tonic-gate
14380Sstevel@tonic-gate softp->ab_rpbp[drive] = rpbp;
14390Sstevel@tonic-gate
14400Sstevel@tonic-gate /*
14410Sstevel@tonic-gate * We need to swap the strings on both platforms.
14420Sstevel@tonic-gate */
14430Sstevel@tonic-gate #ifdef _BIG_ENDIAN
14440Sstevel@tonic-gate pcata_byte_swap((char *)rpbp, sizeof (*rpbp));
14450Sstevel@tonic-gate #else
14460Sstevel@tonic-gate pcata_byte_swap(rpbp->atarp_drvser,
1447*7656SSherry.Moore@Sun.COM sizeof (rpbp->atarp_drvser));
14480Sstevel@tonic-gate pcata_byte_swap(rpbp->atarp_fw, sizeof (rpbp->atarp_fw));
14490Sstevel@tonic-gate pcata_byte_swap(rpbp->atarp_model, sizeof (rpbp->atarp_model));
14500Sstevel@tonic-gate #endif
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate mutex_exit(&softp->ata_mutex);
14530Sstevel@tonic-gate
14540Sstevel@tonic-gate #ifdef ATA_DEBUG
14550Sstevel@tonic-gate if (pcata_debug & DINIT) {
14560Sstevel@tonic-gate (void) strncpy(buf,
1457*7656SSherry.Moore@Sun.COM rpbp->atarp_model, sizeof (rpbp->atarp_model));
14580Sstevel@tonic-gate buf[sizeof (rpbp->atarp_model)-1] = '\0';
14590Sstevel@tonic-gate
14600Sstevel@tonic-gate /* truncate model */
14610Sstevel@tonic-gate for (i = sizeof (rpbp->atarp_model) - 2; i && buf[i] == ' ';
1462*7656SSherry.Moore@Sun.COM i--) {
14630Sstevel@tonic-gate buf[i] = '\0';
14640Sstevel@tonic-gate }
14650Sstevel@tonic-gate cmn_err(CE_CONT, "_getedt model %s, targ %d, stat %x, err %x\n",
1466*7656SSherry.Moore@Sun.COM buf,
1467*7656SSherry.Moore@Sun.COM drive,
1468*7656SSherry.Moore@Sun.COM csx_Get8(softp->handle, AT_STATUS),
1469*7656SSherry.Moore@Sun.COM csx_Get8(softp->handle, AT_ERROR));
14700Sstevel@tonic-gate cmn_err(CE_CONT, " cfg 0x%x, cyl %d, hd %d, sec/trk %d\n",
1471*7656SSherry.Moore@Sun.COM rpbp->atarp_config,
1472*7656SSherry.Moore@Sun.COM rpbp->atarp_fixcyls,
1473*7656SSherry.Moore@Sun.COM rpbp->atarp_heads,
1474*7656SSherry.Moore@Sun.COM rpbp->atarp_sectors);
14750Sstevel@tonic-gate cmn_err(CE_CONT, " mult1 0x%x, mult2 0x%x, dwcap 0x%x,"
1476*7656SSherry.Moore@Sun.COM " cap 0x%x\n",
1477*7656SSherry.Moore@Sun.COM rpbp->atarp_mult1,
1478*7656SSherry.Moore@Sun.COM rpbp->atarp_mult2,
1479*7656SSherry.Moore@Sun.COM rpbp->atarp_dwcap,
1480*7656SSherry.Moore@Sun.COM rpbp->atarp_cap);
14810Sstevel@tonic-gate cmn_err(CE_CONT, " piomode 0x%x, dmamode 0x%x,"
1482*7656SSherry.Moore@Sun.COM " advpiomode 0x%x\n",
1483*7656SSherry.Moore@Sun.COM rpbp->atarp_piomode,
1484*7656SSherry.Moore@Sun.COM rpbp->atarp_dmamode,
1485*7656SSherry.Moore@Sun.COM rpbp->atarp_advpiomode);
14860Sstevel@tonic-gate cmn_err(CE_CONT, " minpio %d, minpioflow %d",
1487*7656SSherry.Moore@Sun.COM rpbp->atarp_minpio,
1488*7656SSherry.Moore@Sun.COM rpbp->atarp_minpioflow);
14890Sstevel@tonic-gate cmn_err(CE_CONT, " valid 0x%x, dwdma 0x%x\n",
1490*7656SSherry.Moore@Sun.COM rpbp->atarp_validinfo,
1491*7656SSherry.Moore@Sun.COM rpbp->atarp_dworddma);
14920Sstevel@tonic-gate }
14930Sstevel@tonic-gate #endif
14940Sstevel@tonic-gate
14950Sstevel@tonic-gate if (!(CARD_PRESENT_VALID(softp)))
14960Sstevel@tonic-gate return (DDI_FAILURE);
14970Sstevel@tonic-gate (void) csx_Get8(softp->handle, AT_STATUS);
14980Sstevel@tonic-gate (void) csx_Get8(softp->handle, AT_ERROR);
14990Sstevel@tonic-gate }
15000Sstevel@tonic-gate
15010Sstevel@tonic-gate kmem_free(secbuf, NBPSCTR);
15020Sstevel@tonic-gate if (dcount == 0)
15030Sstevel@tonic-gate return (DDI_FAILURE);
15040Sstevel@tonic-gate
15050Sstevel@tonic-gate for (dcount = drive = 0; drive < dmax; drive++) {
15060Sstevel@tonic-gate
15070Sstevel@tonic-gate if ((rpbp = softp->ab_rpbp[drive]) == NULL) {
15080Sstevel@tonic-gate continue; /* no drive here */
15090Sstevel@tonic-gate }
15100Sstevel@tonic-gate
15110Sstevel@tonic-gate if (softp->ab_dev_type[drive] != ATA_DEV_DISK) {
15120Sstevel@tonic-gate cmn_err(CE_CONT, "Unknown IDE attachment at 0x%x.\n",
1513*7656SSherry.Moore@Sun.COM softp->ab_cmd - AT_CMD);
15140Sstevel@tonic-gate continue;
15150Sstevel@tonic-gate }
15160Sstevel@tonic-gate
15170Sstevel@tonic-gate /*
15180Sstevel@tonic-gate * feed some of the info back in a set_params call.
15190Sstevel@tonic-gate */
15200Sstevel@tonic-gate mutex_enter(&softp->ata_mutex);
15210Sstevel@tonic-gate if (pcata_setpar(drive, rpbp->atarp_heads,
1522*7656SSherry.Moore@Sun.COM rpbp->atarp_sectors, softp)
1523*7656SSherry.Moore@Sun.COM == DDI_FAILURE) {
15240Sstevel@tonic-gate /*
15250Sstevel@tonic-gate * there should have been a drive here but it
15260Sstevel@tonic-gate * didn't respond properly. It stayed BUSY.
15270Sstevel@tonic-gate */
15280Sstevel@tonic-gate if (softp->ab_rpbp[drive]) {
15290Sstevel@tonic-gate kmem_free(rpbp,
1530*7656SSherry.Moore@Sun.COM (sizeof (struct atarpbuf) +
1531*7656SSherry.Moore@Sun.COM sizeof (struct scsi_inquiry)));
15320Sstevel@tonic-gate }
15330Sstevel@tonic-gate softp->ab_rpbp[drive] = NULL;
15340Sstevel@tonic-gate softp->ab_dev_type[drive] = ATA_DEV_NONE;
15350Sstevel@tonic-gate mutex_exit(&softp->ata_mutex);
15360Sstevel@tonic-gate continue;
15370Sstevel@tonic-gate }
15380Sstevel@tonic-gate mutex_exit(&softp->ata_mutex);
15390Sstevel@tonic-gate dcount++;
15400Sstevel@tonic-gate }
15410Sstevel@tonic-gate
15420Sstevel@tonic-gate #ifdef ATA_DEBUG
15430Sstevel@tonic-gate if (pcata_debug)
15440Sstevel@tonic-gate cmn_err(CE_CONT, "**** probed %d device%s 0x%x\n",
1545*7656SSherry.Moore@Sun.COM dcount, dcount == 1 ? "." : "s.",
1546*7656SSherry.Moore@Sun.COM softp->ab_cmd - AT_CMD);
15470Sstevel@tonic-gate #endif
15480Sstevel@tonic-gate
15490Sstevel@tonic-gate return (dcount ? DDI_SUCCESS : DDI_FAILURE);
15500Sstevel@tonic-gate }
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate /*
15530Sstevel@tonic-gate * pcata_drive_type()
15540Sstevel@tonic-gate */
15550Sstevel@tonic-gate static uchar_t
pcata_drive_type(ata_soft_t * softp,ushort_t * buf)15560Sstevel@tonic-gate pcata_drive_type(ata_soft_t *softp, ushort_t *buf)
15570Sstevel@tonic-gate {
15580Sstevel@tonic-gate struct atarpbuf *rpbp = (struct atarpbuf *)buf;
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate if (pcata_wait1(AT_ALTSTATUS,
15610Sstevel@tonic-gate (ATS_DRDY | ATS_DSC), (ATS_BSY | ATS_ERR), 100000, softp))
15620Sstevel@tonic-gate return (ATA_DEV_NONE);
15630Sstevel@tonic-gate
15640Sstevel@tonic-gate pcata_wait_complete(softp);
15650Sstevel@tonic-gate
15660Sstevel@tonic-gate /*
15670Sstevel@tonic-gate * note: pcata_drive_type is only called by pcata_getedt()
15680Sstevel@tonic-gate * the drive (master/slave) is selected there
15690Sstevel@tonic-gate */
15700Sstevel@tonic-gate /* command also known as IDENTIFY DEVICE */
15710Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
15720Sstevel@tonic-gate softp->intr_pending++;
15730Sstevel@tonic-gate csx_Put8(softp->handle, AT_CMD, ATC_READPARMS);
15740Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
15750Sstevel@tonic-gate
15760Sstevel@tonic-gate if (pcata_wait1(AT_ALTSTATUS, ATS_DRQ, ATS_BSY, 1000000, softp)) {
15770Sstevel@tonic-gate
15780Sstevel@tonic-gate #ifdef ATA_DEBUG
15790Sstevel@tonic-gate if (pcata_debug) {
15800Sstevel@tonic-gate cmn_err(CE_NOTE, "failed drive did not settle:");
15810Sstevel@tonic-gate pcata_print_sttflag(csx_Get8(softp->handle, AT_STATUS));
15820Sstevel@tonic-gate }
15830Sstevel@tonic-gate #endif
15840Sstevel@tonic-gate return (ATA_DEV_NONE);
15850Sstevel@tonic-gate }
15860Sstevel@tonic-gate
15870Sstevel@tonic-gate csx_RepGet16(softp->handle, (ushort_t *)buf, AT_DATA, NBPSCTR >> 1,
1588*7656SSherry.Moore@Sun.COM DDI_DEV_NO_AUTOINCR);
15890Sstevel@tonic-gate
15900Sstevel@tonic-gate #ifdef ATA_DEBUG
15910Sstevel@tonic-gate if (pcata_debug) {
15920Sstevel@tonic-gate if ((csx_Get8(softp->handle, AT_STATUS) & ATS_ERR) == 0) {
15930Sstevel@tonic-gate pcata_byte_swap(rpbp->atarp_model,
1594*7656SSherry.Moore@Sun.COM sizeof (rpbp->atarp_model));
15950Sstevel@tonic-gate rpbp->atarp_model[sizeof (rpbp->atarp_model)-1] = '\0';
15960Sstevel@tonic-gate cmn_err(CE_CONT, "succeeded: %s\n",
1597*7656SSherry.Moore@Sun.COM rpbp->atarp_model);
15980Sstevel@tonic-gate pcata_byte_swap(rpbp->atarp_model,
1599*7656SSherry.Moore@Sun.COM sizeof (rpbp->atarp_model));
16000Sstevel@tonic-gate } else {
16010Sstevel@tonic-gate cmn_err(CE_CONT, "failed drive drive read error.\n");
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate }
16040Sstevel@tonic-gate #endif
16050Sstevel@tonic-gate
16060Sstevel@tonic-gate /*
16070Sstevel@tonic-gate * wait for the drive to recognize I've read all the data. some
16080Sstevel@tonic-gate * drives have been observed to take as much as 3msec to finish
16090Sstevel@tonic-gate * sending the data; allow 5 msec just in case.
16100Sstevel@tonic-gate */
16110Sstevel@tonic-gate if (pcata_wait1(AT_ALTSTATUS, ATS_DRDY, ATS_BSY | ATS_DRQ, 500, softp))
16120Sstevel@tonic-gate return (ATA_DEV_NONE);
16130Sstevel@tonic-gate
16140Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp))
16150Sstevel@tonic-gate return (ATA_DEV_NONE);
16160Sstevel@tonic-gate
16170Sstevel@tonic-gate if (csx_Get8(softp->handle, AT_ALTSTATUS) & ATS_ERR)
16180Sstevel@tonic-gate return (ATA_DEV_NONE);
16190Sstevel@tonic-gate
16200Sstevel@tonic-gate return (ATA_DEV_DISK);
16210Sstevel@tonic-gate }
16220Sstevel@tonic-gate
16230Sstevel@tonic-gate
16240Sstevel@tonic-gate /*
16250Sstevel@tonic-gate * Drive set params command.
16260Sstevel@tonic-gate */
16270Sstevel@tonic-gate static int
pcata_setpar(int drive,int heads,int sectors,ata_soft_t * softp)16280Sstevel@tonic-gate pcata_setpar(int drive, int heads, int sectors, ata_soft_t *softp)
16290Sstevel@tonic-gate {
16300Sstevel@tonic-gate
16310Sstevel@tonic-gate #ifdef ATA_DEBUG
16320Sstevel@tonic-gate if (pcata_debug & DINIT)
16330Sstevel@tonic-gate cmn_err(CE_CONT, "_setpar status=0x%x drive=%d heads=%d\n",
1634*7656SSherry.Moore@Sun.COM csx_Get8(softp->handle, AT_STATUS), drive, heads);
16350Sstevel@tonic-gate #endif
16360Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp))
16370Sstevel@tonic-gate return (DDI_FAILURE);
16380Sstevel@tonic-gate
16390Sstevel@tonic-gate if (pcata_wait(AT_ALTSTATUS, ATS_DRDY, ATS_BSY, softp))
16400Sstevel@tonic-gate return (DDI_FAILURE);
16410Sstevel@tonic-gate
16420Sstevel@tonic-gate pcata_wait_complete(softp);
16430Sstevel@tonic-gate
16440Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_DRVHD, (heads - 1) |
1645*7656SSherry.Moore@Sun.COM (drive == 0 ? ATDH_DRIVE0 : ATDH_DRIVE1));
16460Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_COUNT, sectors);
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
16490Sstevel@tonic-gate softp->intr_pending++;
16500Sstevel@tonic-gate csx_Put8(softp->handle, AT_CMD, ATC_SETPARAM);
16510Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
16520Sstevel@tonic-gate
16530Sstevel@tonic-gate if (pcata_wait(AT_ALTSTATUS, 0, ATS_BSY, softp))
16540Sstevel@tonic-gate return (DDI_FAILURE);
16550Sstevel@tonic-gate return (DDI_SUCCESS);
16560Sstevel@tonic-gate }
16570Sstevel@tonic-gate
16580Sstevel@tonic-gate void
pcata_byte_swap(char * buf,int n)16590Sstevel@tonic-gate pcata_byte_swap(char *buf, int n)
16600Sstevel@tonic-gate {
16610Sstevel@tonic-gate int i;
16620Sstevel@tonic-gate char c;
16630Sstevel@tonic-gate
16640Sstevel@tonic-gate n &= ~1;
16650Sstevel@tonic-gate for (i = 0; i < n; i += 2) {
16660Sstevel@tonic-gate c = buf[i];
16670Sstevel@tonic-gate buf[i] = buf[i + 1];
16680Sstevel@tonic-gate buf[i + 1] = c;
16690Sstevel@tonic-gate }
16700Sstevel@tonic-gate }
16710Sstevel@tonic-gate
16720Sstevel@tonic-gate
16730Sstevel@tonic-gate int
pcata_set_rw_multiple(ata_soft_t * softp,int drive)16740Sstevel@tonic-gate pcata_set_rw_multiple(ata_soft_t *softp, int drive)
16750Sstevel@tonic-gate {
16760Sstevel@tonic-gate int i;
16770Sstevel@tonic-gate int laststat;
16780Sstevel@tonic-gate char size;
16790Sstevel@tonic-gate char accepted_size = -1;
16800Sstevel@tonic-gate
16810Sstevel@tonic-gate #ifdef ATA_DEBUG
16820Sstevel@tonic-gate if (pcata_debug & DENT) {
16830Sstevel@tonic-gate cmn_err(CE_CONT, "_set_rw_multiple (%p, %d)\n",
1684*7656SSherry.Moore@Sun.COM (void *)softp, drive);
16850Sstevel@tonic-gate }
16860Sstevel@tonic-gate #endif
16870Sstevel@tonic-gate
16880Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp))
16890Sstevel@tonic-gate return (DDI_FAILURE);
16900Sstevel@tonic-gate /*
16910Sstevel@tonic-gate * Assume we're going to use read/write multiple until the controller
16920Sstevel@tonic-gate * says it doesn't understand them.
16930Sstevel@tonic-gate */
16940Sstevel@tonic-gate softp->ab_rd_cmd[drive] = ATC_RDMULT;
16950Sstevel@tonic-gate softp->ab_wr_cmd[drive] = ATC_WRMULT;
16960Sstevel@tonic-gate
16970Sstevel@tonic-gate /*
16980Sstevel@tonic-gate * set drive number
16990Sstevel@tonic-gate */
17000Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_DRVHD, drive == 0 ? ATDH_DRIVE0 :
1701*7656SSherry.Moore@Sun.COM ATDH_DRIVE1);
17020Sstevel@tonic-gate
17030Sstevel@tonic-gate for (size = 32; size > 0 && accepted_size == -1 &&
1704*7656SSherry.Moore@Sun.COM CARD_PRESENT_VALID(softp); size >>= 1) {
17050Sstevel@tonic-gate
17060Sstevel@tonic-gate if (pcata_wait(AT_ALTSTATUS, ATS_DRDY, ATS_BSY, softp))
17070Sstevel@tonic-gate return (DDI_FAILURE);
17080Sstevel@tonic-gate
17090Sstevel@tonic-gate pcata_wait_complete(softp);
17100Sstevel@tonic-gate
17110Sstevel@tonic-gate /*
17120Sstevel@tonic-gate * send the command
17130Sstevel@tonic-gate */
17140Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_COUNT, size);
17150Sstevel@tonic-gate
17160Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
17170Sstevel@tonic-gate softp->intr_pending++;
17180Sstevel@tonic-gate csx_Put8(softp->handle, AT_CMD, ATC_SETMULT);
17190Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
17200Sstevel@tonic-gate
17210Sstevel@tonic-gate if (pcata_wait(AT_ALTSTATUS, 0, ATS_BSY, softp))
17220Sstevel@tonic-gate /*
17230Sstevel@tonic-gate * there should have been a drive here but it
17240Sstevel@tonic-gate * didn't respond properly. It stayed BUSY.
17250Sstevel@tonic-gate * complete failure!
17260Sstevel@tonic-gate */
17270Sstevel@tonic-gate return (DDI_FAILURE);
17280Sstevel@tonic-gate /*
17290Sstevel@tonic-gate * Wait for DRDY or error status
17300Sstevel@tonic-gate */
17310Sstevel@tonic-gate for (i = 0; i < ATA_LOOP_CNT && CARD_PRESENT_VALID(softp);
1732*7656SSherry.Moore@Sun.COM i++) {
17330Sstevel@tonic-gate if (((laststat = csx_Get8(softp->handle, AT_ALTSTATUS))
1734*7656SSherry.Moore@Sun.COM & (ATS_DRDY | ATS_ERR)) != 0)
17350Sstevel@tonic-gate break;
17360Sstevel@tonic-gate drv_usecwait(10);
17370Sstevel@tonic-gate }
17380Sstevel@tonic-gate if (i == ATA_LOOP_CNT)
17390Sstevel@tonic-gate /*
17400Sstevel@tonic-gate * Didn't get ready OR error... complete failure!
17410Sstevel@tonic-gate * there should have been a drive here but it
17420Sstevel@tonic-gate * didn't respond properly. It didn't set ERR or DRQ.
17430Sstevel@tonic-gate */
17440Sstevel@tonic-gate return (DDI_FAILURE);
17450Sstevel@tonic-gate
17460Sstevel@tonic-gate /*
17470Sstevel@tonic-gate * See if DRQ or error
17480Sstevel@tonic-gate */
17490Sstevel@tonic-gate if (laststat & ATS_ERR) {
17500Sstevel@tonic-gate /*
17510Sstevel@tonic-gate * there should have been a drive here but it
17520Sstevel@tonic-gate * didn't respond properly. There was an error.
17530Sstevel@tonic-gate * Try the next value.
17540Sstevel@tonic-gate */
17550Sstevel@tonic-gate continue;
17560Sstevel@tonic-gate }
17570Sstevel@tonic-gate /*
17580Sstevel@tonic-gate * Got ready.. use the value that worked.
17590Sstevel@tonic-gate */
17600Sstevel@tonic-gate accepted_size = size;
17610Sstevel@tonic-gate }
17620Sstevel@tonic-gate if (accepted_size == -1) {
17630Sstevel@tonic-gate /*
17640Sstevel@tonic-gate * None of the values worked...
17650Sstevel@tonic-gate * the controller responded correctly though so it probably
17660Sstevel@tonic-gate * doesn't support the read/write multiple commands.
17670Sstevel@tonic-gate */
17680Sstevel@tonic-gate
17690Sstevel@tonic-gate #ifdef ATA_DEBUG
17700Sstevel@tonic-gate if (pcata_debug & DENT) {
17710Sstevel@tonic-gate cmn_err(CE_CONT, "Using STD R/W cmds and setting"
1772*7656SSherry.Moore@Sun.COM "block factor to 1\n");
17730Sstevel@tonic-gate }
17740Sstevel@tonic-gate #endif
17750Sstevel@tonic-gate softp->ab_rd_cmd[drive] = ATC_RDSEC;
17760Sstevel@tonic-gate softp->ab_wr_cmd[drive] = ATC_WRSEC;
17770Sstevel@tonic-gate softp->ab_block_factor[drive] = 1;
17780Sstevel@tonic-gate softp->ab_max_transfer = 1;
17790Sstevel@tonic-gate return (DDI_SUCCESS);
17800Sstevel@tonic-gate }
17810Sstevel@tonic-gate if (accepted_size == 1) {
17820Sstevel@tonic-gate /*
17830Sstevel@tonic-gate * OK... Leave it at 1
17840Sstevel@tonic-gate */
17850Sstevel@tonic-gate #ifdef ATA_DEBUG
17860Sstevel@tonic-gate if (pcata_debug & DENT) {
17870Sstevel@tonic-gate cmn_err(CE_CONT, "setting block factor to 1\n");
17880Sstevel@tonic-gate }
17890Sstevel@tonic-gate #endif
17900Sstevel@tonic-gate softp->ab_block_factor[drive] = accepted_size;
17910Sstevel@tonic-gate softp->ab_max_transfer = accepted_size;
17920Sstevel@tonic-gate return (DDI_SUCCESS);
17930Sstevel@tonic-gate }
17940Sstevel@tonic-gate accepted_size >>= 1;
17950Sstevel@tonic-gate /*
17960Sstevel@tonic-gate * Allow a user specified block factor to override the system chosen
17970Sstevel@tonic-gate * value. Only allow the user to reduce the value.
17980Sstevel@tonic-gate * -1 indicates the user didn't specify anything
17990Sstevel@tonic-gate */
18000Sstevel@tonic-gate if ((softp->ab_block_factor[drive] != -1) &&
18010Sstevel@tonic-gate (softp->ab_block_factor[drive] < accepted_size))
18020Sstevel@tonic-gate accepted_size = softp->ab_block_factor[drive];
18030Sstevel@tonic-gate
18040Sstevel@tonic-gate if (pcata_wait(AT_ALTSTATUS, ATS_DRDY, ATS_BSY, softp))
18050Sstevel@tonic-gate return (DDI_FAILURE);
18060Sstevel@tonic-gate
18070Sstevel@tonic-gate pcata_wait_complete(softp);
18080Sstevel@tonic-gate
18090Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_COUNT, accepted_size);
18100Sstevel@tonic-gate
18110Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
18120Sstevel@tonic-gate softp->intr_pending++;
18130Sstevel@tonic-gate csx_Put8(softp->handle, AT_CMD, ATC_SETMULT);
18140Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
18150Sstevel@tonic-gate
18160Sstevel@tonic-gate if (pcata_wait(AT_ALTSTATUS, 0, ATS_BSY, softp))
18170Sstevel@tonic-gate /*
18180Sstevel@tonic-gate * there should have been a drive here but it
18190Sstevel@tonic-gate * didn't respond properly. It stayed BUSY.
18200Sstevel@tonic-gate */
18210Sstevel@tonic-gate return (DDI_FAILURE);
18220Sstevel@tonic-gate
18230Sstevel@tonic-gate #ifdef ATA_DEBUG
18240Sstevel@tonic-gate if (pcata_debug & DENT) {
18250Sstevel@tonic-gate cmn_err(CE_CONT, "setting block factor for drive %d to %d\n",
18260Sstevel@tonic-gate drive, accepted_size);
18270Sstevel@tonic-gate }
18280Sstevel@tonic-gate #endif
18290Sstevel@tonic-gate
18300Sstevel@tonic-gate softp->ab_block_factor[drive] = accepted_size;
18310Sstevel@tonic-gate return (DDI_SUCCESS);
18320Sstevel@tonic-gate }
18330Sstevel@tonic-gate
18340Sstevel@tonic-gate static int
pcata_dump(dev_t dev,caddr_t addr,daddr_t blkno,int nblk)18350Sstevel@tonic-gate pcata_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
18360Sstevel@tonic-gate {
18370Sstevel@tonic-gate ata_soft_t *softp;
18380Sstevel@tonic-gate buf_t *bp;
18390Sstevel@tonic-gate void *instance;
18400Sstevel@tonic-gate
18410Sstevel@tonic-gate
18420Sstevel@tonic-gate if (pcata_getinfo(NULL, DDI_INFO_DEVT2INSTANCE, (void *)dev,
18430Sstevel@tonic-gate &instance) != DDI_SUCCESS)
18440Sstevel@tonic-gate return (ENODEV);
18450Sstevel@tonic-gate
18460Sstevel@tonic-gate softp = ddi_get_soft_state(pcata_soft, (int)(uintptr_t)instance);
18470Sstevel@tonic-gate if (!softp) {
18480Sstevel@tonic-gate return (ENXIO);
18490Sstevel@tonic-gate }
18500Sstevel@tonic-gate
18510Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp))
18520Sstevel@tonic-gate return (ENODEV);
18530Sstevel@tonic-gate
18540Sstevel@tonic-gate bp = softp->crashbuf;
18550Sstevel@tonic-gate bp->b_un.b_addr = addr;
18560Sstevel@tonic-gate bp->b_edev = dev;
18570Sstevel@tonic-gate bp->b_dev = cmpdev(dev);
18580Sstevel@tonic-gate bp->b_bcount = nblk * DEV_BSIZE;
18590Sstevel@tonic-gate bp->b_flags |= B_WRITE | B_PHYS;
18600Sstevel@tonic-gate bp->b_blkno = blkno;
18610Sstevel@tonic-gate bp->b_private = 0;
18620Sstevel@tonic-gate
18630Sstevel@tonic-gate /*
18640Sstevel@tonic-gate * If pcata_strategy() encounters an exception, or card_removal
18650Sstevel@tonic-gate * is called, before this is complete, it is possible that
18660Sstevel@tonic-gate * biodone will be called but the buffer (bp) wont
18670Sstevel@tonic-gate * be released unless B_ASYNC flag is set. So
18680Sstevel@tonic-gate * don't set B_ASYNC flag unless you mean it.
18690Sstevel@tonic-gate */
18700Sstevel@tonic-gate (void) pcata_strategy(bp);
18710Sstevel@tonic-gate if (bp->b_error)
18720Sstevel@tonic-gate return (bp->b_error);
18730Sstevel@tonic-gate
18740Sstevel@tonic-gate for (;;) {
18750Sstevel@tonic-gate if (!CARD_PRESENT_VALID(softp))
18760Sstevel@tonic-gate return (ENODEV);
18770Sstevel@tonic-gate if (bp->b_flags & B_DONE) {
18780Sstevel@tonic-gate if (bp->b_flags & B_ERROR)
18790Sstevel@tonic-gate return (bp->b_error);
18800Sstevel@tonic-gate else
18810Sstevel@tonic-gate return (0);
18820Sstevel@tonic-gate }
18830Sstevel@tonic-gate drv_usecwait(1000);
18840Sstevel@tonic-gate }
18850Sstevel@tonic-gate }
18860Sstevel@tonic-gate
18870Sstevel@tonic-gate /* ddi print */
18880Sstevel@tonic-gate static int
pcata_print(dev_t dev,char * str)18890Sstevel@tonic-gate pcata_print(dev_t dev, char *str)
18900Sstevel@tonic-gate {
18910Sstevel@tonic-gate void *instance;
18920Sstevel@tonic-gate ata_soft_t *softp;
18930Sstevel@tonic-gate
18940Sstevel@tonic-gate
18950Sstevel@tonic-gate /* get instance number */
18960Sstevel@tonic-gate if (pcata_getinfo(NULL, DDI_INFO_DEVT2INSTANCE, (void *)dev,
18970Sstevel@tonic-gate &instance) != DDI_SUCCESS) {
18980Sstevel@tonic-gate cmn_err(CE_CONT, "_print: pcata_getinfo"
1899*7656SSherry.Moore@Sun.COM "return ENODEV\n");
19000Sstevel@tonic-gate return (ENODEV);
19010Sstevel@tonic-gate }
19020Sstevel@tonic-gate
19030Sstevel@tonic-gate if (!(softp = ddi_get_soft_state(pcata_soft,
19040Sstevel@tonic-gate (int)(uintptr_t)instance))) {
19050Sstevel@tonic-gate return (ENXIO);
19060Sstevel@tonic-gate }
19070Sstevel@tonic-gate
19080Sstevel@tonic-gate cmn_err(CE_NOTE, "_print: socket %d %s", softp->sn, str);
19090Sstevel@tonic-gate return (0);
19100Sstevel@tonic-gate
19110Sstevel@tonic-gate }
19120Sstevel@tonic-gate
19130Sstevel@tonic-gate static int
pcata_rdrw(dev_t dev,struct uio * uio,int flag)19140Sstevel@tonic-gate pcata_rdrw(dev_t dev, struct uio *uio, int flag)
19150Sstevel@tonic-gate {
19160Sstevel@tonic-gate return (physio(pcata_strategy, (buf_t *)0, dev, flag, pcata_min, uio));
19170Sstevel@tonic-gate }
19180Sstevel@tonic-gate
19190Sstevel@tonic-gate
19200Sstevel@tonic-gate
19210Sstevel@tonic-gate /* ARGSUSED2 */
19220Sstevel@tonic-gate static int
pcata_read(dev_t dev,struct uio * uio,cred_t * cred_p)19230Sstevel@tonic-gate pcata_read(dev_t dev, struct uio *uio, cred_t *cred_p)
19240Sstevel@tonic-gate {
19250Sstevel@tonic-gate return (pcata_rdrw(dev, uio, B_READ));
19260Sstevel@tonic-gate }
19270Sstevel@tonic-gate
19280Sstevel@tonic-gate
19290Sstevel@tonic-gate
19300Sstevel@tonic-gate /* ARGSUSED2 */
19310Sstevel@tonic-gate static int
pcata_write(dev_t dev,struct uio * uio,cred_t * cred_p)19320Sstevel@tonic-gate pcata_write(dev_t dev, struct uio *uio, cred_t *cred_p)
19330Sstevel@tonic-gate {
19340Sstevel@tonic-gate return (pcata_rdrw(dev, uio, B_WRITE));
19350Sstevel@tonic-gate }
19360Sstevel@tonic-gate
19370Sstevel@tonic-gate
19380Sstevel@tonic-gate void
pcata_min(buf_t * bp)19390Sstevel@tonic-gate pcata_min(buf_t *bp)
19400Sstevel@tonic-gate {
19410Sstevel@tonic-gate ata_soft_t *softp;
19420Sstevel@tonic-gate void *instance;
19430Sstevel@tonic-gate
19440Sstevel@tonic-gate if (pcata_getinfo(NULL, DDI_INFO_DEVT2INSTANCE, (void *)bp->b_edev,
19450Sstevel@tonic-gate &instance) != DDI_SUCCESS)
19460Sstevel@tonic-gate cmn_err(CE_CONT, "Error in pcata_min\n");
19470Sstevel@tonic-gate
19480Sstevel@tonic-gate softp = ddi_get_soft_state(pcata_soft, (int)(uintptr_t)instance);
19490Sstevel@tonic-gate
19500Sstevel@tonic-gate if ((ROUNDUP(bp->b_bcount, NBPSCTR) >> SCTRSHFT) >
1951*7656SSherry.Moore@Sun.COM softp->ab_max_transfer)
19520Sstevel@tonic-gate
19530Sstevel@tonic-gate bp->b_bcount = softp->ab_max_transfer << SCTRSHFT;
19540Sstevel@tonic-gate }
19550Sstevel@tonic-gate
19560Sstevel@tonic-gate static void
pcata_iosetup(ata_unit_t * unitp,struct ata_cmpkt * pktp)19570Sstevel@tonic-gate pcata_iosetup(ata_unit_t *unitp, struct ata_cmpkt *pktp)
19580Sstevel@tonic-gate {
19590Sstevel@tonic-gate uint32_t sec_count;
19600Sstevel@tonic-gate
19610Sstevel@tonic-gate #ifdef ATA_DEBUG
19620Sstevel@tonic-gate if (pcata_debug & DENT) {
19630Sstevel@tonic-gate cmn_err(CE_CONT, "_iosetup (%p, %p)\n",
1964*7656SSherry.Moore@Sun.COM (void *)unitp, (void *)pktp);
19650Sstevel@tonic-gate }
19660Sstevel@tonic-gate #endif
19670Sstevel@tonic-gate
19680Sstevel@tonic-gate /* check for error retry */
19690Sstevel@tonic-gate if (pktp->ac_flags & CFLAG_ERROR) {
19700Sstevel@tonic-gate pktp->ac_bytes_per_block = NBPSCTR;
19710Sstevel@tonic-gate sec_count = 1;
19720Sstevel@tonic-gate } else {
19730Sstevel@tonic-gate /*
19740Sstevel@tonic-gate * Limit requetst to ab_max_transfer sectors.
19750Sstevel@tonic-gate * The value is specified by the user in the
19760Sstevel@tonic-gate * max_transfer property. It must be in the range 1 to 256.
19770Sstevel@tonic-gate * When max_transfer is 0x100 it is bigger than 8 bits.
19780Sstevel@tonic-gate * The spec says 0 represents 256 so it should be OK.
19790Sstevel@tonic-gate */
19800Sstevel@tonic-gate sec_count = min((pktp->cp_bytexfer >> SCTRSHFT),
19810Sstevel@tonic-gate unitp->a_blkp->ab_max_transfer);
19820Sstevel@tonic-gate }
19830Sstevel@tonic-gate pktp->ac_v_addr = pktp->ac_start_v_addr;
19840Sstevel@tonic-gate pktp->cp_resid = pktp->cp_bytexfer;
19850Sstevel@tonic-gate pktp->cp_bytexfer = sec_count << SCTRSHFT;
19860Sstevel@tonic-gate
19870Sstevel@tonic-gate #ifdef ATA_DEBUG
19880Sstevel@tonic-gate if (pcata_debug & DIO) {
19890Sstevel@tonic-gate cmn_err(CE_CONT,
1990*7656SSherry.Moore@Sun.COM "_iosetup: asking for start 0x%lx count 0x%x\n",
1991*7656SSherry.Moore@Sun.COM pktp->cp_srtsec, pktp->cp_bytexfer >> SCTRSHFT);
19920Sstevel@tonic-gate }
19930Sstevel@tonic-gate #endif
19940Sstevel@tonic-gate /*
19950Sstevel@tonic-gate * setup the task file registers
19960Sstevel@tonic-gate */
19970Sstevel@tonic-gate
19980Sstevel@tonic-gate if (pktp->cp_passthru) {
19990Sstevel@tonic-gate switch (((struct dadkio_rwcmd *)(pktp->cp_passthru))->cmd) {
20000Sstevel@tonic-gate case DADKIO_RWCMD_READ:
20010Sstevel@tonic-gate pktp->ac_cmd = unitp->au_rd_cmd;
20020Sstevel@tonic-gate pktp->ac_direction = AT_IN;
20030Sstevel@tonic-gate break;
20040Sstevel@tonic-gate case DADKIO_RWCMD_WRITE:
20050Sstevel@tonic-gate pktp->ac_cmd = unitp->au_wr_cmd;
20060Sstevel@tonic-gate pktp->ac_direction = AT_OUT;
20070Sstevel@tonic-gate break;
20080Sstevel@tonic-gate }
20090Sstevel@tonic-gate } else {
20100Sstevel@tonic-gate switch (pktp->ac_cdb) {
20110Sstevel@tonic-gate case DCMD_READ:
20120Sstevel@tonic-gate case DCMD_WRITE:
20130Sstevel@tonic-gate case DCMD_RECAL:
20140Sstevel@tonic-gate case DCMD_SEEK:
20150Sstevel@tonic-gate case DCMD_RDVER:
20160Sstevel@tonic-gate switch (pktp->ac_cdb) {
20170Sstevel@tonic-gate case DCMD_READ:
20180Sstevel@tonic-gate pktp->ac_cmd = unitp->au_rd_cmd;
20190Sstevel@tonic-gate pktp->ac_direction = AT_IN;
20200Sstevel@tonic-gate break;
20210Sstevel@tonic-gate case DCMD_WRITE:
20220Sstevel@tonic-gate pktp->ac_cmd = unitp->au_wr_cmd;
20230Sstevel@tonic-gate pktp->ac_direction = AT_OUT;
20240Sstevel@tonic-gate break;
20250Sstevel@tonic-gate case DCMD_RECAL:
20260Sstevel@tonic-gate pktp->ac_cmd = ATC_RECAL;
20270Sstevel@tonic-gate pktp->ac_direction = AT_NO_DATA;
20280Sstevel@tonic-gate break;
20290Sstevel@tonic-gate case DCMD_SEEK:
20300Sstevel@tonic-gate pktp->ac_cmd = ATC_SEEK;
20310Sstevel@tonic-gate pktp->ac_direction = AT_NO_DATA;
20320Sstevel@tonic-gate break;
20330Sstevel@tonic-gate case DCMD_RDVER:
20340Sstevel@tonic-gate pktp->ac_cmd = ATC_RDVER;
20350Sstevel@tonic-gate pktp->ac_direction = AT_NO_DATA;
20360Sstevel@tonic-gate break;
20370Sstevel@tonic-gate }
20380Sstevel@tonic-gate break;
20390Sstevel@tonic-gate default:
20400Sstevel@tonic-gate cmn_err(CE_CONT, "_iosetup: "
2041*7656SSherry.Moore@Sun.COM "unrecognized cmd 0x%x\n",
2042*7656SSherry.Moore@Sun.COM pktp->ac_cdb);
20430Sstevel@tonic-gate break;
20440Sstevel@tonic-gate }
20450Sstevel@tonic-gate }
20460Sstevel@tonic-gate }
20470Sstevel@tonic-gate
20480Sstevel@tonic-gate
20490Sstevel@tonic-gate /* ARGSUSED */
20500Sstevel@tonic-gate int
pcata_spinup(ata_soft_t * softp,int slot)20510Sstevel@tonic-gate pcata_spinup(ata_soft_t *softp, int slot)
20520Sstevel@tonic-gate {
20530Sstevel@tonic-gate
20540Sstevel@tonic-gate if (!(CARD_PRESENT_VALID(softp)))
20550Sstevel@tonic-gate return (DDI_FAILURE);
20560Sstevel@tonic-gate
20570Sstevel@tonic-gate if (pcata_wait(AT_ALTSTATUS, ATS_DRDY, ATS_BSY, softp))
20580Sstevel@tonic-gate return (DDI_FAILURE);
20590Sstevel@tonic-gate
20600Sstevel@tonic-gate pcata_wait_complete(softp);
20610Sstevel@tonic-gate
20620Sstevel@tonic-gate /* spin up the drive */
20630Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_DRVHD, ATDH_DRIVE0);
20640Sstevel@tonic-gate
20650Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
20660Sstevel@tonic-gate softp->intr_pending++;
20670Sstevel@tonic-gate csx_Put8(softp->handle, AT_CMD, ATC_IDLE_IMMED);
20680Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
20690Sstevel@tonic-gate
20700Sstevel@tonic-gate if (pcata_wait(AT_ALTSTATUS,
20710Sstevel@tonic-gate (ATS_DRDY | ATS_DSC), (ATS_BSY | ATS_ERR), softp)) {
20720Sstevel@tonic-gate #ifdef ATA_DEBUG
20730Sstevel@tonic-gate cmn_err(CE_NOTE, "TIMEOUT SPINNING UP: ");
20740Sstevel@tonic-gate pcata_print_sttflag(csx_Get8(softp->handle, AT_ALTSTATUS));
20750Sstevel@tonic-gate #endif
20760Sstevel@tonic-gate return (DDI_FAILURE);
20770Sstevel@tonic-gate }
20780Sstevel@tonic-gate
20790Sstevel@tonic-gate pcata_wait_complete(softp);
20800Sstevel@tonic-gate
20810Sstevel@tonic-gate /* set the R/W multiple value decided at first init time */
20820Sstevel@tonic-gate
20830Sstevel@tonic-gate PCIDE_OUTB(softp->handle, AT_COUNT, softp->ab_block_factor[0]);
20840Sstevel@tonic-gate
20850Sstevel@tonic-gate mutex_enter(&softp->hi_mutex);
20860Sstevel@tonic-gate softp->intr_pending++;
20870Sstevel@tonic-gate csx_Put8(softp->handle, AT_CMD, ATC_SETMULT);
20880Sstevel@tonic-gate mutex_exit(&softp->hi_mutex);
20890Sstevel@tonic-gate
20900Sstevel@tonic-gate if (pcata_wait(AT_STATUS, 0, ATS_BSY, softp)) {
20910Sstevel@tonic-gate /*
20920Sstevel@tonic-gate * there should have been a drive here but it
20930Sstevel@tonic-gate * didn't respond properly. It stayed BUSY.
20940Sstevel@tonic-gate */
20950Sstevel@tonic-gate #ifdef ATA_DEBUG
20960Sstevel@tonic-gate cmn_err(CE_NOTE, "Error Spinning up ATA drive (after CPR)\n");
20970Sstevel@tonic-gate #endif
20980Sstevel@tonic-gate return (DDI_FAILURE);
20990Sstevel@tonic-gate }
21000Sstevel@tonic-gate
21010Sstevel@tonic-gate return (DDI_SUCCESS);
21020Sstevel@tonic-gate }
21030Sstevel@tonic-gate
21040Sstevel@tonic-gate #ifdef ATA_DEBUG
21050Sstevel@tonic-gate static char *
21060Sstevel@tonic-gate ata_sttvals[] = { "err", "idx", "corr", "drq", "dsc", "dwf", "drdy", "bsy" };
21070Sstevel@tonic-gate
21080Sstevel@tonic-gate
21090Sstevel@tonic-gate static void
pcata_print_sttflag(int svalue)21100Sstevel@tonic-gate pcata_print_sttflag(int svalue)
21110Sstevel@tonic-gate {
21120Sstevel@tonic-gate int i;
21130Sstevel@tonic-gate char buf[80];
21140Sstevel@tonic-gate
21150Sstevel@tonic-gate (void) sprintf(buf, "_sttflag = 0x%x [ ", svalue);
21160Sstevel@tonic-gate
21170Sstevel@tonic-gate for (i = 7; i >= 0; i--, svalue <<= 1) {
21180Sstevel@tonic-gate if (svalue & 0x80) {
21190Sstevel@tonic-gate (void) strcat(buf, ata_sttvals[i]);
21200Sstevel@tonic-gate (void) strcat(buf, " ");
21210Sstevel@tonic-gate }
21220Sstevel@tonic-gate }
21230Sstevel@tonic-gate cmn_err(CE_CONT, "%s ]\n", buf);
21240Sstevel@tonic-gate }
21250Sstevel@tonic-gate #endif
2126