NetBSD/sys/dev/scsipi/atapiconf.c
jmc c7258354f0 Force the initial probes to happen within the newly forked off kthread.
This eliminates problems where the underlying interrupt handler isn't the
specific layer calling scsipi_complete() for a given scsi transaction.
This avoids deadlocks where the kthread that called the autoconf routines
to configure a scsibus shouldn't be the one put to sleep waiting on a
scsipi_complete (only the scsibus's kthread should be doing that).

To avoid jitter this will force the scsibus's to probe in the order they
run through autoconf (so machines with multiple bus's don't move sd* devices
around on every reboot).
2002-09-19 08:31:05 +00:00

356 lines
9.6 KiB
C

/* $NetBSD: atapiconf.c,v 1.49 2002/09/19 08:31:05 jmc Exp $ */
/*
* Copyright (c) 1996, 2001 Manuel Bouyer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Manuel Bouyer.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: atapiconf.c,v 1.49 2002/09/19 08:31:05 jmc Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/kthread.h>
#include <dev/scsipi/scsipi_all.h>
#include <dev/scsipi/scsipiconf.h>
#include <dev/scsipi/atapiconf.h>
#include "locators.h"
#define SILENT_PRINTF(flags,string) if (!(flags & A_SILENT)) printf string
#define MAX_TARGET 1
const struct scsipi_periphsw atapi_probe_periphsw = {
NULL,
NULL,
NULL,
NULL,
};
int atapibusmatch __P((struct device *, struct cfdata *, void *));
void atapibusattach __P((struct device *, struct device *, void *));
int atapibusactivate __P((struct device *, enum devact));
int atapibusdetach __P((struct device *, int flags));
int atapibussubmatch __P((struct device *, struct cfdata *, void *));
int atapi_probe_bus __P((struct atapibus_softc *, int));
struct cfattach atapibus_ca = {
sizeof(struct atapibus_softc), atapibusmatch, atapibusattach,
atapibusdetach, atapibusactivate,
};
extern struct cfdriver atapibus_cd;
int atapibusprint __P((void *, const char *));
const struct scsi_quirk_inquiry_pattern atapi_quirk_patterns[] = {
{{T_CDROM, T_REMOV,
"ALPS ELECTRIC CO.,LTD. DC544C", "", "SW03D"}, PQUIRK_NOTUR},
{{T_CDROM, T_REMOV,
"BCD-16X 1997-04-25", "", "VER 2.2"}, PQUIRK_NOSTARTUNIT},
{{T_CDROM, T_REMOV,
"BCD-24X 1997-06-27", "", "VER 2.0"}, PQUIRK_NOSTARTUNIT},
{{T_CDROM, T_REMOV,
"CR-2801TE", "", "1.07"}, PQUIRK_NOSENSE},
{{T_CDROM, T_REMOV,
"CREATIVECD3630E", "", "AC101"}, PQUIRK_NOSENSE},
{{T_CDROM, T_REMOV,
"FX320S", "", "q01"}, PQUIRK_NOSENSE},
{{T_CDROM, T_REMOV,
"GCD-R580B", "", "1.00"}, PQUIRK_LITTLETOC},
{{T_CDROM, T_REMOV,
"HITACHI CDR-7730", "", "0008a"}, PQUIRK_NOSENSE},
{{T_CDROM, T_REMOV,
"MATSHITA CR-574", "", "1.02"}, PQUIRK_NOCAPACITY},
{{T_CDROM, T_REMOV,
"MATSHITA CR-574", "", "1.06"}, PQUIRK_NOCAPACITY},
{{T_CDROM, T_REMOV,
"Memorex CRW-2642", "", "1.0g"}, PQUIRK_NOSENSE},
{{T_CDROM, T_REMOV,
"NEC CD-ROM DRIVE:273", "", "4.21"}, PQUIRK_NOTUR},
{{T_CDROM, T_REMOV,
"SANYO CRD-256P", "", "1.02"}, PQUIRK_NOCAPACITY},
{{T_CDROM, T_REMOV,
"SANYO CRD-254P", "", "1.02"}, PQUIRK_NOCAPACITY},
{{T_CDROM, T_REMOV,
"SANYO CRD-S54P", "", "1.08"}, PQUIRK_NOCAPACITY},
{{T_CDROM, T_REMOV,
"CD-ROM CDR-S1", "", "1.70"}, PQUIRK_NOCAPACITY}, /* Sanyo */
{{T_CDROM, T_REMOV,
"CD-ROM CDR-N16", "", "1.25"}, PQUIRK_NOCAPACITY}, /* Sanyo */
{{T_CDROM, T_REMOV,
"UJDCD8730", "", "1.14"}, PQUIRK_NODOORLOCK}, /* Acer */
{{T_DIRECT, T_REMOV, /* Panasonic MultiMediaCard */
"04DA", "1B00", "0010"}, PQUIRK_BYTE5_ZERO |
PQUIRK_NO_FLEX_PAGE },
{{T_DIRECT, T_REMOV, /* ZiO! MultiMediaCard */
"eUSB", "MultiMediaCard", ""}, PQUIRK_NO_FLEX_PAGE },
{{T_DIRECT, T_REMOV,
"FUJIFILM", "USB-DRIVEUNIT", "1.00"}, PQUIRK_NO_FLEX_PAGE |
PQUIRK_NOSENSE },
};
int
atapiprint(aux, pnp)
void *aux;
const char *pnp;
{
struct scsipi_channel *chan = aux;
if (pnp)
printf("atapibus at %s", pnp);
printf(" channel %d", chan->chan_channel);
return (UNCONF);
}
int
atapibusmatch(parent, cf, aux)
struct device *parent;
struct cfdata *cf;
void *aux;
{
struct scsipi_channel *chan = aux;
if (chan == NULL)
return (0);
if (chan->chan_bustype->bustype_type != SCSIPI_BUSTYPE_ATAPI)
return (0);
if (cf->cf_loc[ATAPICF_CHANNEL] != chan->chan_channel &&
cf->cf_loc[ATAPICF_CHANNEL] != ATAPICF_CHANNEL_DEFAULT)
return (0);
return (1);
}
int
atapibussubmatch(parent, cf, aux)
struct device *parent;
struct cfdata *cf;
void *aux;
{
struct scsipibus_attach_args *sa = aux;
struct scsipi_periph *periph = sa->sa_periph;
if (cf->cf_loc[ATAPIBUSCF_DRIVE] != ATAPIBUSCF_DRIVE_DEFAULT &&
cf->cf_loc[ATAPIBUSCF_DRIVE] != periph->periph_target)
return (0);
return ((*cf->cf_attach->ca_match)(parent, cf, aux));
}
void
atapibusattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct atapibus_softc *sc = (void *) self;
struct scsipi_channel *chan = aux;
sc->sc_channel = chan;
chan->chan_name = sc->sc_dev.dv_xname;
/* ATAPI has no LUNs. */
chan->chan_nluns = 1;
printf(": %d targets\n", chan->chan_ntargets);
/* Initialize the channel. */
chan->chan_init_cb = NULL;
chan->chan_init_cb_arg = NULL;
scsipi_channel_init(chan);
/* Probe the bus for devices. */
atapi_probe_bus(sc, -1);
}
int
atapibusactivate(self, act)
struct device *self;
enum devact act;
{
struct atapibus_softc *sc = (void *) self;
struct scsipi_channel *chan = sc->sc_channel;
struct scsipi_periph *periph;
int target, error = 0, s;
s = splbio();
switch (act) {
case DVACT_ACTIVATE:
error = EOPNOTSUPP;
break;
case DVACT_DEACTIVATE:
for (target = 0; target < chan->chan_ntargets; target++) {
periph = scsipi_lookup_periph(chan, target, 0);
if (periph == NULL)
continue;
error = config_deactivate(periph->periph_dev);
if (error)
goto out;
}
break;
}
out:
splx(s);
return (error);
}
int
atapibusdetach(self, flags)
struct device *self;
int flags;
{
struct atapibus_softc *sc = (void *)self;
struct scsipi_channel *chan = sc->sc_channel;
struct scsipi_periph *periph;
int target, error;
/*
* Shut down the channel.
*/
scsipi_channel_shutdown(chan);
/*
* Now detach all of the periphs.
*/
for (target = 0; target < chan->chan_ntargets; target++) {
periph = scsipi_lookup_periph(chan, target, 0);
if (periph == NULL)
continue;
error = config_detach(periph->periph_dev, flags);
if (error)
return (error);
scsipi_remove_periph(chan, periph);
free(periph, M_DEVBUF);
}
return (0);
}
int
atapi_probe_bus(sc, target)
struct atapibus_softc *sc;
int target;
{
struct scsipi_channel *chan = sc->sc_channel;
int maxtarget, mintarget;
int error;
struct atapi_adapter *atapi_adapter;
if (target == -1) {
maxtarget = 1;
mintarget = 0;
} else {
if (target < 0 || target >= chan->chan_ntargets)
return (ENXIO);
maxtarget = mintarget = target;
}
if ((error = scsipi_adapter_addref(chan->chan_adapter)) != 0)
return (error);
atapi_adapter = (struct atapi_adapter*)chan->chan_adapter;
for (target = mintarget; target <= maxtarget; target++)
atapi_adapter->atapi_probe_device(sc, target);
scsipi_adapter_delref(chan->chan_adapter);
return (0);
}
void *
atapi_probe_device(sc, target, periph, sa)
struct atapibus_softc *sc;
int target;
struct scsipi_periph *periph;
struct scsipibus_attach_args *sa;
{
struct scsipi_channel *chan = sc->sc_channel;
struct scsi_quirk_inquiry_pattern *finger;
struct cfdata *cf;
int priority, quirks;
finger = (struct scsi_quirk_inquiry_pattern *)scsipi_inqmatch(
&sa->sa_inqbuf, (caddr_t)atapi_quirk_patterns,
sizeof(atapi_quirk_patterns) /
sizeof(atapi_quirk_patterns[0]),
sizeof(atapi_quirk_patterns[0]), &priority);
if (finger != NULL)
quirks = finger->quirks;
else
quirks = 0;
/*
* Now apply any quirks from the table.
*/
periph->periph_quirks |= quirks;
if ((cf = config_search(atapibussubmatch, &sc->sc_dev,
sa)) != 0) {
scsipi_insert_periph(chan, periph);
/*
* XXX Can't assign periph_dev here, because we'll
* XXX need it before config_attach() returns. Must
* XXX assign it in periph driver.
*/
return config_attach(&sc->sc_dev, cf, sa,
atapibusprint);
} else {
atapibusprint(sa, sc->sc_dev.dv_xname);
printf(" not configured\n");
free(periph, M_DEVBUF);
return NULL;
}
}
int
atapibusprint(aux, pnp)
void *aux;
const char *pnp;
{
struct scsipibus_attach_args *sa = aux;
struct scsipi_inquiry_pattern *inqbuf;
char *dtype;
if (pnp != NULL)
printf("%s", pnp);
inqbuf = &sa->sa_inqbuf;
dtype = scsipi_dtype(inqbuf->type & SID_TYPE);
printf(" drive %d: <%s, %s, %s> type %d %s %s",
sa->sa_periph->periph_target ,inqbuf->vendor,
inqbuf->product, inqbuf->revision, inqbuf->type, dtype,
inqbuf->removable ? "removable" : "fixed");
return (UNCONF);
}