Beispiel #1
0
static void 
aststrategy(struct buf *bp)
{
    struct ast_softc *stp = bp->b_dev->si_drv1;
    int s;

    if (stp->device->flags & ATA_D_DETACHING) {
	bp->b_flags |= B_ERROR;
	bp->b_error = ENXIO;
	biodone(bp);
	return;
    }

    /* if it's a null transfer, return immediatly. */
    if (bp->b_bcount == 0) {
	bp->b_resid = 0;
	biodone(bp);
	return;
    }
    if (!(bp->b_flags & B_READ) && stp->flags & F_WRITEPROTECT) {
	bp->b_flags |= B_ERROR;
	bp->b_error = EPERM;
	biodone(bp);
	return;
    }
	
    /* check for != blocksize requests */
    if (bp->b_bcount % stp->blksize) {
	ata_prtdev(stp->device, "transfers must be multiple of %d\n",
		   stp->blksize);
	bp->b_flags |= B_ERROR;
	bp->b_error = EIO;
	biodone(bp);
	return;
    }

    /* warn about transfers bigger than the device suggests */
    if (bp->b_bcount > stp->blksize * stp->cap.ctl) {	 
	if ((stp->flags & F_CTL_WARN) == 0) {
	    ata_prtdev(stp->device, "WARNING: CTL exceeded %ld>%d\n",
		       bp->b_bcount, stp->blksize * stp->cap.ctl);
	    stp->flags |= F_CTL_WARN;
	}
    }

    s = splbio();
    bufq_insert_tail(&stp->queue, bp);
    splx(s);
    ata_start(stp->device->channel);
}
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;
}
Beispiel #3
0
static int
ata_cbuschannel_banking(device_t dev, int flags)
{
    struct ata_cbus_controller *ctlr = device_get_softc(device_get_parent(dev));
    struct ata_channel *ch = device_get_softc(dev);
    int res;

    mtx_lock(&ctlr->bank_mtx);
    switch (flags) {
    case ATA_LF_LOCK:
	if (ctlr->locked_bank == -1)
	    ctlr->locked_bank = ch->unit;
	if (ctlr->locked_bank == ch->unit) {
	    ctlr->hardware_bank = ch->unit;
	    ATA_OUTB(ctlr->bankio, 0, ch->unit);
	}
	else
	    ctlr->restart_bank = ch->unit;
	break;

    case ATA_LF_UNLOCK:
	if (ctlr->locked_bank == ch->unit) {
	    ctlr->locked_bank = -1;
	    if (ctlr->restart_bank != -1) {
		if ((ch = ctlr->interrupt[ctlr->restart_bank].argument)) {
		    ctlr->restart_bank = -1;
		    mtx_unlock(&ctlr->bank_mtx);
		    ata_start(ch->dev);
		    return -1;
		}
	    }
	}
	break;

    case ATA_LF_WHICH:
	break;
    }
    res = ctlr->locked_bank;
    mtx_unlock(&ctlr->bank_mtx);
    return res;
}
Beispiel #4
0
static int
ata_serialize(device_t dev, int flags)
{
    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
    struct ata_channel *ch = device_get_softc(dev);
    struct ata_serialize *serial;
    int res;

    serial = ctlr->chipset_data;

    mtx_lock(&serial->locked_mtx);
    switch (flags) {
    case ATA_LF_LOCK:
	if (serial->locked_ch == -1)
	    serial->locked_ch = ch->unit;
	if (serial->locked_ch != ch->unit)
	    serial->restart_ch = ch->unit;
	break;

    case ATA_LF_UNLOCK:
	if (serial->locked_ch == ch->unit) {
	    serial->locked_ch = -1;
	    if (serial->restart_ch != -1) {
		if ((ch = ctlr->interrupt[serial->restart_ch].argument)) {
		    serial->restart_ch = -1;
		    mtx_unlock(&serial->locked_mtx);
		    ata_start(dev);
		    return -1;
		}
	    }
	}
	break;

    case ATA_LF_WHICH:
	break;
    }
    res = serial->locked_ch;
    mtx_unlock(&serial->locked_mtx);
    return res;
}
Beispiel #5
0
static int
ata_usbchannel_locking(device_t dev, int flags)
{
    struct atausb_softc *sc = device_get_softc(device_get_parent(dev));
    struct ata_channel *ch = device_get_softc(dev);
    int res = -1;


    spin_lock(&sc->locked_mtx);
    switch (flags) {
    case ATA_LF_LOCK:
	if (sc->locked_ch == NULL)
	    sc->locked_ch = ch;
	if (sc->locked_ch != ch)
	    sc->restart_ch = ch;
	break;

    case ATA_LF_UNLOCK:
	if (sc->locked_ch == ch) {
	    sc->locked_ch = NULL;
	    if (sc->restart_ch) {
		ch = sc->restart_ch;
		sc->restart_ch = NULL;
		spin_unlock(&sc->locked_mtx);
		ata_start(ch->dev);
		return res;
	    }
	}
	break;

    case ATA_LF_WHICH:
	break;
    }
    if (sc->locked_ch)
	res = sc->locked_ch->unit;
    spin_unlock(&sc->locked_mtx);
    return res;
}
Beispiel #6
0
int
ata_reinit(struct ata_channel *ch)
{
    int devices, misdev, newdev;

    if (!ch->r_io || !ch->r_altio || !ch->r_irq)
	return ENXIO;

    ATA_FORCELOCK_CH(ch, ATA_CONTROL);
    ch->running = NULL;
    devices = ch->devices;
    ata_printf(ch, -1, "resetting devices .. ");
    ata_reset(ch);

    if ((misdev = devices & ~ch->devices)) {
	if (misdev)
	    printf("\n");
#if NATADISK > 0
	if (misdev & ATA_ATA_MASTER && ch->device[MASTER].driver)
	    ad_detach(&ch->device[MASTER], 0);
	if (misdev & ATA_ATA_SLAVE && ch->device[SLAVE].driver)
	    ad_detach(&ch->device[SLAVE], 0);
#endif
#if DEV_ATAPIALL
	if (misdev & ATA_ATAPI_MASTER && ch->device[MASTER].driver)
	    atapi_detach(&ch->device[MASTER]);
	if (misdev & ATA_ATAPI_SLAVE && ch->device[SLAVE].driver)
	    atapi_detach(&ch->device[SLAVE]);
#endif
	if (misdev & ATA_ATA_MASTER || misdev & ATA_ATAPI_MASTER) {
	    if (ch->device[MASTER].param)
		free(ch->device[MASTER].param, M_ATA);
	    ch->device[MASTER].param = NULL;
	}
	if (misdev & ATA_ATA_SLAVE || misdev & ATA_ATAPI_SLAVE) {
	    if (ch->device[SLAVE].param)
		free(ch->device[SLAVE].param, M_ATA);
	    ch->device[SLAVE].param = NULL;
	}
    }
    if ((newdev = ~devices & ch->devices)) {
	if (newdev & ATA_ATA_MASTER)
	    if (ata_getparam(&ch->device[MASTER], ATA_C_ATA_IDENTIFY))
		ch->devices &= ~ATA_ATA_MASTER;
	if (newdev & ATA_ATA_SLAVE)
	    if (ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY))
		ch->devices &= ~ATA_ATA_SLAVE;
	if (newdev & ATA_ATAPI_MASTER)
	    if (ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY))
		ch->devices &= ~ATA_ATAPI_MASTER;
	if (newdev & ATA_ATAPI_SLAVE)
	    if (ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY))
		ch->devices &= ~ATA_ATAPI_SLAVE;
    }
    newdev = ~devices & ch->devices;
    if (!misdev && newdev)
	printf("\n");
#if NATADISK > 0
    if (newdev & ATA_ATA_MASTER && !ch->device[MASTER].driver)
	ad_attach(&ch->device[MASTER], 1);
    else if (ch->devices & ATA_ATA_MASTER && ch->device[MASTER].driver) {
	ata_getparam(&ch->device[MASTER], ATA_C_ATA_IDENTIFY);
	ad_reinit(&ch->device[MASTER]);
    }
    if (newdev & ATA_ATA_SLAVE && !ch->device[SLAVE].driver)
	ad_attach(&ch->device[SLAVE], 1);
    else if (ch->devices & (ATA_ATA_SLAVE) && ch->device[SLAVE].driver) {
	ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY);
	ad_reinit(&ch->device[SLAVE]);
    }
#endif
#if DEV_ATAPIALL
    if (newdev & ATA_ATAPI_MASTER && !ch->device[MASTER].driver)
	atapi_attach(&ch->device[MASTER], 1);
    else if (ch->devices & (ATA_ATAPI_MASTER) && ch->device[MASTER].driver) {
	ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY);
	atapi_reinit(&ch->device[MASTER]);
    }
    if (newdev & ATA_ATAPI_SLAVE && !ch->device[SLAVE].driver)
	atapi_attach(&ch->device[SLAVE], 1);
    else if (ch->devices & (ATA_ATAPI_SLAVE) && ch->device[SLAVE].driver) {
	ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY);
	atapi_reinit(&ch->device[SLAVE]);
    }
#endif
#if NATAPICAM > 0
    if (ch->devices & (ATA_ATAPI_MASTER | ATA_ATAPI_SLAVE))
	atapi_cam_reinit_bus(ch);
#endif
    printf("done\n");
    ATA_UNLOCK_CH(ch);
    ata_start(ch);
    return 0;
}
Beispiel #7
0
static void
ata_intr(void *data)
{
    struct ata_channel *ch = (struct ata_channel *)data;
    /* 
     * on PCI systems we might share an interrupt line with another
     * device or our twin ATA channel, so call ch->intr_func to figure 
     * out if it is really an interrupt we should process here
     */
    if (ch->intr_func && ch->intr_func(ch))
	return;

    /* if drive is busy it didn't interrupt */
    if (ATA_INB(ch->r_altio, ATA_ALTSTAT) & ATA_S_BUSY) {
	DELAY(100);
	if (!(ATA_INB(ch->r_altio, ATA_ALTSTAT) & ATA_S_DRQ))
	    return;
    }

    /* clear interrupt and get status */
    ch->status = ATA_INB(ch->r_io, ATA_STATUS);

    if (ch->status & ATA_S_ERROR)
	ch->error = ATA_INB(ch->r_io, ATA_ERROR);

    /* find & call the responsible driver to process this interrupt */
    switch (ch->active) {
#if NATADISK > 0
    case ATA_ACTIVE_ATA:
	if (!ch->running || ad_interrupt(ch->running) == ATA_OP_CONTINUES)
	    return;
	break;
#endif
#if DEV_ATAPIALL
    case ATA_ACTIVE_ATAPI:
	if (!ch->running || atapi_interrupt(ch->running) == ATA_OP_CONTINUES)
	    return;
	break;
#endif
    case ATA_WAIT_INTR:
    case ATA_WAIT_INTR | ATA_CONTROL:
	wakeup((caddr_t)ch);
	break;

    case ATA_WAIT_READY:
    case ATA_WAIT_READY | ATA_CONTROL:
	break;

    case ATA_IDLE:
	if (ch->flags & ATA_QUEUED) {
	    ch->active = ATA_ACTIVE;
	    if (ata_service(ch) == ATA_OP_CONTINUES)
		return;
	}
	/* FALLTHROUGH */

    default:
#ifdef ATA_DEBUG
    {
	static int intr_count = 0;

	if (intr_count++ < 10)
	    ata_printf(ch, -1, "unwanted interrupt #%d active=%02x s=%02x\n",
		       intr_count, ch->active, ch->status);
    }
#endif
	break;
    }
    ch->active &= ATA_CONTROL;
    if (ch->active & ATA_CONTROL)
	return;
    ch->running = NULL;
    ata_start(ch);
    return;
}
int
ata_reinit(device_t dev)
{
    struct ata_channel *ch = device_get_softc(dev);
    struct ata_request *request;
    device_t *children;
    int nchildren, i;

    /* check that we have a valid channel to reinit */
    if (!ch || !ch->r_irq)
	return ENXIO;

    if (bootverbose)
	device_printf(dev, "reiniting channel ..\n");

    /* poll for locking the channel */
    while (ATA_LOCKING(dev, ATA_LF_LOCK) != ch->unit)
	pause("atarini", 1);

    /* catch eventual request in ch->running */
    mtx_lock(&ch->state_mtx);
    if ((request = ch->running))
	callout_stop(&request->callout);
    ch->running = NULL;

    /* unconditionally grap the channel lock */
    ch->state |= ATA_STALL_QUEUE;
    mtx_unlock(&ch->state_mtx);

    /* reset the controller HW, the channel and device(s) */
    ATA_RESET(dev);

    /* reinit the children and delete any that fails */
    if (!device_get_children(dev, &children, &nchildren)) {
	mtx_lock(&Giant);       /* newbus suckage it needs Giant */
	for (i = 0; i < nchildren; i++) {
	    /* did any children go missing ? */
	    if (children[i] && device_is_attached(children[i]) &&
		ATA_REINIT(children[i])) {
		/*
		 * if we had a running request and its device matches
		 * this child we need to inform the request that the 
		 * device is gone.
		 */
		if (request && request->dev == children[i]) {
		    request->result = ENXIO;
		    device_printf(request->dev, "FAILURE - device detached\n");

		    /* if not timeout finish request here */
		    if (!(request->flags & ATA_R_TIMEOUT))
			    ata_finish(request);
		    request = NULL;
		}
		device_delete_child(dev, children[i]);
	    }
	}
	free(children, M_TEMP);
	mtx_unlock(&Giant);     /* newbus suckage dealt with, release Giant */
    }

    /* if we still have a good request put it on the queue again */
    if (request && !(request->flags & ATA_R_TIMEOUT)) {
	device_printf(request->dev,
		      "WARNING - %s requeued due to channel reset",
		      ata_cmd2str(request));
	if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
	    printf(" LBA=%ju", request->u.ata.lba);
	printf("\n");
	request->flags |= ATA_R_REQUEUE;
	ata_queue_request(request);
    }

    /* we're done release the channel for new work */
    mtx_lock(&ch->state_mtx);
    ch->state = ATA_IDLE;
    mtx_unlock(&ch->state_mtx);
    ATA_LOCKING(dev, ATA_LF_UNLOCK);

    if (bootverbose)
	device_printf(dev, "reinit done ..\n");

    /* kick off requests on the queue */
    ata_start(dev);
    return 0;
}
Beispiel #9
0
/*
 * device related interfaces
 */
static int
ata_ioctl(struct dev_ioctl_args *ap)
{
    device_t device, *children;
    struct ata_ioc_devices *devices = (struct ata_ioc_devices *)ap->a_data;
    int *value = (int *)ap->a_data;
    int i, nchildren, error = ENOTTY;

    switch (ap->a_cmd) {
    case IOCATAGMAXCHANNEL:
	*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);
	ata_start(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));
		    }
		}
	    }
	    kfree(children, M_TEMP);
	    error = 0;
	}
	else
	    error = ENODEV;
	break;

    default:
	if (ata_raid_ioctl_func)
	    error = ata_raid_ioctl_func(ap->a_cmd, ap->a_data);
    }
    return error;
}