예제 #1
0
int 
astattach(struct ata_device *atadev)
{
    struct ast_softc *stp;
    struct ast_readposition position;
    dev_t dev;

    stp = malloc(sizeof(struct ast_softc), M_AST, M_NOWAIT | M_ZERO);
    if (!stp) {
	ata_prtdev(atadev, "out of memory\n");
	return 0;
    }

    stp->device = atadev;
    stp->lun = ata_get_lun(&ast_lun_map);
    ata_set_name(atadev, "ast", stp->lun);
    bufq_init(&stp->queue);

    if (ast_sense(stp)) {
	free(stp, M_AST);
	return 0;
    }

    if (!strcmp(atadev->param->model, "OnStream DI-30")) {
	struct ast_transferpage transfer;
	struct ast_identifypage identify;

	stp->flags |= F_ONSTREAM;
	bzero(&transfer, sizeof(struct ast_transferpage));
	ast_mode_sense(stp, ATAPI_TAPE_TRANSFER_PAGE,
		       &transfer, sizeof(transfer));
	bzero(&identify, sizeof(struct ast_identifypage));
	ast_mode_sense(stp, ATAPI_TAPE_IDENTIFY_PAGE,
		       &identify, sizeof(identify));
	strncpy(identify.ident, "FBSD", 4);
	ast_mode_select(stp, &identify, sizeof(identify));
	ast_read_position(stp, 0, &position);
    }

    devstat_add_entry(&stp->stats, "ast", stp->lun, DEV_BSIZE,
		      DEVSTAT_NO_ORDERED_TAGS,
		      DEVSTAT_TYPE_SEQUENTIAL | DEVSTAT_TYPE_IF_IDE,
		      DEVSTAT_PRIORITY_TAPE);
    dev = make_dev(&ast_cdevsw, dkmakeminor(stp->lun, 0, 0),
		   UID_ROOT, GID_OPERATOR, 0640, "ast%d", stp->lun);
    dev->si_drv1 = stp;
    dev->si_iosize_max = 256 * DEV_BSIZE;
    stp->dev1 = dev;
    dev = make_dev(&ast_cdevsw, dkmakeminor(stp->lun, 0, 1),
		   UID_ROOT, GID_OPERATOR, 0640, "nast%d", stp->lun);
    dev->si_drv1 = stp;
    dev->si_iosize_max = 256 * DEV_BSIZE;
    stp->dev2 = dev;
    stp->device->flags |= ATA_D_MEDIA_CHANGED;
    ast_describe(stp);
    atadev->driver = stp;
    return 1;
}
예제 #2
0
int 
afdattach(struct ata_device *atadev)
{
    struct afd_softc *fdp;
    dev_t dev;

    fdp = malloc(sizeof(struct afd_softc), M_AFD, M_NOWAIT | M_ZERO);
    if (!fdp) {
	ata_prtdev(atadev, "out of memory\n");
	return 0;
    }

    fdp->device = atadev;
    fdp->lun = ata_get_lun(&afd_lun_map);
    ata_set_name(atadev, "afd", fdp->lun);
    bufq_init(&fdp->queue);

    if (afd_sense(fdp)) {
	free(fdp, M_AFD);
	return 0;
    }

    devstat_add_entry(&fdp->stats, "afd", fdp->lun, DEV_BSIZE,
		      DEVSTAT_NO_ORDERED_TAGS,
		      DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
		      DEVSTAT_PRIORITY_WFD);
    dev = disk_create(fdp->lun, &fdp->disk, 0, &afd_cdevsw, &afddisk_cdevsw);
    dev->si_drv1 = fdp;
    fdp->dev = dev;

    if (!strncmp(atadev->param->model, "IOMEGA ZIP", 10) ||
	!strncmp(atadev->param->model, "IOMEGA Clik!", 12))
	fdp->dev->si_iosize_max = 64 * DEV_BSIZE;
    else
	fdp->dev->si_iosize_max = 252 * DEV_BSIZE;

    afd_describe(fdp);
    atadev->flags |= ATA_D_MEDIA_CHANGED;
    atadev->driver = fdp;
    return 1;
}
예제 #3
0
파일: wst.c 프로젝트: UnitedMarsupials/kame
int 
wstattach(struct atapi *ata, int unit, struct atapi_params *ap, int debug)
{
    struct wst *t;
    int lun;

    if (wstnlun >= NUNIT) {
        printf("wst: too many units\n");
        return(-1);
    }
    if (!atapi_request_immediate) {
        printf("wst: configuration error, ATAPI core code not present!\n");
        printf(
	    "wst: check `options ATAPI_STATIC' in your kernel config file!\n");
        return(-1);
    }
    t = malloc(sizeof(struct wst), M_TEMP, M_NOWAIT);
    if (!t) {
        printf("wst: out of memory\n");
        return(-1);
    }
    wsttab[wstnlun] = t;
    bzero(t, sizeof(struct wst));
    bufq_init(&t->buf_queue);
    t->ata = ata;
    t->unit = unit;
    t->ata->use_dsc = 1;
    lun = t->lun = wstnlun;
    t->param = ap;
    t->flags = WST_MEDIA_CHANGED | WST_DEBUG;

    if (wst_sense(t))
	return -1;

    wst_describe(t);
    wstnlun++;

    make_dev(&wst_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0640, "rwst%d", t->lun);
    return(1);
}
예제 #4
0
STATIC sscop_t *
sscop_alloc_priv(queue_t *q)
{
	sscop_t *sp;

	if ((sp = kmem_cache_alloc(sscop_cachep))) {
		bzero(sp, sizeof(*sp));
		RD(q)->q_ptr = WR(q)->q_tpr = sp;
		sp->rq = RD(q);
		sp->wq = WR(q);

		/* link into master list */
		if ((sp->next = sscop_priv_list))
			sp->next->pprev = &sp->next;
		sp->pprev = &sscop_priv_list;
		sscop_priv_list = sp;

		sp->t_state = TS_UNINIT;

		sp->n_ostr = sscop_default_o_streams;
		sp->n_istr = sscop_default_i_streams;
		sp->a_rwnd = sscop_default_rmem;

		bufq_init(&sp->out_of_order_queue);
		bufq_init(&sp->duplicate_queue);
		bufq_init(&sp->write_queue);
		bufq_init(&sp->urgent_queue);
		bufq_init(&sp->retrans_queue);
		bufq_init(&sp->error_queue);
		bufq_init(&sp->connect_queue);

		sp->pmtu = 576;

		sp->max_retrans = sscop_assoc_max_retrans;
		sp->max_inits = sscop_max_init_retries;
	}
	return (sp);
}
예제 #5
0
/* ARGSUSED */
int
mfs_mount(struct mount *mp, const char *path, void *data,
    struct nameidata *ndp, struct proc *p)
{
	struct vnode *devvp;
	struct mfs_args args;
	struct ufsmount *ump;
	struct fs *fs;
	struct mfsnode *mfsp;
	char fspec[MNAMELEN];
	int flags, error;

	error = copyin(data, &args, sizeof(struct mfs_args));
	if (error)
		return (error);

	/*
	 * If updating, check whether changing from read-only to
	 * read/write; if there is no device name, that's all we do.
	 */
	if (mp->mnt_flag & MNT_UPDATE) {
		ump = VFSTOUFS(mp);
		fs = ump->um_fs;
		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
			flags = WRITECLOSE;
			if (mp->mnt_flag & MNT_FORCE)
				flags |= FORCECLOSE;
			error = ffs_flushfiles(mp, flags, p);
			if (error)
				return (error);
		}
		if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR))
			fs->fs_ronly = 0;
#ifdef EXPORTMFS
		if (args.fspec == NULL)
			return (vfs_export(mp, &ump->um_export, 
			    &args.export_info));
#endif
		return (0);
	}
	error = copyinstr(args.fspec, fspec, sizeof(fspec), NULL);
	if (error)
		return (error);
	error = getnewvnode(VT_MFS, NULL, &mfs_vops, &devvp);
	if (error)
		return (error);
	devvp->v_type = VBLK;
	if (checkalias(devvp, makedev(255, mfs_minor), NULL))
		panic("mfs_mount: dup dev");
	mfs_minor++;
	mfsp = malloc(sizeof *mfsp, M_MFSNODE, M_WAITOK | M_ZERO);
	devvp->v_data = mfsp;
	mfsp->mfs_baseoff = args.base;
	mfsp->mfs_size = args.size;
	mfsp->mfs_vnode = devvp;
	mfsp->mfs_pid = p->p_pid;
	bufq_init(&mfsp->mfs_bufq, BUFQ_FIFO);
	if ((error = ffs_mountfs(devvp, mp, p)) != 0) {
		mfsp->mfs_shutdown = 1;
		vrele(devvp);
		return (error);
	}
	ump = VFSTOUFS(mp);
	fs = ump->um_fs;

	memset(fs->fs_fsmnt, 0, sizeof(fs->fs_fsmnt));
	strlcpy(fs->fs_fsmnt, path, sizeof(fs->fs_fsmnt));
	memcpy(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN);
	memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
	strlcpy(mp->mnt_stat.f_mntfromname, fspec, MNAMELEN);
	memset(mp->mnt_stat.f_mntfromspec, 0, MNAMELEN);
	strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN);
	memcpy(&mp->mnt_stat.mount_info.mfs_args, &args, sizeof(args));

	return (0);
}
예제 #6
0
/*
 * The routine called by the low level scsi routine when it discovers
 * a device suitable for this driver.
 */
void
sdattach(struct device *parent, struct device *self, void *aux)
{
	struct sd_softc *sc = (struct sd_softc *)self;
	struct scsi_attach_args *sa = aux;
	struct disk_parms *dp = &sc->params;
	struct scsi_link *sc_link = sa->sa_sc_link;
	int sd_autoconf = scsi_autoconf | SCSI_SILENT |
	    SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE;
	struct dk_cache dkc;
	int error, result;

	SC_DEBUG(sc_link, SDEV_DB2, ("sdattach:\n"));

	/*
	 * Store information needed to contact our base driver
	 */
	sc->sc_link = sc_link;
	sc_link->interpret_sense = sd_interpret_sense;
	sc_link->device_softc = sc;

	if ((sc_link->flags & SDEV_ATAPI) && (sc_link->flags & SDEV_REMOVABLE))
		sc_link->quirks |= SDEV_NOSYNCCACHE;

	if (!(sc_link->inqdata.flags & SID_RelAdr))
		sc_link->quirks |= SDEV_ONLYBIG;

	/*
	 * Note if this device is ancient.  This is used in sdminphys().
	 */
	if (!(sc_link->flags & SDEV_ATAPI) &&
	    SCSISPC(sa->sa_inqbuf->version) == 0)
		sc->flags |= SDF_ANCIENT;

	/*
	 * Use the subdriver to request information regarding
	 * the drive. We cannot use interrupts yet, so the
	 * request must specify this.
	 */
	printf("\n");

	scsi_xsh_set(&sc->sc_xsh, sc_link, sdstart);
	timeout_set(&sc->sc_timeout, (void (*)(void *))scsi_xsh_add,
	    &sc->sc_xsh);

	/* Spin up non-UMASS devices ready or not. */
	if ((sc->sc_link->flags & SDEV_UMASS) == 0)
		scsi_start(sc_link, SSS_START, sd_autoconf);

	/*
	 * Some devices (e.g. Blackberry Pearl) won't admit they have
	 * media loaded unless its been locked in.
	 */
	if ((sc_link->flags & SDEV_REMOVABLE) != 0)
		scsi_prevent(sc_link, PR_PREVENT, sd_autoconf);

	/* Check that it is still responding and ok. */
	error = scsi_test_unit_ready(sc->sc_link, TEST_READY_RETRIES * 3,
	    sd_autoconf);

	if (error)
		result = SDGP_RESULT_OFFLINE;
	else
		result = sd_get_parms(sc, &sc->params, sd_autoconf);

	if ((sc_link->flags & SDEV_REMOVABLE) != 0)
		scsi_prevent(sc_link, PR_ALLOW, sd_autoconf);

	switch (result) {
	case SDGP_RESULT_OK:
		printf("%s: %lluMB, %lu bytes/sector, %llu sectors",
		    sc->sc_dev.dv_xname,
		    dp->disksize / (1048576 / dp->secsize), dp->secsize,
		    dp->disksize);
		printf("\n");
		break;

	case SDGP_RESULT_OFFLINE:
		break;

#ifdef DIAGNOSTIC
	default:
		panic("sdattach: unknown result (%#x) from get_parms", result);
		break;
#endif
	}

	/*
	 * Initialize disk structures.
	 */
	sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
	bufq_init(&sc->sc_bufq, BUFQ_FIFO);

	/*
	 * Enable write cache by default.
	 */
	memset(&dkc, 0, sizeof(dkc));
	if (sd_ioctl_cache(sc, DIOCGCACHE, &dkc) == 0 && dkc.wrcache == 0) {
		dkc.wrcache = 1;
		sd_ioctl_cache(sc, DIOCSCACHE, &dkc);
	}

	/*
	 * Establish a shutdown hook so that we can ensure that
	 * our data has actually made it onto the platter at
	 * shutdown time.  Note that this relies on the fact
	 * that the shutdown hook code puts us at the head of
	 * the list (thus guaranteeing that our hook runs before
	 * our ancestors').
	 */
	if ((sc->sc_sdhook =
	    shutdownhook_establish(sd_shutdown, sc)) == NULL)
		printf("%s: WARNING: unable to establish shutdown hook\n",
		    sc->sc_dev.dv_xname);

	/* Attach disk. */
	disk_attach(&sc->sc_dev, &sc->sc_dk);
}
예제 #7
0
void
wdattach(struct device *parent, struct device *self, void *aux)
{
	struct wd_softc *wd = (void *)self;
	struct ata_atapi_attach *aa_link= aux;
	struct wdc_command wdc_c;
	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;

	strlcpy(wd->drvp->drive_name, wd->sc_dev.dv_xname,
	    sizeof(wd->drvp->drive_name));
	wd->drvp->cf_flags = wd->sc_dev.dv_cfdata->cf_flags;

	if ((NERRS_MAX - 2) > 0)
		wd->drvp->n_dmaerrs = NERRS_MAX - 2;
	else
		wd->drvp->n_dmaerrs = 0;

	/* 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);

	wdc_probe_caps(wd->drvp, &wd->sc_params);
	wdc_print_caps(wd->drvp);

	if ((wd->sc_params.atap_multi & 0xff) > 1) {
		wd->sc_multi = wd->sc_params.atap_multi & 0xff;
	} else {
		wd->sc_multi = 1;
	}

	printf("%s: %d-sector PIO,", wd->sc_dev.dv_xname, wd->sc_multi);

	/* use 48-bit LBA if enabled */
	/* XXX: shall we use it if drive capacity < 137Gb? */
	if ((wd->sc_params.atap_cmd2_en & ATAPI_CMD2_48AD) != 0)
		wd->sc_flags |= WDF_LBA48;

	/* 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_LBA48) != 0) {
		wd->sc_capacity =
		    (((u_int64_t)wd->sc_params.atap_max_lba[3] << 48) |
		     ((u_int64_t)wd->sc_params.atap_max_lba[2] << 32) |
		     ((u_int64_t)wd->sc_params.atap_max_lba[1] << 16) |
		      (u_int64_t)wd->sc_params.atap_max_lba[0]);
		printf(" LBA48, %lluMB, %llu sectors\n",
		    wd->sc_capacity / (1048576 / DEV_BSIZE),
		    wd->sc_capacity);
	} else if ((wd->sc_flags & WDF_LBA) != 0) {
		wd->sc_capacity =
		    (wd->sc_params.atap_capacity[1] << 16) |
		    wd->sc_params.atap_capacity[0];
		printf(" LBA, %lluMB, %llu sectors\n",
		    wd->sc_capacity / (1048576 / DEV_BSIZE),
		    wd->sc_capacity);
	} else {
		wd->sc_capacity =
		    wd->sc_params.atap_cylinders *
		    wd->sc_params.atap_heads *
		    wd->sc_params.atap_sectors;
		printf(" CHS, %lluMB, %d cyl, %d head, %d sec, %llu sectors\n",
		    wd->sc_capacity / (1048576 / DEV_BSIZE),
		    wd->sc_params.atap_cylinders,
		    wd->sc_params.atap_heads,
		    wd->sc_params.atap_sectors,
		    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);

	/* use read look ahead if supported */
	if (wd->sc_params.atap_cmd_set1 & WDC_CMD1_AHEAD) {
		bzero(&wdc_c, sizeof(struct wdc_command));
		wdc_c.r_command = SET_FEATURES;
		wdc_c.r_precomp = WDSF_READAHEAD_EN;
		wdc_c.timeout = 1000;
		wdc_c.flags = at_poll;

		if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) {
			printf("%s: enable look ahead command didn't "
			    "complete\n", wd->sc_dev.dv_xname);
		}
	}

	/* use write cache if supported */
	if (wd->sc_params.atap_cmd_set1 & WDC_CMD1_CACHE) {
		bzero(&wdc_c, sizeof(struct wdc_command));
		wdc_c.r_command = SET_FEATURES;
		wdc_c.r_precomp = WDSF_EN_WR_CACHE;
		wdc_c.timeout = 1000;
		wdc_c.flags = at_poll;
	
		if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) {
			printf("%s: enable write cache command didn't "
			    "complete\n", wd->sc_dev.dv_xname);
		}
	}

	/*
	 * FREEZE LOCK the drive so malicous users can't lock it on us.
	 * As there is no harm in issuing this to drives that don't
	 * support the security feature set we just send it, and don't
	 * bother checking if the drive sends a command abort to tell us it
	 * doesn't support it.
	 */
	bzero(&wdc_c, sizeof(struct wdc_command));

	wdc_c.r_command = WDCC_SEC_FREEZE_LOCK;
	wdc_c.timeout = 1000;
	wdc_c.flags = at_poll;
	if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) {
		printf("%s: freeze lock command didn't complete\n",
		    wd->sc_dev.dv_xname);
	}

	/*
	 * Initialize disk structures.
	 */
	wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
	bufq_init(&wd->sc_bufq, BUFQ_DEFAULT);
	timeout_set(&wd->sc_restart_timeout, wdrestart, wd);

	/* Attach disk. */
	disk_attach(&wd->sc_dev, &wd->sc_dk);
	wd->sc_wdc_bio.lp = wd->sc_dk.dk_label;
}
예제 #8
0
static cam_status
ptctor(struct cam_periph *periph, void *arg)
{
	struct pt_softc *softc;
	struct ccb_setasync csa;
	struct ccb_getdev *cgd;

	cgd = (struct ccb_getdev *)arg;
	if (periph == NULL) {
		printf("ptregister: periph was NULL!!\n");
		return(CAM_REQ_CMP_ERR);
	}

	if (cgd == NULL) {
		printf("ptregister: no getdev CCB, can't register device\n");
		return(CAM_REQ_CMP_ERR);
	}

	softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);

	if (softc == NULL) {
		printf("daregister: Unable to probe new device. "
		       "Unable to allocate softc\n");				
		return(CAM_REQ_CMP_ERR);
	}

	bzero(softc, sizeof(*softc));
	LIST_INIT(&softc->pending_ccbs);
	softc->state = PT_STATE_NORMAL;
	bufq_init(&softc->buf_queue);

	softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;

	periph->softc = softc;
	
	cam_extend_set(ptperiphs, periph->unit_number, periph);

	devstat_add_entry(&softc->device_stats, "pt",
			  periph->unit_number, 0,
			  DEVSTAT_NO_BLOCKSIZE,
			  SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
			  DEVSTAT_PRIORITY_OTHER);

	softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT,
			      GID_OPERATOR, 0600, "%s%d", periph->periph_name,
			      periph->unit_number);
	/*
	 * Add async callbacks for bus reset and
	 * bus device reset calls.  I don't bother
	 * checking if this fails as, in most cases,
	 * the system will function just fine without
	 * them and the only alternative would be to
	 * not attach the device on failure.
	 */
	xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
	csa.ccb_h.func_code = XPT_SASYNC_CB;
	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
	csa.callback = ptasync;
	csa.callback_arg = periph;
	xpt_action((union ccb *)&csa);

	/* Tell the user we've attached to the device */
	xpt_announce_periph(periph, NULL);

	return(CAM_REQ_CMP);
}
예제 #9
0
/*
 * Controller is working, and drive responded.  Attach it.
 */
void
fdattach(struct device *parent, struct device *self, void *aux)
{
	struct fdc_softc *fdc = (void *)parent;
	struct fd_softc *fd = (void *)self;
	struct fdc_attach_args *fa = aux;
	struct fd_type *type = fa->fa_deftype;
	int drive = fa->fa_drive;

	if (!type || (fa->fa_flags & 0x10)) {
		/* The config has overridden this. */
		switch (fa->fa_flags & 0x07) {
		case 1:	/* 2.88MB */
			type = &fd_types[7];
			break;
		case 2:	/* 1.44MB */
			type = &fd_types[0];
			break;
		case 3: /* 1.2MB */
			type = &fd_types[1];
			break;
		case 4: /* 720K */
			type = &fd_types[4];
			break;
		case 5: /* 360K */
			type = &fd_types[3];
			break;
		case 6:	/* 1.2 MB japanese format */
			type = &fd_types[8];
			break;
#ifdef __alpha__
		default:
			/* 1.44MB, how to detect others?
			 * idea from NetBSD -- [email protected]
                         */
			type = &fd_types[0];
#endif
		}
	}

	if (type)
		printf(": %s %d cyl, %d head, %d sec\n", type->name,
		    type->tracks, type->heads, type->sectrac);
	else
		printf(": density unknown\n");

	fd->sc_cylin = -1;
	fd->sc_drive = drive;
	fd->sc_deftype = type;
	fdc->sc_type[drive] = FDC_TYPE_DISK;
	fdc->sc_link.fdlink.sc_fd[drive] = fd;

	/*
	 * Initialize and attach the disk structure.
	 */
	fd->sc_dk.dk_flags = DKF_NOLABELREAD;
	fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
	bufq_init(&fd->sc_bufq, BUFQ_DEFAULT);
	disk_attach(&fd->sc_dev, &fd->sc_dk);

	/* Setup timeout structures */
	timeout_set(&fd->fd_motor_on_to, fd_motor_on, fd);
	timeout_set(&fd->fd_motor_off_to, fd_motor_off, fd);
	timeout_set(&fd->fdtimeout_to, fdtimeout, fd);
}