xref: /netbsd-src/sys/dev/scsipi/atapiconf.c (revision ef3476fb5721c4ddb85643c5ce2f7cbbc30a2820)
1*ef3476fbSriastradh /*	$NetBSD: atapiconf.c,v 1.95 2022/04/09 23:38:32 riastradh Exp $	*/
26f3bab1fSbouyer 
36f3bab1fSbouyer /*
4bfc80822Sbouyer  * Copyright (c) 1996, 2001 Manuel Bouyer.  All rights reserved.
56f3bab1fSbouyer  *
66f3bab1fSbouyer  * Redistribution and use in source and binary forms, with or without
76f3bab1fSbouyer  * modification, are permitted provided that the following conditions
86f3bab1fSbouyer  * are met:
96f3bab1fSbouyer  * 1. Redistributions of source code must retain the above copyright
106f3bab1fSbouyer  *    notice, this list of conditions and the following disclaimer.
116f3bab1fSbouyer  * 2. Redistributions in binary form must reproduce the above copyright
126f3bab1fSbouyer  *    notice, this list of conditions and the following disclaimer in the
136f3bab1fSbouyer  *    documentation and/or other materials provided with the distribution.
146f3bab1fSbouyer  *
156f3bab1fSbouyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
166f3bab1fSbouyer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
176f3bab1fSbouyer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
186f3bab1fSbouyer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
196f3bab1fSbouyer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
206f3bab1fSbouyer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
216f3bab1fSbouyer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
226f3bab1fSbouyer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
236f3bab1fSbouyer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
246f3bab1fSbouyer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
256f3bab1fSbouyer  */
266f3bab1fSbouyer 
277ba10b35Slukem #include <sys/cdefs.h>
28*ef3476fbSriastradh __KERNEL_RCSID(0, "$NetBSD: atapiconf.c,v 1.95 2022/04/09 23:38:32 riastradh Exp $");
297ba10b35Slukem 
306f3bab1fSbouyer #include <sys/param.h>
316f3bab1fSbouyer #include <sys/systm.h>
326f3bab1fSbouyer #include <sys/malloc.h>
336f3bab1fSbouyer #include <sys/device.h>
346f3bab1fSbouyer #include <sys/buf.h>
356f3bab1fSbouyer #include <sys/proc.h>
36937a7a3eSbouyer #include <sys/kthread.h>
37a6a95dd6Smlelstv #include <sys/atomic.h>
386f3bab1fSbouyer 
396f3bab1fSbouyer #include <dev/scsipi/scsipi_all.h>
40937a7a3eSbouyer #include <dev/scsipi/scsipiconf.h>
416f3bab1fSbouyer #include <dev/scsipi/atapiconf.h>
42d7d845c3Senami 
436f3bab1fSbouyer #include "locators.h"
446f3bab1fSbouyer 
456f3bab1fSbouyer #define SILENT_PRINTF(flags,string) if (!(flags & A_SILENT)) printf string
4667e874d8Senami #define MAX_TARGET 1
476f3bab1fSbouyer 
48937a7a3eSbouyer const struct scsipi_periphsw atapi_probe_periphsw = {
49937a7a3eSbouyer 	NULL,
50937a7a3eSbouyer 	NULL,
51937a7a3eSbouyer 	NULL,
52937a7a3eSbouyer 	NULL,
53937a7a3eSbouyer };
54937a7a3eSbouyer 
55b1be269fScube static int	atapibusmatch(device_t, cfdata_t, void *);
56534869a2Sdyoung static void	atapibusattach(device_t, device_t, void *);
57534869a2Sdyoung static int	atapibusdetach(device_t, int flags);
58534869a2Sdyoung static void	atapibuschilddet(device_t, device_t);
5967e874d8Senami 
60b1be269fScube static int	atapibussubmatch(device_t, cfdata_t, const int *, void *);
61937a7a3eSbouyer 
626cb9b748Sthorpej static int	atapi_probe_bus(struct atapibus_softc *, int);
636cb9b748Sthorpej 
646cb9b748Sthorpej static int	atapibusprint(void *, const char *);
656f3bab1fSbouyer 
663098a4fbSdyoung CFATTACH_DECL3_NEW(atapibus, sizeof(struct atapibus_softc),
67acb06354Sdyoung     atapibusmatch, atapibusattach, atapibusdetach, NULL, NULL,
683098a4fbSdyoung     atapibuschilddet, DVF_DETACH_SHUTDOWN);
696f3bab1fSbouyer 
7093f26b5fSthorpej extern struct cfdriver atapibus_cd;
716f3bab1fSbouyer 
726cb9b748Sthorpej static const struct scsi_quirk_inquiry_pattern atapi_quirk_patterns[] = {
736f3bab1fSbouyer 	{{T_CDROM, T_REMOV,
74937a7a3eSbouyer 	 "ALPS ELECTRIC CO.,LTD. DC544C", "", "SW03D"},	PQUIRK_NOTUR},
75d8f58a35Sbouyer 	{{T_CDROM, T_REMOV,
76937a7a3eSbouyer 	 "CR-2801TE", "", "1.07"},		PQUIRK_NOSENSE},
77d86a570eSbouyer 	{{T_CDROM, T_REMOV,
78937a7a3eSbouyer 	 "CREATIVECD3630E", "", "AC101"},	PQUIRK_NOSENSE},
79cafe97daSbouyer 	{{T_CDROM, T_REMOV,
80937a7a3eSbouyer 	 "FX320S", "", "q01"},			PQUIRK_NOSENSE},
81d8f58a35Sbouyer 	{{T_CDROM, T_REMOV,
82937a7a3eSbouyer 	 "GCD-R580B", "", "1.00"},		PQUIRK_LITTLETOC},
83d8f58a35Sbouyer 	{{T_CDROM, T_REMOV,
84937a7a3eSbouyer 	 "HITACHI CDR-7730", "", "0008a"},      PQUIRK_NOSENSE},
8586ae2ab1Sjdolecek 	{{T_CDROM, T_REMOV,
86937a7a3eSbouyer 	 "MATSHITA CR-574", "", "1.02"},	PQUIRK_NOCAPACITY},
87d8f58a35Sbouyer 	{{T_CDROM, T_REMOV,
88937a7a3eSbouyer 	 "MATSHITA CR-574", "", "1.06"},	PQUIRK_NOCAPACITY},
89d8f58a35Sbouyer 	{{T_CDROM, T_REMOV,
90937a7a3eSbouyer 	 "Memorex CRW-2642", "", "1.0g"},	PQUIRK_NOSENSE},
91d8f58a35Sbouyer 	{{T_CDROM, T_REMOV,
92937a7a3eSbouyer 	 "NEC                 CD-ROM DRIVE:273", "", "4.21"}, PQUIRK_NOTUR},
936f3bab1fSbouyer 	{{T_CDROM, T_REMOV,
94937a7a3eSbouyer 	 "SANYO CRD-256P", "", "1.02"},		PQUIRK_NOCAPACITY},
956f3bab1fSbouyer 	{{T_CDROM, T_REMOV,
96937a7a3eSbouyer 	 "SANYO CRD-254P", "", "1.02"},		PQUIRK_NOCAPACITY},
9787219fa0Sbouyer 	{{T_CDROM, T_REMOV,
98937a7a3eSbouyer 	 "SANYO CRD-S54P", "", "1.08"},		PQUIRK_NOCAPACITY},
995e5babfbSbouyer 	{{T_CDROM, T_REMOV,
100937a7a3eSbouyer 	 "CD-ROM  CDR-S1", "", "1.70"},		PQUIRK_NOCAPACITY}, /* Sanyo */
101d8d77f77Sbouyer 	{{T_CDROM, T_REMOV,
102937a7a3eSbouyer 	 "CD-ROM  CDR-N16", "", "1.25"},	PQUIRK_NOCAPACITY}, /* Sanyo */
1036f3bab1fSbouyer };
1046f3bab1fSbouyer 
1056f3bab1fSbouyer int
atapiprint(void * aux,const char * pnp)106168cd830Schristos atapiprint(void *aux, const char *pnp)
1074809ad42Sbouyer {
1084809ad42Sbouyer 	if (pnp)
10972a7af27Sthorpej 		aprint_normal("atapibus at %s", pnp);
1104809ad42Sbouyer 	return (UNCONF);
1114809ad42Sbouyer }
1124809ad42Sbouyer 
1136cb9b748Sthorpej static int
atapibusmatch(device_t parent,cfdata_t cf,void * aux)114b1be269fScube atapibusmatch(device_t parent, cfdata_t cf, void *aux)
1156f3bab1fSbouyer {
1164809ad42Sbouyer 	struct scsipi_channel *chan = aux;
1176f3bab1fSbouyer 
1184809ad42Sbouyer 	if (chan == NULL)
119d7d845c3Senami 		return (0);
120937a7a3eSbouyer 
12163d14cffSbouyer 	if (SCSIPI_BUSTYPE_TYPE(chan->chan_bustype->bustype_type) !=
12263d14cffSbouyer 	    SCSIPI_BUSTYPE_ATAPI)
123d7d845c3Senami 		return (0);
124937a7a3eSbouyer 
125d7d845c3Senami 	return (1);
1266f3bab1fSbouyer }
1276f3bab1fSbouyer 
1286cb9b748Sthorpej static int
atapibussubmatch(device_t parent,cfdata_t cf,const int * ldesc,void * aux)129b1be269fScube atapibussubmatch(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
1306f3bab1fSbouyer {
1316f3bab1fSbouyer 	struct scsipibus_attach_args *sa = aux;
132937a7a3eSbouyer 	struct scsipi_periph *periph = sa->sa_periph;
1336f3bab1fSbouyer 
1346f3bab1fSbouyer 	if (cf->cf_loc[ATAPIBUSCF_DRIVE] != ATAPIBUSCF_DRIVE_DEFAULT &&
135937a7a3eSbouyer 	    cf->cf_loc[ATAPIBUSCF_DRIVE] != periph->periph_target)
136d7d845c3Senami 		return (0);
1376c88de3bSthorpej 	return (config_match(parent, cf, aux));
1386f3bab1fSbouyer }
1396f3bab1fSbouyer 
1406cb9b748Sthorpej static void
atapibusattach(device_t parent,device_t self,void * aux)141534869a2Sdyoung atapibusattach(device_t parent, device_t self, void *aux)
1426f3bab1fSbouyer {
14307c30f82Sthorpej 	struct atapibus_softc *sc = device_private(self);
1444809ad42Sbouyer 	struct scsipi_channel *chan = aux;
1456f3bab1fSbouyer 
146937a7a3eSbouyer 	sc->sc_channel = chan;
147b1be269fScube 	sc->sc_dev = self;
1486f3bab1fSbouyer 
149b1be269fScube 	chan->chan_name = device_xname(sc->sc_dev);
1503c54deadSmlelstv 	chan->chan_id = -1;
1514940346bSbouyer 
152937a7a3eSbouyer 	/* ATAPI has no LUNs. */
153937a7a3eSbouyer 	chan->chan_nluns = 1;
154b276edd8Sjmcneill 	aprint_naive("\n");
155b276edd8Sjmcneill 	aprint_normal(": %d targets\n", chan->chan_ntargets);
15603ffe0a5Sthorpej 
157a6a95dd6Smlelstv 	if (atomic_inc_uint_nv(&chan_running(chan)) == 1)
158a6a95dd6Smlelstv 		mutex_init(chan_mtx(chan), MUTEX_DEFAULT, IPL_BIO);
159a6a95dd6Smlelstv 
160b6a6db8fSmlelstv 	cv_init(&chan->chan_cv_thr, "scshut");
161b6a6db8fSmlelstv 	cv_init(&chan->chan_cv_comp, "sccomp");
162b6a6db8fSmlelstv 	cv_init(&chan->chan_cv_xs, "xscmd");
163b6a6db8fSmlelstv 
164937a7a3eSbouyer 	/* Initialize the channel. */
165c7258354Sjmc 	chan->chan_init_cb = NULL;
166c7258354Sjmc 	chan->chan_init_cb_arg = NULL;
167937a7a3eSbouyer 	scsipi_channel_init(chan);
16819fddaeeSbouyer 
1694c1d81b2Sjmcneill 	if (!pmf_device_register(self, NULL, NULL))
1704c1d81b2Sjmcneill 		aprint_error_dev(self, "couldn't establish power handler\n");
1714c1d81b2Sjmcneill 
172937a7a3eSbouyer 	/* Probe the bus for devices. */
173937a7a3eSbouyer 	atapi_probe_bus(sc, -1);
1746f3bab1fSbouyer }
1756f3bab1fSbouyer 
176534869a2Sdyoung static void
atapibuschilddet(device_t self,device_t child)177534869a2Sdyoung atapibuschilddet(device_t self, device_t child)
178534869a2Sdyoung {
179534869a2Sdyoung 	struct atapibus_softc *sc = device_private(self);
180534869a2Sdyoung 	struct scsipi_channel *chan = sc->sc_channel;
181534869a2Sdyoung 	struct scsipi_periph *periph;
182534869a2Sdyoung 	int target;
183534869a2Sdyoung 
184b6a6db8fSmlelstv 	mutex_enter(chan_mtx(chan));
185534869a2Sdyoung 	for (target = 0; target < chan->chan_ntargets; target++) {
186b6a6db8fSmlelstv 		periph = scsipi_lookup_periph_locked(chan, target, 0);
187534869a2Sdyoung 		if (periph == NULL || periph->periph_dev != child)
188534869a2Sdyoung 			continue;
189534869a2Sdyoung 		scsipi_remove_periph(chan, periph);
190b6a6db8fSmlelstv 		scsipi_free_periph(periph);
191534869a2Sdyoung 		break;
192534869a2Sdyoung 	}
193b6a6db8fSmlelstv 	mutex_exit(chan_mtx(chan));
194534869a2Sdyoung }
195534869a2Sdyoung 
1963c54deadSmlelstv /* same as scsibusdetach */
1976cb9b748Sthorpej static int
atapibusdetach(device_t self,int flags)198534869a2Sdyoung atapibusdetach(device_t self, int flags)
19967e874d8Senami {
20007c30f82Sthorpej 	struct atapibus_softc *sc = device_private(self);
201937a7a3eSbouyer 	struct scsipi_channel *chan = sc->sc_channel;
2023c54deadSmlelstv 	int error = 0;
2033c54deadSmlelstv 
2043c54deadSmlelstv 	/*
2053c54deadSmlelstv 	 * Detach all of the periphs.
2063c54deadSmlelstv 	 */
2073c54deadSmlelstv 	error = scsipi_target_detach(chan, -1, -1, flags);
2083c54deadSmlelstv 	if (error)
2093c54deadSmlelstv 		return error;
2103c54deadSmlelstv 
2113c54deadSmlelstv 	pmf_device_deregister(self);
21267e874d8Senami 
213937a7a3eSbouyer 	/*
214937a7a3eSbouyer 	 * Shut down the channel.
215937a7a3eSbouyer 	 */
216937a7a3eSbouyer 	scsipi_channel_shutdown(chan);
217937a7a3eSbouyer 
218b6a6db8fSmlelstv 	cv_destroy(&chan->chan_cv_xs);
219b6a6db8fSmlelstv 	cv_destroy(&chan->chan_cv_comp);
220b6a6db8fSmlelstv 	cv_destroy(&chan->chan_cv_thr);
221a6a95dd6Smlelstv 
222*ef3476fbSriastradh 	membar_release();
223122a3e8aSriastradh 	if (atomic_dec_uint_nv(&chan_running(chan)) == 0) {
224*ef3476fbSriastradh 		membar_acquire();
225b6a6db8fSmlelstv 		mutex_destroy(chan_mtx(chan));
226122a3e8aSriastradh 	}
227b6a6db8fSmlelstv 
2283c54deadSmlelstv 	return 0;
22967e874d8Senami }
23067e874d8Senami 
2316cb9b748Sthorpej static int
atapi_probe_bus(struct atapibus_softc * sc,int target)2326cb9b748Sthorpej atapi_probe_bus(struct atapibus_softc *sc, int target)
2336f3bab1fSbouyer {
234937a7a3eSbouyer 	struct scsipi_channel *chan = sc->sc_channel;
2356f3bab1fSbouyer 	int maxtarget, mintarget;
23654b52fb5Sthorpej 	int error;
23726f6c9a9Sbouyer 	struct atapi_adapter *atapi_adapter;
238d7d845c3Senami 
239842c96bdSskrll 	KASSERT(chan->chan_ntargets >= 1);
240842c96bdSskrll 
2416f3bab1fSbouyer 	if (target == -1) {
242842c96bdSskrll 		maxtarget = chan->chan_ntargets - 1;
2436f3bab1fSbouyer 		mintarget = 0;
2446f3bab1fSbouyer 	} else {
245937a7a3eSbouyer 		if (target < 0 || target >= chan->chan_ntargets)
246d7d845c3Senami 			return (ENXIO);
2476f3bab1fSbouyer 		maxtarget = mintarget = target;
2486f3bab1fSbouyer 	}
249937a7a3eSbouyer 
250937a7a3eSbouyer 	if ((error = scsipi_adapter_addref(chan->chan_adapter)) != 0)
25154b52fb5Sthorpej 		return (error);
252937a7a3eSbouyer 	atapi_adapter = (struct atapi_adapter*)chan->chan_adapter;
253d7d845c3Senami 	for (target = mintarget; target <= maxtarget; target++)
254937a7a3eSbouyer 		atapi_adapter->atapi_probe_device(sc, target);
255937a7a3eSbouyer 	scsipi_adapter_delref(chan->chan_adapter);
256d7d845c3Senami 	return (0);
2576f3bab1fSbouyer }
2586f3bab1fSbouyer 
25926f6c9a9Sbouyer void *
atapi_probe_device(struct atapibus_softc * sc,int target,struct scsipi_periph * periph,struct scsipibus_attach_args * sa)260168cd830Schristos atapi_probe_device(struct atapibus_softc *sc, int target,
2616cb9b748Sthorpej     struct scsipi_periph *periph, struct scsipibus_attach_args *sa)
26226f6c9a9Sbouyer {
263937a7a3eSbouyer 	struct scsipi_channel *chan = sc->sc_channel;
2643acb3fe6Schristos 	const struct scsi_quirk_inquiry_pattern *finger;
265d16a259fScegger 	cfdata_t cf;
266937a7a3eSbouyer 	int priority, quirks;
2676f3bab1fSbouyer 
2683acb3fe6Schristos 	finger = scsipi_inqmatch(
2693acb3fe6Schristos 	    &sa->sa_inqbuf, (const void *)atapi_quirk_patterns,
2706f3bab1fSbouyer 	    sizeof(atapi_quirk_patterns) /
2716f3bab1fSbouyer 	        sizeof(atapi_quirk_patterns[0]),
2726f3bab1fSbouyer 	    sizeof(atapi_quirk_patterns[0]), &priority);
2736f3bab1fSbouyer 
274937a7a3eSbouyer 	if (finger != NULL)
275937a7a3eSbouyer 		quirks = finger->quirks;
276937a7a3eSbouyer 	else
277937a7a3eSbouyer 		quirks = 0;
278937a7a3eSbouyer 
279937a7a3eSbouyer 	/*
280937a7a3eSbouyer 	 * Now apply any quirks from the table.
281937a7a3eSbouyer 	 */
282937a7a3eSbouyer 	periph->periph_quirks |= quirks;
283937a7a3eSbouyer 
2842685996bSthorpej 	if ((cf = config_search(sc->sc_dev, sa,
285c7fb772bSthorpej 				CFARGS(.submatch =
286c7fb772bSthorpej 				           atapibussubmatch))) != NULL) {
287937a7a3eSbouyer 		scsipi_insert_periph(chan, periph);
288937a7a3eSbouyer 		/*
289937a7a3eSbouyer 		 * XXX Can't assign periph_dev here, because we'll
290937a7a3eSbouyer 		 * XXX need it before config_attach() returns.  Must
291937a7a3eSbouyer 		 * XXX assign it in periph driver.
292937a7a3eSbouyer 		 */
2932685996bSthorpej 		return config_attach(sc->sc_dev, cf, sa, atapibusprint,
294c7fb772bSthorpej 		    CFARGS_NONE);
2956f3bab1fSbouyer 	} else {
296b1be269fScube 		atapibusprint(sa, device_xname(sc->sc_dev));
297235f037fStsutsui 		aprint_normal(" not configured\n");
298b6a6db8fSmlelstv 		scsipi_free_periph(periph);
299937a7a3eSbouyer 		return NULL;
3006f3bab1fSbouyer 	}
3016f3bab1fSbouyer }
3026f3bab1fSbouyer 
3036cb9b748Sthorpej static int
atapibusprint(void * aux,const char * pnp)3046cb9b748Sthorpej atapibusprint(void *aux, const char *pnp)
3056f3bab1fSbouyer {
3066f3bab1fSbouyer 	struct scsipibus_attach_args *sa = aux;
3076f3bab1fSbouyer 	struct scsipi_inquiry_pattern *inqbuf;
308cb3eb355Sthorpej 	const char *dtype;
3096f3bab1fSbouyer 
3106f3bab1fSbouyer 	if (pnp != NULL)
31172a7af27Sthorpej 		aprint_normal("%s", pnp);
3126f3bab1fSbouyer 
3136f3bab1fSbouyer 	inqbuf = &sa->sa_inqbuf;
3146f3bab1fSbouyer 
3156f3bab1fSbouyer 	dtype = scsipi_dtype(inqbuf->type & SID_TYPE);
31672a7af27Sthorpej 	aprint_normal(" drive %d: <%s, %s, %s> %s %s",
317937a7a3eSbouyer 	    sa->sa_periph->periph_target, inqbuf->vendor,
31898ec436dSsoren 	    inqbuf->product, inqbuf->revision, dtype,
3196f3bab1fSbouyer 	    inqbuf->removable ? "removable" : "fixed");
3206f3bab1fSbouyer 	return (UNCONF);
3216f3bab1fSbouyer }
322