struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad;
struct dkbad *bt = &DKBAD(wd->sc_dk.dk_cpulabel);
struct	wd_ioctl *wi_get __P((void));void	wdioctlstrategy __P((struct buf *));void  wdgetdefaultlabel __P((struct wd_softc *, struct disklabel *));static void  wdgetdisklabel __P((dev_t dev, struct wd_softc *, 				 struct disklabel *,				 struct cpu_disklabel *, int));void  wdstrategy	__P((struct buf *));void  wdstart	__P((void *));void  __wdstart	__P((struct wd_softc*, struct buf *));void  wdrestart __P((void*));int   wd_get_params __P((struct wd_softc *, u_int8_t, struct ataparams *));void  wd_flushcache __P((struct wd_softc *, int));void  wd_shutdown __P((void*));struct dkdriver wddkdriver = { wdstrategy };/* XXX: these should go elsewhere */cdev_decl(wd);bdev_decl(wd);#ifdef DKBADstatic void bad144intern __P((struct wd_softc *));#endifint	wdlock	__P((struct wd_softc *));void	wdunlock	__P((struct wd_softc *));intwdprobe(parent, match_, aux)	struct device *parent;#ifndef __OpenBSD__	struct cfdata *match;#else	void *match_;#endif	void *aux;{	struct ata_atapi_attach *aa_link = aux;	struct cfdata *match = match_;	if (aa_link == NULL)		return 0;	if (aa_link->aa_type != T_ATA)		return 0;#ifndef __OpenBSD__	if (match->cf_loc[ATACF_CHANNEL] != ATACF_CHANNEL_DEFAULT &&	    match->cf_loc[ATACF_CHANNEL] != aa_link->aa_channel)		return 0;	if (match->cf_loc[ATACF_DRIVE] != ATACF_DRIVE_DEFAULT &&	    match->cf_loc[ATACF_DRIVE] != aa_link->aa_drv_data->drive)		return 0;#else	if (match->cf_loc[0] != -1 &&	    match->cf_loc[0] != aa_link->aa_channel)		return 0;	if (match->cf_loc[1] != -1 &&	    match->cf_loc[1] != aa_link->aa_drv_data->drive)		return 0;#endif	return 1;}voidwdattach(parent, self, aux)	struct device *parent, *self;	void *aux;{	struct wd_softc *wd = (void *)self;	struct ata_atapi_attach *aa_link= aux;	int i, blank;	char buf[41], c, *p, *q;	WDCDEBUG_PRINT(("wdattach\n"), DEBUG_FUNCS | DEBUG_PROBE);	wd->openings = aa_link->aa_openings;	wd->drvp = aa_link->aa_drv_data;;	wd->wdc_softc = parent;	/* give back our softc to our caller */	wd->drvp->drv_softc = &wd->sc_dev;	/* read our drive info */	if (wd_get_params(wd, AT_POLL, &wd->sc_params) != 0) {		printf("%s: IDENTIFY failed\n", wd->sc_dev.dv_xname);		return;	}	for (blank = 0, p = wd->sc_params.atap_model, q = buf, i = 0;	    i < sizeof(wd->sc_params.atap_model); i++) {		c = *p++;		if (c == '\0')			break;		if (c != ' ') {			if (blank) {				*q++ = ' ';				blank = 0;			}			*q++ = c;		} else			blank = 1;		}	*q++ = '\0';	printf(": <%s>\n", buf);	if ((wd->sc_params.atap_multi & 0xff) > 1) {		wd->sc_multi = wd->sc_params.atap_multi & 0xff;	} else {		wd->sc_multi = 1;	}	printf("%s: drive supports %d-sector pio transfers,",	    wd->sc_dev.dv_xname, wd->sc_multi);	/* Prior to ATA-4, LBA was optional. */	if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0)		wd->sc_flags |= WDF_LBA;#if 0	/* ATA-4 requires LBA. */	if (wd->sc_params.atap_ataversion != 0xffff &&	    wd->sc_params.atap_ataversion >= WDC_VER_ATA4)		wd->sc_flags |= WDF_LBA;#endif	if ((wd->sc_flags & WDF_LBA) != 0) {		printf(" lba addressing\n");		wd->sc_capacity =		    (wd->sc_params.atap_capacity[1] << 16) |		    wd->sc_params.atap_capacity[0];		printf("%s: %dMB, %d cyl, %d head, %d sec, "		    "%d bytes/sect x %d sectors\n",		    self->dv_xname,		    wd->sc_capacity / (1048576 / DEV_BSIZE),		    wd->sc_params.atap_cylinders,		    wd->sc_params.atap_heads,		    wd->sc_params.atap_sectors,		    DEV_BSIZE,		    wd->sc_capacity);	} else {		printf(" chs addressing\n");		wd->sc_capacity =		    wd->sc_params.atap_cylinders *		    wd->sc_params.atap_heads *		    wd->sc_params.atap_sectors;		printf("%s: %dMB, %d cyl, %d head, %d sec, %d bytes/sect x %d "		    "sectors\n", self->dv_xname,		    wd->sc_capacity / (1048576 / DEV_BSIZE),		    wd->sc_params.atap_cylinders,		    wd->sc_params.atap_heads,		    wd->sc_params.atap_sectors,		    DEV_BSIZE,		    wd->sc_capacity);	}	WDCDEBUG_PRINT(("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n",	    self->dv_xname, wd->sc_params.atap_dmatiming_mimi,	    wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE);	/*	 * Initialize and attach the disk structure.	 */	wd->sc_dk.dk_driver = &wddkdriver;	wd->sc_dk.dk_name = wd->sc_dev.dv_xname;	disk_attach(&wd->sc_dk);	wd->sc_wdc_bio.lp = wd->sc_dk.dk_label;	if (shutdownhook_establish(wd_shutdown, wd) == NULL)		printf("%s: WARNING: unable to establish shutdown hook\n",		    wd->sc_dev.dv_xname); #if NRND > 0	rnd_attach_source(&wd->rnd_source, wd->sc_dev.dv_xname,			  RND_TYPE_DISK, 0);#endif}/* * Read/write routine for a buffer.  Validates the arguments and schedules the * transfer.  Does not wait for the transfer to complete. */voidwdstrategy(bp)	struct buf *bp;{	struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(bp->b_dev)];	int s;	WDCDEBUG_PRINT(("wdstrategy (%s)\n", wd->sc_dev.dv_xname),	    DEBUG_XFERS);		/* Valid request?  */	if (bp->b_blkno < 0 ||	    (bp->b_bcount % wd->sc_dk.dk_label->d_secsize) != 0 ||	    (bp->b_bcount / wd->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) {		bp->b_error = EINVAL;		goto bad;	}		/* If device invalidated (e.g. media change, door open), error. */	if ((wd->sc_flags & WDF_LOADED) == 0) {		bp->b_error = EIO;		goto bad;	}	/* If it's a null transfer, return immediately. */	if (bp->b_bcount == 0)		goto done;	/*	 * Do bounds checking, adjust transfer. if error, process.	 * If end of partition, just return.	 */	if (WDPART(bp->b_dev) != RAW_PART &&	    bounds_check_with_label(bp, wd->sc_dk.dk_label, wd->sc_dk.dk_cpulabel,	    (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)		goto done;	/* Queue transfer on drive, activate drive and controller if idle. */	s = splbio();	disksort(&wd->sc_q, bp);	wdstart(wd);	splx(s);	return;bad:	bp->b_flags |= B_ERROR;done:	/* Toss transfer; we're done early. */	bp->b_resid = bp->b_bcount;	biodone(bp);}/* * Queue a drive for I/O. */voidwdstart(arg)	void *arg;{	struct wd_softc *wd = arg;	struct buf *dp, *bp=0;	WDCDEBUG_PRINT(("wdstart %s\n", wd->sc_dev.dv_xname),	    DEBUG_XFERS);	while (wd->openings > 0) {		/* Is there a buf for us ? */		dp = &wd->sc_q;		if ((bp = dp->b_actf) == NULL)  /* yes, an assign */			 return;		dp->b_actf = bp->b_actf;			/* 		 * Make the command. First lock the device		 */		wd->openings--;		wd->retries = 0;		__wdstart(wd, bp);	}}void__wdstart(wd, bp)	struct wd_softc *wd;	struct buf *bp;{	daddr_t p_offset;	if (WDPART(bp->b_dev) != RAW_PART)		p_offset =		    wd->sc_dk.dk_label->d_partitions[WDPART(bp->b_dev)].p_offset;	else		p_offset = 0;	wd->sc_wdc_bio.blkno = bp->b_blkno + p_offset;	wd->sc_wdc_bio.blkno /= (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE);	wd->sc_wdc_bio.blkdone =0;	wd->sc_bp = bp;	/*	 * If we're retrying, retry in single-sector mode. This will give us	 * the sector number of the problem, and will eventually allow the	 * transfer to succeed.	 */	if (wd->sc_multi == 1 || wd->retries >= WDIORETRIES_SINGLE)		wd->sc_wdc_bio.flags = ATA_SINGLE;	else		wd->sc_wdc_bio.flags = 0;	if (wd->sc_flags & WDF_LBA)		wd->sc_wdc_bio.flags |= ATA_LBA;	if (bp->b_flags & B_READ)		wd->sc_wdc_bio.flags |= ATA_READ;	wd->sc_wdc_bio.bcount = bp->b_bcount;	wd->sc_wdc_bio.databuf = bp->b_data;	/* Instrumentation. */	disk_busy(&wd->sc_dk);	switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) {	case WDC_TRY_AGAIN:		timeout(wdrestart, wd, hz);		break;	case WDC_QUEUED:		break;	case WDC_COMPLETE:		wddone(wd);		break;	default:		panic("__wdstart: bad return code from wdc_ata_bio()");	}}voidwddone(v)	void *v;{	struct wd_softc *wd = v;	struct buf *bp = wd->sc_bp;	char buf[256], *errbuf = buf;	WDCDEBUG_PRINT(("wddone %s\n", wd->sc_dev.dv_xname),	    DEBUG_XFERS);	bp->b_resid = wd->sc_wdc_bio.bcount;	errbuf[0] = '\0';	switch (wd->sc_wdc_bio.error) {	case ERR_DMA:		errbuf = "DMA error";		goto retry;	case ERR_DF:		errbuf = "device fault";		goto retry;	case TIMEOUT:		errbuf = "device timeout";		goto retry;	case ERROR:		/* Don't care about media change bits */		if (wd->sc_wdc_bio.r_error != 0 &&		    (wd->sc_wdc_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0)			goto noerror;		ata_perror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf);retry:		/* Just reset and retry. Can we do more ? */		wdc_reset_channel(wd->drvp);		diskerr(bp, "wd", errbuf, LOG_PRINTF,		    wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label);		if (wd->retries++ < WDIORETRIES) {			printf(", retrying\n");			timeout(wdrestart, wd, RECOVERYTIME);			return;		}		printf("\n");		bp->b_flags |= B_ERROR;		bp->b_error = EIO;		break;	case NOERROR:noerror:	if ((wd->sc_wdc_bio.flags & ATA_CORR) || wd->retries > 0)			printf("%s: soft error (corrected)\n",			    wd->sc_dev.dv_xname);	}	disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid));#if NRND > 0	rnd_add_uint32(&wd->rnd_source, bp->b_blkno);#endif	biodone(bp);	wd->openings++;	wdstart(wd);}voidwdrestart(v)	void *v;{	struct wd_softc *wd = v;	struct buf *bp = wd->sc_bp;	int s;	WDCDEBUG_PRINT(("wdrestart %s\n", wd->sc_dev.dv_xname),	    DEBUG_XFERS);	s = splbio();	__wdstart(v, bp);	splx(s);}intwdread(dev, uio, flags)	dev_t dev;	struct uio *uio;	int flags;{	WDCDEBUG_PRINT(("wdread\n"), DEBUG_XFERS);	return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio));}intwdwrite(dev, uio, flags)	dev_t dev;	struct uio *uio;	int flags;{	WDCDEBUG_PRINT(("wdwrite\n"), DEBUG_XFERS);	return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio));}/* * Wait interruptibly for an exclusive lock. * * XXX * Several drivers do this; it should be abstracted and made MP-safe. */intwdlock(wd)	struct wd_softc *wd;{	int error;	int s;	WDCDEBUG_PRINT(("wdlock\n"), DEBUG_FUNCS);	s = splbio();	while ((wd->sc_flags & WDF_LOCKED) != 0) {		wd->sc_flags |= WDF_WANTED;		if ((error = tsleep(wd, PRIBIO | PCATCH,		    "wdlck", 0)) != 0) {			splx(s);			return error;		}	}	wd->sc_flags |= WDF_LOCKED;	splx(s);	return 0;}/* * Unlock and wake up any waiters. */voidwdunlock(wd)	struct wd_softc *wd;{	WDCDEBUG_PRINT(("wdunlock\n"), DEBUG_FUNCS);	wd->sc_flags &= ~WDF_LOCKED;	if ((wd->sc_flags & WDF_WANTED) != 0) {		wd->sc_flags &= ~WDF_WANTED;		wakeup(wd);	}}intwdopen(dev, flag, fmt, p)	dev_t dev;	int flag, fmt;	struct proc *p;{	struct wd_softc *wd;	int unit, part;	int error;	WDCDEBUG_PRINT(("wdopen\n"), DEBUG_FUNCS);	unit = WDUNIT(dev);	if (unit >= wd_cd.cd_ndevs)		return ENXIO;	wd = wd_cd.cd_devs[unit];	if (wd == NULL)		return ENXIO;	/*	 * If this is the first open of this device, add a reference	 * to the adapter.	 */#ifndef __OpenBSD__	if (wd->sc_dk.dk_openmask == 0 &&	    (error = wdc_ata_addref(wd->drvp)) != 0)		return (error);#endif	if ((error = wdlock(wd)) != 0)		goto bad4;	if (wd->sc_dk.dk_openmask != 0) {		/*		 * If any partition is open, but the disk has been invalidated,		 * disallow further opens.		 */		if ((wd->sc_flags & WDF_LOADED) == 0) {			error = EIO;			goto bad3;		}	} else {		if ((wd->sc_flags & WDF_LOADED) == 0) {			wd->sc_flags |= WDF_LOADED;			/* Load the physical device parameters. */			wd_get_params(wd, AT_WAIT, &wd->sc_params);			/* Load the partition info if not already loaded. */			wdgetdisklabel(dev, wd, wd->sc_dk.dk_label,				       wd->sc_dk.dk_cpulabel, 0);		}	}	part = WDPART(dev);	/* Check that the partition exists. */	if (part != RAW_PART &&	    (part >= wd->sc_dk.dk_label->d_npartitions ||	     wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {		error = ENXIO;		goto bad;	}		/* Insure only one open at a time. */	switch (fmt) {	case S_IFCHR:		wd->sc_dk.dk_copenmask |= (1 << part);		break;	case S_IFBLK:		wd->sc_dk.dk_bopenmask |= (1 << part);		break;	}	wd->sc_dk.dk_openmask =	    wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;	wdunlock(wd);	return 0;bad:	if (wd->sc_dk.dk_openmask == 0) {	}bad3:	wdunlock(wd);bad4:#ifndef __OpenBSD__	if (wd->sc_dk.dk_openmask == 0)		wdc_ata_delref(wd->drvp);#endif	return error;}intwdclose(dev, flag, fmt, p)	dev_t dev;	int flag, fmt;	struct proc *p;{	struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)];	int part = WDPART(dev);	int error;		WDCDEBUG_PRINT(("wdclose\n"), DEBUG_FUNCS);	if ((error = wdlock(wd)) != 0)		return error;	switch (fmt) {	case S_IFCHR:		wd->sc_dk.dk_copenmask &= ~(1 << part);		break;	case S_IFBLK:		wd->sc_dk.dk_bopenmask &= ~(1 << part);		break;	}	wd->sc_dk.dk_openmask =	    wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;	if (wd->sc_dk.dk_openmask == 0) {		wd_flushcache(wd,0);		/* XXXX Must wait for I/O to complete! */#ifndef __OpenBSD__		wdc_ata_delref(wd->drvp);#endif	}	wdunlock(wd);	return 0;}voidwdgetdefaultlabel(wd, lp)	struct wd_softc *wd;	struct disklabel *lp;{	WDCDEBUG_PRINT(("wdgetdefaultlabel\n"), DEBUG_FUNCS);	memset(lp, 0, sizeof(struct disklabel));	lp->d_secsize = DEV_BSIZE;	lp->d_ntracks = wd->sc_params.atap_heads;	lp->d_nsectors = wd->sc_params.atap_sectors;	lp->d_ncylinders = wd->sc_params.atap_cylinders;	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;#if 0	if (strcmp(wd->sc_params.atap_model, "ST506") == 0) {		lp->d_type = DTYPE_ST506;		strncpy(lp->d_typename, "ST506 disk", 16);	} else {		lp->d_type = DTYPE_ESDI;		strncpy(lp->d_typename, "ESDI/IDE",		sizeof lp->d_typename);	}#endif	strncpy(lp->d_typename, wd->sc_params.atap_model, 16);	strncpy(lp->d_packname, "fictitious", 16);	lp->d_secperunit = wd->sc_capacity;	lp->d_rpm = 3600;	lp->d_interleave = 1;	lp->d_flags = 0;	lp->d_partitions[RAW_PART].p_offset = 0;	lp->d_partitions[RAW_PART].p_size =	lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;	lp->d_npartitions = RAW_PART + 1;	lp->d_magic = DISKMAGIC;	lp->d_magic2 = DISKMAGIC;	lp->d_checksum = dkcksum(lp);}/* * Fabricate a default disk label, and try to read the correct one. */static voidwdgetdisklabel(dev, wd, lp, clp, spoofonly)	dev_t  dev;	struct wd_softc *wd;	struct disklabel *lp;	struct cpu_disklabel *clp;	int spoofonly;{	char *errstring;	WDCDEBUG_PRINT(("wdgetdisklabel\n"), DEBUG_FUNCS);	memset(clp, 0, sizeof(struct cpu_disklabel));	wdgetdefaultlabel(wd, lp);	wd->sc_badsect[0] = -1;	if (wd->drvp->state > RECAL)		wd->drvp->drive_flags |= DRIVE_RESET;	errstring = readdisklabel(WDLABELDEV(dev),	    wdstrategy, lp, clp, spoofonly);	if (errstring) {		/*		 * This probably happened because the drive's default		 * geometry doesn't match the DOS geometry.  We		 * assume the DOS geometry is now in the label and try		 * again.  XXX This is a kluge.		 */		if (wd->drvp->state > RECAL)			wd->drvp->drive_flags |= DRIVE_RESET;		errstring = readdisklabel(WDLABELDEV(dev),		    wdstrategy, lp, clp, spoofonly);	}	if (errstring) {		printf("%s: %s\n", wd->sc_dev.dv_xname, errstring);		return;	}	if (wd->drvp->state > RECAL)		wd->drvp->drive_flags |= DRIVE_RESET;#ifdef DKBAD	if ((lp->d_flags & D_BADSECT) != 0)		bad144intern(wd);#endif}intwdioctl(dev, xfer, addr, flag, p)	dev_t dev;	u_long xfer;	caddr_t addr;	int flag;	struct proc *p;{	struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)];	int error;	WDCDEBUG_PRINT(("wdioctl\n"), DEBUG_FUNCS);	if ((wd->sc_flags & WDF_LOADED) == 0)		return EIO;	switch (xfer) {#ifdef DKBAD	case DIOCSBAD:		if ((flag & FWRITE) == 0)			return EBADF;		DKBAD(wd->sc_dk.dk_cpulabel) = *(struct dkbad *)addr;		wd->sc_dk.dk_label->d_flags |= D_BADSECT;		bad144intern(wd);		return 0;#endif	case DIOCGPDINFO: {			struct cpu_disklabel osdep;			wdgetdisklabel(dev, wd, (struct disklabel *)addr,			    &osdep, 1);			return 0;		}	case DIOCGDINFO:		*(struct disklabel *)addr = *(wd->sc_dk.dk_label);		return 0;		case DIOCGPART:		((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label;		((struct partinfo *)addr)->part =		    &wd->sc_dk.dk_label->d_partitions[WDPART(dev)];		return 0;		case DIOCWDINFO:	case DIOCSDINFO:		if ((flag & FWRITE) == 0)			return EBADF;		if ((error = wdlock(wd)) != 0)			return error;		wd->sc_flags |= WDF_LABELLING;		error = setdisklabel(wd->sc_dk.dk_label,		    (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0,		    wd->sc_dk.dk_cpulabel);		if (error == 0) {			if (wd->drvp->state > RECAL)				wd->drvp->drive_flags |= DRIVE_RESET;			if (xfer == DIOCWDINFO)				error = writedisklabel(WDLABELDEV(dev),				    wdstrategy, wd->sc_dk.dk_label,				    wd->sc_dk.dk_cpulabel);		}		wd->sc_flags &= ~WDF_LABELLING;		wdunlock(wd);		return error;		case DIOCWLABEL:		if ((flag & FWRITE) == 0)			return EBADF;		if (*(int *)addr)			wd->sc_flags |= WDF_WLABEL;		else			wd->sc_flags &= ~WDF_WLABEL;		return 0;#ifndef __OpenBSD__	case DIOCGDEFLABEL:		wdgetdefaultlabel(wd, (struct disklabel *)addr);		return 0;#endif#ifdef notyet	case DIOCWFORMAT:		if ((flag & FWRITE) == 0)			return EBADF;		{		register struct format_op *fop;		struct iovec aiov;		struct uio auio;			fop = (struct format_op *)addr;		aiov.iov_base = fop->df_buf;		aiov.iov_len = fop->df_count;		auio.uio_iov = &aiov;		auio.uio_iovcnt = 1;		auio.uio_resid = fop->df_count;		auio.uio_segflg = 0;		auio.uio_offset =			fop->df_startblk * wd->sc_dk.dk_label->d_secsize;		auio.uio_procp = p;		error = physio(wdformat, NULL, dev, B_WRITE, minphys,		    &auio);		fop->df_count -= auio.uio_resid;		fop->df_reg[0] = wdc->sc_status;		fop->df_reg[1] = wdc->sc_error;		return error;		}#endif	case ATAIOCCOMMAND:		/*		 * Make sure this command is (relatively) safe first		 */		if ((((atareq_t *) addr)->flags & ATACMD_READ) == 0 &&		    (flag & FWRITE) == 0)			return (EBADF);		{		struct wd_ioctl *wi;		atareq_t *atareq = (atareq_t *) addr;		int error;		wi = wi_get();		wi->wi_softc = wd;		wi->wi_atareq = *atareq;		if (atareq->datalen && atareq->flags &		    (ATACMD_READ | ATACMD_WRITE)) {			wi->wi_iov.iov_base = atareq->databuf;			wi->wi_iov.iov_len = atareq->datalen;			wi->wi_uio.uio_iov = &wi->wi_iov;			wi->wi_uio.uio_iovcnt = 1;			wi->wi_uio.uio_resid = atareq->datalen;			wi->wi_uio.uio_offset = 0;			wi->wi_uio.uio_segflg = UIO_USERSPACE;			wi->wi_uio.uio_rw =			    (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE;			wi->wi_uio.uio_procp = p;			error = physio(wdioctlstrategy, &wi->wi_bp, dev,			    (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE,			    minphys, &wi->wi_uio);		} else {			/* No need to call physio if we don't have any			   user data */			wi->wi_bp.b_flags = 0;			wi->wi_bp.b_data = 0;			wi->wi_bp.b_bcount = 0;			wi->wi_bp.b_dev = 0;			wi->wi_bp.b_proc = p;			wdioctlstrategy(&wi->wi_bp);			error = wi->wi_bp.b_error;		}		*atareq = wi->wi_atareq;		wi_free(wi);		return(error);		}	default:		return ENOTTY;	}#ifdef DIAGNOSTIC	panic("wdioctl: impossible");#endif}#ifdef B_FORMATintwdformat(struct buf *bp){	bp->b_flags |= B_FORMAT;	return wdstrategy(bp);}#endifintwdsize(dev)	dev_t dev;{	struct wd_softc *wd;	int part, unit, omask;	int size;	WDCDEBUG_PRINT(("wdsize\n"), DEBUG_FUNCS);	unit = WDUNIT(dev);	if (unit >= wd_cd.cd_ndevs)		return (-1);	wd = wd_cd.cd_devs[unit];	if (wd == NULL)		return (-1);	part = WDPART(dev);	omask = wd->sc_dk.dk_openmask & (1 << part);	if (omask == 0 && wdopen(dev, 0, S_IFBLK, NULL) != 0)		return (-1);	if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)		size = -1;	else		size = wd->sc_dk.dk_label->d_partitions[part].p_size *		    (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE);	if (omask == 0 && wdclose(dev, 0, S_IFBLK, NULL) != 0)		return (-1);	return (size);}#ifndef __BDEVSW_DUMP_OLD_TYPE/* #define WD_DUMP_NOT_TRUSTED if you just want to watch */static int wddoingadump = 0;static int wddumprecalibrated = 0;static int wddumpmulti = 1;/* * Dump core after a system crash. */intwddump(dev, blkno, va, size)	dev_t dev;	daddr_t blkno;	caddr_t va;	size_t size;{	struct wd_softc *wd;	/* disk unit to do the I/O */	struct disklabel *lp;   /* disk's disklabel */	int unit, part;	int nblks;	/* total number of sectors left to write */	int err;	char errbuf[256];	/* Check if recursive dump; if so, punt. */	if (wddoingadump)		return EFAULT;	wddoingadump = 1;	unit = WDUNIT(dev);	if (unit >= wd_cd.cd_ndevs)		return ENXIO;	wd = wd_cd.cd_devs[unit];	if (wd == (struct wd_softc *)0)		return ENXIO;	part = WDPART(dev);	/* Make sure it was initialized. */	if (wd->drvp->state < READY)		return ENXIO;	/* Convert to disk sectors.  Request must be a multiple of size. */	lp = wd->sc_dk.dk_label;	if ((size % lp->d_secsize) != 0)		return EFAULT;	nblks = size / lp->d_secsize;	blkno = blkno / (lp->d_secsize / DEV_BSIZE);	/* Check transfer bounds against partition size. */	if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size))		return EINVAL;  	/* Offset block number to start of partition. */	blkno += lp->d_partitions[part].p_offset;	/* Recalibrate, if first dump transfer. */	if (wddumprecalibrated == 0) {		wddumpmulti = wd->sc_multi;		wddumprecalibrated = 1;		wd->drvp->state = RECAL;	}  	while (nblks > 0) {again:		wd->sc_wdc_bio.blkno = blkno;		wd->sc_wdc_bio.flags = ATA_POLL;		if (wddumpmulti == 1)			wd->sc_wdc_bio.flags |= ATA_SINGLE;		if (wd->sc_flags & WDF_LBA)			wd->sc_wdc_bio.flags |= ATA_LBA;		wd->sc_wdc_bio.bcount =			min(nblks, wddumpmulti) * lp->d_secsize;		wd->sc_wdc_bio.databuf = va;#ifndef WD_DUMP_NOT_TRUSTED		switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) {		case WDC_TRY_AGAIN:			panic("wddump: try again");			break;		case WDC_QUEUED:			panic("wddump: polled command has been queued");			break;		case WDC_COMPLETE:			break;		}		switch(wd->sc_wdc_bio.error) {		case TIMEOUT:			printf("wddump: device timed out");			err = EIO;			break;		case ERR_DF:			printf("wddump: drive fault");			err = EIO;			break;		case ERR_DMA:			printf("wddump: DMA error");			err = EIO;			break;		case ERROR:			errbuf[0] = '\0';			ata_perror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf);			printf("wddump: %s", errbuf);			err = EIO;			break;		case NOERROR: 			err = 0;			break;		default:			panic("wddump: unknown error type");		}		if (err != 0) {			if (wddumpmulti != 1) {				wddumpmulti = 1; /* retry in single-sector */				printf(", retrying\n");				goto again;			}			printf("\n");			return err;		}#else	/* WD_DUMP_NOT_TRUSTED */		/* Let's just talk about this first... */		printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n",		    unit, va, cylin, head, sector);		delay(500 * 1000);	/* half a second */#endif		/* update block count */		nblks -= min(nblks, wddumpmulti);		blkno += min(nblks, wddumpmulti);		va += min(nblks, wddumpmulti) * lp->d_secsize;	}	wddoingadump = 0;	return 0;}#else /* __BDEVSW_DUMP_NEW_TYPE */intwddump(dev, blkno, va, size)	dev_t dev;	daddr_t blkno;	caddr_t va;	size_t size;{	/* Not implemented. */	return ENXIO;}#endif /* __BDEVSW_DUMP_NEW_TYPE */#ifdef DKBAD/* * Internalize the bad sector table. */voidbad144intern(wd)	struct wd_softc *wd;{	struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad;	struct disklabel *lp = wd->sc_dk.dk_label;	int i = 0;	WDCDEBUG_PRINT(("bad144intern\n"), DEBUG_XFERS);	for (; i < NBT_BAD; i++) {		if (bt->bt_bad[i].bt_cyl == 0xffff)			break;		wd->sc_badsect[i] =		    bt->bt_bad[i].bt_cyl * lp->d_secpercyl +		    (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors +		    (bt->bt_bad[i].bt_trksec & 0xff);	}	for (; i < NBT_BAD+1; i++)		wd->sc_badsect[i] = -1;}#endifintwd_get_params(wd, flags, params)	struct wd_softc *wd;	u_int8_t flags;	struct ataparams *params;{	switch (ata_get_params(wd->drvp, flags, params)) {	case CMD_AGAIN:		return 1;	case CMD_ERR:		/*		 * We `know' there's a drive here; just assume it's old.		 * This geometry is only used to read the MBR and print a		 * (false) attach message.		 */		strncpy(params->atap_model, "ST506",		    sizeof params->atap_model);		params->atap_config = ATA_CFG_FIXED;		params->atap_cylinders = 1024;		params->atap_heads = 8;		params->atap_sectors = 17;		params->atap_multi = 1;		params->atap_capabilities1 = params->atap_capabilities2 = 0;		wd->drvp->ata_vers = -1; /* Mark it as pre-ATA */		return 0;	case CMD_OK:		return 0;	default:		panic("wd_get_params: bad return code from ata_get_params");		/* NOTREACHED */	}}voidwd_flushcache(wd, flags)	struct wd_softc *wd;	int flags;{	struct wdc_command wdc_c;	if (wd->drvp->ata_vers < 4) /* WDCC_FLUSHCACHE is here since ATA-4 */		return;	memset(&wdc_c, 0, sizeof(struct wdc_command));	wdc_c.r_command = WDCC_FLUSHCACHE;	wdc_c.r_st_bmask = WDCS_DRDY;	wdc_c.r_st_pmask = WDCS_DRDY;	wdc_c.flags = flags | AT_WAIT;	wdc_c.timeout = 30000; /* 30s timeout */	if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) {		printf("%s: flush cache command didn't complete\n",		    wd->sc_dev.dv_xname);	}	if (wdc_c.flags & AT_TIMEOU) {		printf("%s: flush cache command timeout\n",		    wd->sc_dev.dv_xname);	}	if (wdc_c.flags & AT_DF) {		printf("%s: flush cache command: drive fault\n",		    wd->sc_dev.dv_xname);	}	/*	 * Ignore error register, it shouldn't report anything else	 * than COMMAND ABORTED, which means the device doesn't support	 * flush cache	 */}voidwd_shutdown(arg)	void *arg;{	struct wd_softc *wd = arg;	wd_flushcache(wd, ATA_POLL);}/* * Allocate space for a ioctl queue structure.  Mostly taken from * scsipi_ioctl.c */struct wd_ioctl *wi_get(){	struct wd_ioctl *wi;	int s;	wi = malloc(sizeof(struct wd_ioctl), M_TEMP, M_WAITOK);	memset(wi, 0, sizeof (struct wd_ioctl));	s = splbio();	LIST_INSERT_HEAD(&wi_head, wi, wi_list);	splx(s);	return (wi);}