atapiconf.c revision 1.28.2.2 1 /* $NetBSD: atapiconf.c,v 1.28.2.2 1999/10/20 10:14:54 enami Exp $ */
2
3 /*
4 * Copyright (c) 1996 Manuel Bouyer. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Manuel Bouyer.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/malloc.h>
36 #include <sys/device.h>
37 #include <sys/buf.h>
38 #include <sys/proc.h>
39 #include <sys/kthread.h>
40
41 #include <dev/ata/atareg.h>
42 #include <dev/ata/atavar.h>
43 #include <dev/scsipi/scsipi_all.h>
44 #include <dev/scsipi/atapi_all.h>
45 #include <dev/scsipi/scsipiconf.h>
46 #include <dev/scsipi/atapiconf.h>
47
48 #include "locators.h"
49
50 #define SILENT_PRINTF(flags,string) if (!(flags & A_SILENT)) printf string
51 #define MAX_TARGET 1
52
53 const struct scsipi_periphsw atapi_probe_periphsw = {
54 NULL,
55 NULL,
56 NULL,
57 NULL,
58 };
59
60 struct atapibus_softc {
61 struct device sc_dev;
62 struct scsipi_channel *sc_channel; /* our scsipi_channel */
63 struct ata_drive_datas *sc_drvs; /* array supplied by adapter */
64 };
65
66 int atapibusmatch __P((struct device *, struct cfdata *, void *));
67 void atapibusattach __P((struct device *, struct device *, void *));
68 int atapibusactivate __P((struct device *, enum devact));
69 int atapibusdetach __P((struct device *, int flags));
70
71 int atapibussubmatch __P((struct device *, struct cfdata *, void *));
72
73 int atapiprint __P((void *, const char *));
74
75 int atapi_probe_bus __P((struct atapibus_softc *, int));
76 void atapi_probe_device __P((struct atapibus_softc *, int ));
77
78 struct cfattach atapibus_ca = {
79 sizeof(struct atapibus_softc), atapibusmatch, atapibusattach,
80 atapibusdetach, atapibusactivate,
81 };
82
83 extern struct cfdriver atapibus_cd;
84
85 int atapibusprint __P((void *, const char *));
86
87 const struct scsipi_bustype atapi_bustype = {
88 SCSIPI_BUSTYPE_ATAPI,
89 atapi_scsipi_cmd,
90 atapi_interpret_sense,
91 atapi_print_addr,
92 };
93
94 struct scsi_quirk_inquiry_pattern atapi_quirk_patterns[] = {
95 {{T_CDROM, T_REMOV,
96 "ALPS ELECTRIC CO.,LTD. DC544C", "", "SW03D"}, PQUIRK_NOTUR},
97 {{T_CDROM, T_REMOV,
98 "BCD-16X 1997-04-25", "", "VER 2.2"}, PQUIRK_NOSTARTUNIT},
99 {{T_CDROM, T_REMOV,
100 "BCD-24X 1997-06-27", "", "VER 2.0"}, PQUIRK_NOSTARTUNIT},
101 {{T_CDROM, T_REMOV,
102 "CR-2801TE", "", "1.07"}, PQUIRK_NOSENSE},
103 {{T_CDROM, T_REMOV,
104 "CREATIVECD3630E", "", "AC101"}, PQUIRK_NOSENSE},
105 {{T_CDROM, T_REMOV,
106 "FX320S", "", "q01"}, PQUIRK_NOSENSE},
107 {{T_CDROM, T_REMOV,
108 "GCD-R580B", "", "1.00"}, PQUIRK_LITTLETOC},
109 {{T_CDROM, T_REMOV,
110 "MATSHITA CR-574", "", "1.02"}, PQUIRK_NOCAPACITY},
111 {{T_CDROM, T_REMOV,
112 "MATSHITA CR-574", "", "1.06"}, PQUIRK_NOCAPACITY},
113 {{T_CDROM, T_REMOV,
114 "Memorex CRW-2642", "", "1.0g"}, PQUIRK_NOSENSE},
115 {{T_CDROM, T_REMOV,
116 "NEC CD-ROM DRIVE:273", "", "4.21"}, PQUIRK_NOTUR},
117 {{T_CDROM, T_REMOV,
118 "SANYO CRD-256P", "", "1.02"}, PQUIRK_NOCAPACITY},
119 {{T_CDROM, T_REMOV,
120 "SANYO CRD-254P", "", "1.02"}, PQUIRK_NOCAPACITY},
121 {{T_CDROM, T_REMOV,
122 "SANYO CRD-S54P", "", "1.08"}, PQUIRK_NOCAPACITY},
123 {{T_CDROM, T_REMOV,
124 "CD-ROM CDR-S1", "", "1.70"}, PQUIRK_NOCAPACITY}, /* Sanyo */
125 {{T_CDROM, T_REMOV,
126 "CD-ROM CDR-N16", "", "1.25"}, PQUIRK_NOCAPACITY}, /* Sanyo */
127 {{T_CDROM, T_REMOV,
128 "UJDCD8730", "", "1.14"}, PQUIRK_NODOORLOCK}, /* Acer */
129 };
130
131 int
132 atapibusmatch(parent, cf, aux)
133 struct device *parent;
134 struct cfdata *cf;
135 void *aux;
136 {
137 struct ata_atapi_attach *aa = aux;
138
139 if (aa == NULL)
140 return (0);
141
142 if (aa->aa_type != T_ATAPI)
143 return (0);
144
145 if (cf->cf_loc[ATAPICF_CHANNEL] != aa->aa_channel &&
146 cf->cf_loc[ATAPICF_CHANNEL] != ATAPICF_CHANNEL_DEFAULT)
147 return (0);
148
149 return (1);
150 }
151
152 int
153 atapibussubmatch(parent, cf, aux)
154 struct device *parent;
155 struct cfdata *cf;
156 void *aux;
157 {
158 struct scsipibus_attach_args *sa = aux;
159 struct scsipi_periph *periph = sa->sa_periph;
160
161 if (cf->cf_loc[ATAPIBUSCF_DRIVE] != ATAPIBUSCF_DRIVE_DEFAULT &&
162 cf->cf_loc[ATAPIBUSCF_DRIVE] != periph->periph_target)
163 return (0);
164 return ((*cf->cf_attach->ca_match)(parent, cf, aux));
165 }
166
167 #if 0
168 void
169 atapi_fixquirk(sc_link)
170 struct scsipi_link *ad_link;
171 {
172 struct ataparams *id = &ad_link->id;
173 struct atapi_quirk_inquiry_pattern *quirk;
174
175 /*
176 * Clean up the model name, serial and revision numbers.
177 */
178 btrim(id->model, sizeof(id->model));
179 btrim(id->serial_number, sizeof(id->serial_number));
180 btrim(id->firmware_revision, sizeof(id->firmware_revision));
181 }
182 #endif
183
184 void
185 atapibusattach(parent, self, aux)
186 struct device *parent, *self;
187 void *aux;
188 {
189 struct atapibus_softc *sc = (void *) self;
190 struct ata_atapi_attach *aa = aux;
191 struct scsipi_channel *chan = aa->aa_bus_private;
192
193 sc->sc_channel = chan;
194 sc->sc_drvs = aa->aa_drv_data;
195
196 /* ATAPI has no LUNs. */
197 chan->chan_nluns = 1;
198 printf(": %d targets\n", chan->chan_ntargets);
199
200 /* Initialize the channel. */
201 scsipi_channel_init(chan);
202
203 /* Probe the bus for devices. */
204 atapi_probe_bus(sc, -1);
205 }
206
207 int
208 atapibusactivate(self, act)
209 struct device *self;
210 enum devact act;
211 {
212 struct atapibus_softc *sc = (void *) self;
213 struct scsipi_channel *chan = sc->sc_channel;
214 struct scsipi_periph *periph;
215 int target, error = 0, s;
216
217 s = splbio();
218 switch (act) {
219 case DVACT_ACTIVATE:
220 error = EOPNOTSUPP;
221 break;
222
223 case DVACT_DEACTIVATE:
224 for (target = 0; target < chan->chan_ntargets; target++) {
225 periph = chan->chan_periphs[target][0];
226 if (periph == NULL)
227 continue;
228 error = config_deactivate(periph->periph_dev);
229 if (error)
230 goto out;
231 }
232 break;
233 }
234 out:
235 splx(s);
236 return (error);
237 }
238
239 int
240 atapibusdetach(self, flags)
241 struct device *self;
242 int flags;
243 {
244 struct atapibus_softc *sc = (void *)self;
245 struct scsipi_channel *chan = sc->sc_channel;
246 struct scsipi_periph *periph;
247 int target, error;
248
249 for (target = 0; target < chan->chan_ntargets; target++) {
250 periph = chan->chan_periphs[target][0];
251 if (periph == NULL)
252 continue;
253 error = config_detach(periph->periph_dev, flags);
254 if (error)
255 return (error);
256
257 /*
258 * We have successfully detached the child. Drop the
259 * direct reference for the child so that wdcdetach
260 * won't call detach routine twice.
261 */
262 #ifdef DIAGNOSTIC
263 if (periph->periph_dev != sc->sc_drvs[target].drv_softc)
264 panic("softc mismatch");
265 #endif
266 sc->sc_drvs[target].drv_softc = NULL;
267
268 free(periph, M_DEVBUF);
269 chan->chan_periphs[target][0] = NULL;
270 }
271 return (0);
272 }
273
274 int
275 atapi_probe_bus(sc, target)
276 struct atapibus_softc *sc;
277 int target;
278 {
279 struct scsipi_channel *chan = sc->sc_channel;
280 int maxtarget, mintarget;
281 int error;
282
283 if (target == -1) {
284 maxtarget = 1;
285 mintarget = 0;
286 } else {
287 if (target < 0 || target >= chan->chan_ntargets)
288 return (ENXIO);
289 maxtarget = mintarget = target;
290 }
291
292 if ((error = scsipi_adapter_addref(chan->chan_adapter)) != 0)
293 return (error);
294 for (target = mintarget; target <= maxtarget; target++)
295 atapi_probe_device(sc, target);
296 scsipi_adapter_delref(chan->chan_adapter);
297 return (0);
298 }
299
300 void
301 atapi_probe_device(sc, target)
302 struct atapibus_softc *sc;
303 int target;
304 {
305 struct scsipi_channel *chan = sc->sc_channel;
306 struct scsipi_periph *periph;
307 struct ataparams ids;
308 struct ataparams *id = &ids;
309 struct ata_drive_datas *drvp = &sc->sc_drvs[target];
310 struct scsi_quirk_inquiry_pattern *finger;
311 struct scsipibus_attach_args sa;
312 struct cfdata *cf;
313 int priority, quirks;
314 char serial_number[21], model[41], firmware_revision[9];
315
316 /* skip if already attached */
317 if (chan->chan_periphs[target][0] != NULL)
318 return;
319
320 if (wdc_atapi_get_params(chan, target,
321 XS_CTL_POLL|XS_CTL_NOSLEEP, id) == 0) {
322 #ifdef ATAPI_DEBUG_PROBE
323 printf("%s drive %d: cmdsz 0x%x drqtype 0x%x\n",
324 sc->sc_dev.dv_xname, target,
325 id->atap_config & ATAPI_CFG_CMD_MASK,
326 id->atap_config & ATAPI_CFG_DRQ_MASK);
327 #endif
328 periph = malloc(sizeof(*periph), M_DEVBUF, M_NOWAIT);
329 if (periph == NULL) {
330 printf("%s: unable to allocate periph for drive %d\n",
331 sc->sc_dev.dv_xname, target);
332 return;
333 }
334 memset(periph, 0, sizeof(*periph));
335
336 periph->periph_dev = NULL;
337 periph->periph_channel = chan;
338 periph->periph_switch = &atapi_probe_periphsw;
339
340 /*
341 * Start with one command opening. The periph
342 * driver will grow this if it knows it can
343 * take advantage of it.
344 */
345 periph->periph_openings = 1;
346 periph->periph_active = 0;
347
348 periph->periph_target = target;
349 periph->periph_lun = 0;
350
351 TAILQ_INIT(&periph->periph_xferq);
352
353 #if defined(SCSIDEBUG) && DEBUGTYPE == BUS_ATAPI
354 if (DEBUGTARGET == -1 || target == DEBUGTARGET)
355 sc_link->flags |= DEBUGLEVEL;
356 #endif /* SCSIDEBUG */
357
358 periph->periph_type = ATAPI_CFG_TYPE(id->atap_config);
359 if (id->atap_config & ATAPI_CFG_REMOV)
360 periph->periph_flags |= PERIPH_REMOVABLE;
361
362 sa.sa_periph = periph;
363 sa.sa_inqbuf.type = ATAPI_CFG_TYPE(id->atap_config);
364 sa.sa_inqbuf.removable = id->atap_config & ATAPI_CFG_REMOV ?
365 T_REMOV : T_FIXED;
366 scsipi_strvis(model, 40, id->atap_model, 40);
367 scsipi_strvis(serial_number, 20, id->atap_serial, 20);
368 scsipi_strvis(firmware_revision, 8, id->atap_revision, 8);
369 sa.sa_inqbuf.vendor = model;
370 sa.sa_inqbuf.product = serial_number;
371 sa.sa_inqbuf.revision = firmware_revision;
372
373 finger = (struct scsi_quirk_inquiry_pattern *)scsipi_inqmatch(
374 &sa.sa_inqbuf, (caddr_t)atapi_quirk_patterns,
375 sizeof(atapi_quirk_patterns) /
376 sizeof(atapi_quirk_patterns[0]),
377 sizeof(atapi_quirk_patterns[0]), &priority);
378
379 if (finger != NULL)
380 quirks = finger->quirks;
381 else
382 quirks = 0;
383
384 /*
385 * Determine the operating mode capabilities of the device.
386 */
387 if ((id->atap_config & ATAPI_CFG_CMD_MASK) == ATAPI_CFG_CMD_16)
388 periph->periph_cap |= PERIPH_CAP_CMD16;
389 /* XXX This is gross. */
390 periph->periph_cap |= (id->atap_config & ATAPI_CFG_DRQ_MASK);
391
392 /*
393 * Now apply any quirks from the table.
394 */
395 periph->periph_quirks |= quirks;
396
397 if ((cf = config_search(atapibussubmatch, &sc->sc_dev,
398 &sa)) != 0) {
399 chan->chan_periphs[target][0] = periph;
400 /*
401 * XXX Can't assign periph_dev here, because we'll
402 * XXX need it before config_attach() returns. Must
403 * XXX assign it in periph driver.
404 */
405 drvp->drv_softc = config_attach(&sc->sc_dev, cf, &sa,
406 atapibusprint);
407 wdc_probe_caps(drvp);
408 return;
409 } else {
410 atapibusprint(&sa, sc->sc_dev.dv_xname);
411 printf(" not configured\n");
412 free(periph, M_DEVBUF);
413 return;
414 }
415 }
416 }
417
418 int
419 atapibusprint(aux, pnp)
420 void *aux;
421 const char *pnp;
422 {
423 struct scsipibus_attach_args *sa = aux;
424 struct scsipi_inquiry_pattern *inqbuf;
425 char *dtype;
426
427 if (pnp != NULL)
428 printf("%s", pnp);
429
430 inqbuf = &sa->sa_inqbuf;
431
432 dtype = scsipi_dtype(inqbuf->type & SID_TYPE);
433 printf(" drive %d: <%s, %s, %s> type %d %s %s",
434 sa->sa_periph->periph_target ,inqbuf->vendor,
435 inqbuf->product, inqbuf->revision, inqbuf->type, dtype,
436 inqbuf->removable ? "removable" : "fixed");
437 return (UNCONF);
438 }
439