Exemplo n.º 1
0
static void
ata_cam_process_sense(device_t dev, struct ata_request *request)
{
	struct ata_channel *ch = device_get_softc(dev);
	union ccb *ccb = request->ccb;
	int fatalerr = 0;

	ch->requestsense = 0;

	if (request->flags & ATA_R_TIMEOUT)
		fatalerr = 1;
	if ((request->flags & ATA_R_TIMEOUT) == 0 &&
	    (request->status & ATA_S_ERROR) == 0 &&
	    request->result == 0) {
		ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
	} else {
		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
		ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
	}

	ata_free_request(request);
	xpt_done(ccb);
	/* Do error recovery if needed. */
	if (fatalerr)
		ata_reinit(dev);
}
Exemplo n.º 2
0
int
ata_resume(device_t dev)
{
    struct ata_channel *ch;
    int error;

    /* check for valid device */
    if (!dev || !(ch = device_get_softc(dev)))
	return ENXIO;

    /* reinit the devices, we dont know what mode/state they are in */
    error = ata_reinit(dev);

    /* kick off requests on the queue */
    ata_start(dev);
    return error;
}
Exemplo n.º 3
0
int
ata_resume(device_t dev)
{
    struct ata_channel *ch;
    int error;

    /* check for valid device */
    if (!dev || !(ch = device_get_softc(dev)))
	return ENXIO;

	mtx_lock(&ch->state_mtx);
	error = ata_reinit(dev);
	xpt_release_simq(ch->sim, TRUE);
	mtx_unlock(&ch->state_mtx);
	if (ch->flags & ATA_PERIODIC_POLL)
		callout_reset(&ch->poll_callout, hz, ata_periodic_poll, ch);
    return error;
}
Exemplo n.º 4
0
static void
ata_conn_event(void *context, int dummy)
{
	device_t dev = (device_t)context;
	struct ata_channel *ch = device_get_softc(dev);
	union ccb *ccb;

	mtx_lock(&ch->state_mtx);
	if (ch->sim == NULL) {
		mtx_unlock(&ch->state_mtx);
		return;
	}
	ata_reinit(dev);
	if ((ccb = xpt_alloc_ccb_nowait()) == NULL)
		return;
	if (xpt_create_path(&ccb->ccb_h.path, NULL,
	    cam_sim_path(ch->sim),
	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
		xpt_free_ccb(ccb);
		return;
	}
	xpt_rescan(ccb);
	mtx_unlock(&ch->state_mtx);
}
Exemplo n.º 5
0
static void
ataaction(struct cam_sim *sim, union ccb *ccb)
{
	device_t dev, parent;
	struct ata_channel *ch;

	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ataaction func_code=%x\n",
	    ccb->ccb_h.func_code));

	ch = (struct ata_channel *)cam_sim_softc(sim);
	dev = ch->dev;
	switch (ccb->ccb_h.func_code) {
	/* Common cases first */
	case XPT_ATA_IO:	/* Execute the requested I/O operation */
	case XPT_SCSI_IO:
		if (ata_check_ids(dev, ccb))
			return;
		if ((ch->devices & ((ATA_ATA_MASTER | ATA_ATAPI_MASTER)
		    << ccb->ccb_h.target_id)) == 0) {
			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
			break;
		}
		if (ch->running)
			device_printf(dev, "already running!\n");
		if (ccb->ccb_h.func_code == XPT_ATA_IO &&
		    (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
		    (ccb->ataio.cmd.control & ATA_A_RESET)) {
			struct ata_res *res = &ccb->ataio.res;
			
			bzero(res, sizeof(*res));
			if (ch->devices & (ATA_ATA_MASTER << ccb->ccb_h.target_id)) {
				res->lba_high = 0;
				res->lba_mid = 0;
			} else {
				res->lba_high = 0xeb;
				res->lba_mid = 0x14;
			}
			ccb->ccb_h.status = CAM_REQ_CMP;
			break;
		}
		ata_cam_begin_transaction(dev, ccb);
		return;
	case XPT_EN_LUN:		/* Enable LUN as a target */
	case XPT_TARGET_IO:		/* Execute target I/O request */
	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
	case XPT_ABORT:			/* Abort the specified CCB */
		/* XXX Implement */
		ccb->ccb_h.status = CAM_REQ_INVALID;
		break;
	case XPT_SET_TRAN_SETTINGS:
	{
		struct	ccb_trans_settings *cts = &ccb->cts;
		struct	ata_cam_device *d; 

		if (ata_check_ids(dev, ccb))
			return;
		if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
			d = &ch->curr[ccb->ccb_h.target_id];
		else
			d = &ch->user[ccb->ccb_h.target_id];
		if (ch->flags & ATA_SATA) {
			if (cts->xport_specific.sata.valid & CTS_SATA_VALID_REVISION)
				d->revision = cts->xport_specific.sata.revision;
			if (cts->xport_specific.sata.valid & CTS_SATA_VALID_MODE) {
				if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
					d->mode = ATA_SETMODE(ch->dev,
					    ccb->ccb_h.target_id,
					    cts->xport_specific.sata.mode);
				} else
					d->mode = cts->xport_specific.sata.mode;
			}
			if (cts->xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
				d->bytecount = min(8192, cts->xport_specific.sata.bytecount);
			if (cts->xport_specific.sata.valid & CTS_SATA_VALID_ATAPI)
				d->atapi = cts->xport_specific.sata.atapi;
			if (cts->xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
				d->caps = cts->xport_specific.sata.caps;
		} else {
			if (cts->xport_specific.ata.valid & CTS_ATA_VALID_MODE) {
				if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
					d->mode = ATA_SETMODE(ch->dev,
					    ccb->ccb_h.target_id,
					    cts->xport_specific.ata.mode);
				} else
					d->mode = cts->xport_specific.ata.mode;
			}
			if (cts->xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
				d->bytecount = cts->xport_specific.ata.bytecount;
			if (cts->xport_specific.ata.valid & CTS_ATA_VALID_ATAPI)
				d->atapi = cts->xport_specific.ata.atapi;
			if (cts->xport_specific.ata.valid & CTS_ATA_VALID_CAPS)
				d->caps = cts->xport_specific.ata.caps;
		}
		ccb->ccb_h.status = CAM_REQ_CMP;
		break;
	}
	case XPT_GET_TRAN_SETTINGS:
	{
		struct	ccb_trans_settings *cts = &ccb->cts;
		struct  ata_cam_device *d;

		if (ata_check_ids(dev, ccb))
			return;
		if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
			d = &ch->curr[ccb->ccb_h.target_id];
		else
			d = &ch->user[ccb->ccb_h.target_id];
		cts->protocol = PROTO_UNSPECIFIED;
		cts->protocol_version = PROTO_VERSION_UNSPECIFIED;
		if (ch->flags & ATA_SATA) {
			cts->transport = XPORT_SATA;
			cts->transport_version = XPORT_VERSION_UNSPECIFIED;
			cts->xport_specific.sata.valid = 0;
			cts->xport_specific.sata.mode = d->mode;
			cts->xport_specific.sata.valid |= CTS_SATA_VALID_MODE;
			cts->xport_specific.sata.bytecount = d->bytecount;
			cts->xport_specific.sata.valid |= CTS_SATA_VALID_BYTECOUNT;
			if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
				cts->xport_specific.sata.revision =
				    ATA_GETREV(dev, ccb->ccb_h.target_id);
				if (cts->xport_specific.sata.revision != 0xff) {
					cts->xport_specific.sata.valid |=
					    CTS_SATA_VALID_REVISION;
				}
				cts->xport_specific.sata.caps =
				    d->caps & CTS_SATA_CAPS_D;
				if (ch->pm_level) {
					cts->xport_specific.sata.caps |=
					    CTS_SATA_CAPS_H_PMREQ;
				}
				cts->xport_specific.sata.caps &=
				    ch->user[ccb->ccb_h.target_id].caps;
			} else {
				cts->xport_specific.sata.revision = d->revision;
				cts->xport_specific.sata.valid |= CTS_SATA_VALID_REVISION;
				cts->xport_specific.sata.caps = d->caps;
			}
			cts->xport_specific.sata.valid |= CTS_SATA_VALID_CAPS;
			cts->xport_specific.sata.atapi = d->atapi;
			cts->xport_specific.sata.valid |= CTS_SATA_VALID_ATAPI;
		} else {
			cts->transport = XPORT_ATA;
			cts->transport_version = XPORT_VERSION_UNSPECIFIED;
			cts->xport_specific.ata.valid = 0;
			cts->xport_specific.ata.mode = d->mode;
			cts->xport_specific.ata.valid |= CTS_ATA_VALID_MODE;
			cts->xport_specific.ata.bytecount = d->bytecount;
			cts->xport_specific.ata.valid |= CTS_ATA_VALID_BYTECOUNT;
			if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
				cts->xport_specific.ata.caps =
				    d->caps & CTS_ATA_CAPS_D;
				if (!(ch->flags & ATA_NO_48BIT_DMA))
					cts->xport_specific.ata.caps |=
					    CTS_ATA_CAPS_H_DMA48;
				cts->xport_specific.ata.caps &=
				    ch->user[ccb->ccb_h.target_id].caps;
			} else
				cts->xport_specific.ata.caps = d->caps;
			cts->xport_specific.ata.valid |= CTS_ATA_VALID_CAPS;
			cts->xport_specific.ata.atapi = d->atapi;
			cts->xport_specific.ata.valid |= CTS_ATA_VALID_ATAPI;
		}
		ccb->ccb_h.status = CAM_REQ_CMP;
		break;
	}
	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
		ata_reinit(dev);
		ccb->ccb_h.status = CAM_REQ_CMP;
		break;
	case XPT_TERM_IO:		/* Terminate the I/O process */
		/* XXX Implement */
		ccb->ccb_h.status = CAM_REQ_INVALID;
		break;
	case XPT_PATH_INQ:		/* Path routing inquiry */
	{
		struct ccb_pathinq *cpi = &ccb->cpi;

		parent = device_get_parent(dev);
		cpi->version_num = 1; /* XXX??? */
		cpi->hba_inquiry = PI_SDTR_ABLE;
		cpi->target_sprt = 0;
		cpi->hba_misc = PIM_SEQSCAN;
		cpi->hba_eng_cnt = 0;
		if (ch->flags & ATA_NO_SLAVE)
			cpi->max_target = 0;
		else
			cpi->max_target = 1;
		cpi->max_lun = 0;
		cpi->initiator_id = 0;
		cpi->bus_id = cam_sim_bus(sim);
		if (ch->flags & ATA_SATA)
			cpi->base_transfer_speed = 150000;
		else
			cpi->base_transfer_speed = 3300;
		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
		strncpy(cpi->hba_vid, "ATA", HBA_IDLEN);
		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
		cpi->unit_number = cam_sim_unit(sim);
		if (ch->flags & ATA_SATA)
			cpi->transport = XPORT_SATA;
		else
			cpi->transport = XPORT_ATA;
		cpi->transport_version = XPORT_VERSION_UNSPECIFIED;
		cpi->protocol = PROTO_ATA;
		cpi->protocol_version = PROTO_VERSION_UNSPECIFIED;
		cpi->maxio = ch->dma.max_iosize ? ch->dma.max_iosize : DFLTPHYS;
		if (device_get_devclass(device_get_parent(parent)) ==
		    devclass_find("pci")) {
			cpi->hba_vendor = pci_get_vendor(parent);
			cpi->hba_device = pci_get_device(parent);
			cpi->hba_subvendor = pci_get_subvendor(parent);
			cpi->hba_subdevice = pci_get_subdevice(parent);
		}
		cpi->ccb_h.status = CAM_REQ_CMP;
		break;
	}
	default:
		ccb->ccb_h.status = CAM_REQ_INVALID;
		break;
	}
	xpt_done(ccb);
}
Exemplo n.º 6
0
static void
ata_cam_end_transaction(device_t dev, struct ata_request *request)
{
	struct ata_channel *ch = device_get_softc(dev);
	union ccb *ccb = request->ccb;
	int fatalerr = 0;

	if (ch->requestsense) {
		ata_cam_process_sense(dev, request);
		return;
	}

	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
	if (request->flags & ATA_R_TIMEOUT) {
		xpt_freeze_simq(ch->sim, 1);
		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
		ccb->ccb_h.status |= CAM_CMD_TIMEOUT | CAM_RELEASE_SIMQ;
		fatalerr = 1;
	} else if (request->status & ATA_S_ERROR) {
		if (ccb->ccb_h.func_code == XPT_ATA_IO) {
			ccb->ccb_h.status |= CAM_ATA_STATUS_ERROR;
		} else {
			ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
		}
	} else if (request->result == ERESTART)
		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
	else if (request->result != 0)
		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
	else
		ccb->ccb_h.status |= CAM_REQ_CMP;
	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP &&
	    !(ccb->ccb_h.status & CAM_DEV_QFRZN)) {
		xpt_freeze_devq(ccb->ccb_h.path, 1);
		ccb->ccb_h.status |= CAM_DEV_QFRZN;
	}
	if (ccb->ccb_h.func_code == XPT_ATA_IO &&
	    ((request->status & ATA_S_ERROR) ||
	    (ccb->ataio.cmd.flags & CAM_ATAIO_NEEDRESULT))) {
		struct ata_res *res = &ccb->ataio.res;
		res->status = request->status;
		res->error = request->error;
		res->lba_low = request->u.ata.lba;
		res->lba_mid = request->u.ata.lba >> 8;
		res->lba_high = request->u.ata.lba >> 16;
		res->device = request->u.ata.lba >> 24;
		res->lba_low_exp = request->u.ata.lba >> 24;
		res->lba_mid_exp = request->u.ata.lba >> 32;
		res->lba_high_exp = request->u.ata.lba >> 40;
		res->sector_count = request->u.ata.count;
		res->sector_count_exp = request->u.ata.count >> 8;
	}
	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
		if (ccb->ccb_h.func_code == XPT_ATA_IO) {
			ccb->ataio.resid =
			    ccb->ataio.dxfer_len - request->donecount;
		} else {
			ccb->csio.resid =
			    ccb->csio.dxfer_len - request->donecount;
		}
	}
	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR &&
	    (ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
		ata_cam_request_sense(dev, request);
	else {
		ata_free_request(request);
		xpt_done(ccb);
	}
	/* Do error recovery if needed. */
	if (fatalerr)
		ata_reinit(dev);
}
Exemplo n.º 7
0
static int
ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
{
    struct ata_cmd *iocmd = (struct ata_cmd *)addr;
    struct ata_channel *ch;
    device_t device = devclass_get_device(ata_devclass, iocmd->channel);
    int error;

    if (cmd != IOCATA)
	return ENOTTY;
    
    if (iocmd->channel < -1 || iocmd->device < -1 || iocmd->device > SLAVE)
	return ENXIO;

    switch (iocmd->cmd) {
	case ATAATTACH:
	    /* should enable channel HW on controller that can SOS XXX */   
	    error = ata_probe(device);
	    if (!error)
		error = ata_attach(device);
	    return error;

	case ATADETACH:
	    error = ata_detach(device);
	    /* should disable channel HW on controller that can SOS XXX */   
	    return error;

	case ATAREINIT:
	    if (!device || !(ch = device_get_softc(device)))
		return ENXIO;
	    ATA_SLEEPLOCK_CH(ch, ATA_ACTIVE);
	    if ((error = ata_reinit(ch)))
		ATA_UNLOCK_CH(ch);
	    return error;

	case ATAGMODE:
	    if (!device || !(ch = device_get_softc(device)))
		return ENXIO;

	    if ((iocmd->device == MASTER || iocmd->device == -1) &&
		ch->device[MASTER].driver)
		iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode;
	    else
		iocmd->u.mode.mode[MASTER] = -1;

	    if ((iocmd->device == SLAVE || iocmd->device == -1) &&
		ch->device[SLAVE].param)
		iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode;
	    else
		iocmd->u.mode.mode[SLAVE] = -1;
	    return 0;

	case ATASMODE:
	    if (!device || !(ch = device_get_softc(device)))
		return ENXIO;

	    if ((iocmd->device == MASTER || iocmd->device == -1) &&
		iocmd->u.mode.mode[MASTER] >= 0 && ch->device[MASTER].param) {
		ata_change_mode(&ch->device[MASTER],iocmd->u.mode.mode[MASTER]);
		iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode;
	    }
	    else
		iocmd->u.mode.mode[MASTER] = -1;

	    if ((iocmd->device == SLAVE || iocmd->device == -1) &&
		iocmd->u.mode.mode[SLAVE] >= 0 && ch->device[SLAVE].param) {
		ata_change_mode(&ch->device[SLAVE], iocmd->u.mode.mode[SLAVE]);
		iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode;
	    }
	    else
		iocmd->u.mode.mode[SLAVE] = -1;
	    return 0;

	case ATAGPARM:
	    if (!device || !(ch = device_get_softc(device)))
		return ENXIO;

	    iocmd->u.param.type[MASTER] = 
		ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER);
	    iocmd->u.param.type[SLAVE] =
		ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE);

	    if (ch->device[MASTER].name)
		strcpy(iocmd->u.param.name[MASTER], ch->device[MASTER].name);
	    if (ch->device[SLAVE].name)
		strcpy(iocmd->u.param.name[SLAVE], ch->device[SLAVE].name);

	    if (ch->device[MASTER].param)
		bcopy(ch->device[MASTER].param, &iocmd->u.param.params[MASTER],
		      sizeof(struct ata_params));
	    if (ch->device[SLAVE].param)
		bcopy(ch->device[SLAVE].param, &iocmd->u.param.params[SLAVE],
		      sizeof(struct ata_params));
	    return 0;

	case ATAENCSTAT: {
	    struct ata_device *atadev;

	    if (!device || !(ch = device_get_softc(device)))
		return ENXIO;

	    if (iocmd->device == SLAVE)
		atadev = &ch->device[SLAVE];
	    else
		atadev = &ch->device[MASTER];

	    return ata_enclosure_status(atadev,
					&iocmd->u.enclosure.fan,
					&iocmd->u.enclosure.temp,
					&iocmd->u.enclosure.v05,
					&iocmd->u.enclosure.v12);
	}

#if NATADISK > 0
	case ATARAIDREBUILD:
	    return ata_raid_rebuild(iocmd->channel);

	case ATARAIDCREATE:
	    return ata_raid_create(&iocmd->u.raid_setup);

	case ATARAIDDELETE:
	    return ata_raid_delete(iocmd->channel);

	case ATARAIDSTATUS:
	    return ata_raid_status(iocmd->channel, &iocmd->u.raid_status);
#endif
#if DEV_ATAPIALL
	case ATAPICMD: {
	    struct ata_device *atadev;
	    caddr_t buf;

	    if (!device || !(ch = device_get_softc(device)))
		return ENXIO;

	    if (!(atadev = &ch->device[iocmd->device]) ||
		!(ch->devices & (iocmd->device == MASTER ?
				 ATA_ATAPI_MASTER : ATA_ATAPI_SLAVE)))
		return ENODEV;

	    if (!(buf = malloc(iocmd->u.atapi.count, M_ATA, M_NOWAIT)))
		return ENOMEM;

	    if (iocmd->u.atapi.flags & ATAPI_CMD_WRITE) {
		error = copyin(iocmd->u.atapi.data, buf, iocmd->u.atapi.count);
		if (error)
		    return error;
	    }
	    error = atapi_queue_cmd(atadev, iocmd->u.atapi.ccb,
				    buf, iocmd->u.atapi.count,
				    (iocmd->u.atapi.flags == ATAPI_CMD_READ ?
				     ATPR_F_READ : 0) | ATPR_F_QUIET, 
				    iocmd->u.atapi.timeout, NULL, NULL);
	    if (error) {
		iocmd->u.atapi.error = error;
		bcopy(&atadev->result, iocmd->u.atapi.sense_data,
		      sizeof(struct atapi_reqsense));
		error = 0;
	    }
	    else if (iocmd->u.atapi.flags & ATAPI_CMD_READ)
		error = copyout(buf, iocmd->u.atapi.data, iocmd->u.atapi.count);

	    free(buf, M_ATA);
	    return error;
	}
#endif
	default:
	    break;
    }
    return ENOTTY;
}
Exemplo n.º 8
0
int
ata_resume(device_t dev)
{
    return ata_reinit(device_get_softc(dev));
}
Exemplo n.º 9
0
/*
 * device related interfaces
 */
static int
ata_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
	  int32_t flag, struct thread *td)
{
    device_t device, *children;
    struct ata_ioc_devices *devices = (struct ata_ioc_devices *)data;
    int *value = (int *)data;
    int i, nchildren, error = ENOTTY;

    switch (cmd) {
    case IOCATAGMAXCHANNEL:
	/* In case we have channel 0..n this will return n+1. */
	*value = devclass_get_maxunit(ata_devclass);
	error = 0;
	break;

    case IOCATAREINIT:
	if (*value >= devclass_get_maxunit(ata_devclass) ||
	    !(device = devclass_get_device(ata_devclass, *value)))
	    return ENXIO;
	error = ata_reinit(device);
	break;

    case IOCATAATTACH:
	if (*value >= devclass_get_maxunit(ata_devclass) ||
	    !(device = devclass_get_device(ata_devclass, *value)))
	    return ENXIO;
	/* XXX SOS should enable channel HW on controller */
	error = ata_attach(device);
	break;

    case IOCATADETACH:
	if (*value >= devclass_get_maxunit(ata_devclass) ||
	    !(device = devclass_get_device(ata_devclass, *value)))
	    return ENXIO;
	error = ata_detach(device);
	/* XXX SOS should disable channel HW on controller */
	break;

    case IOCATADEVICES:
	if (devices->channel >= devclass_get_maxunit(ata_devclass) ||
	    !(device = devclass_get_device(ata_devclass, devices->channel)))
	    return ENXIO;
	bzero(devices->name[0], 32);
	bzero(&devices->params[0], sizeof(struct ata_params));
	bzero(devices->name[1], 32);
	bzero(&devices->params[1], sizeof(struct ata_params));
	if (!device_get_children(device, &children, &nchildren)) {
	    for (i = 0; i < nchildren; i++) {
		if (children[i] && device_is_attached(children[i])) {
		    struct ata_device *atadev = device_get_softc(children[i]);

		    if (atadev->unit == ATA_MASTER) {
			strncpy(devices->name[0],
				device_get_nameunit(children[i]), 32);
			bcopy(&atadev->param, &devices->params[0],
			      sizeof(struct ata_params));
		    }
		    if (atadev->unit == ATA_SLAVE) {
			strncpy(devices->name[1],
				device_get_nameunit(children[i]), 32);
			bcopy(&atadev->param, &devices->params[1],
			      sizeof(struct ata_params));
		    }
		}
	    }
	    free(children, M_TEMP);
	    error = 0;
	}
	else
	    error = ENODEV;
	break;

    default:
	if (ata_raid_ioctl_func)
	    error = ata_raid_ioctl_func(cmd, data);
    }
    return error;
}