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