atapiconf.c revision 1.28.2.5 1 /* $NetBSD: atapiconf.c,v 1.28.2.5 2000/02/04 23:01:54 thorpej 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 atapi_kill_pending,
93 };
94
95 struct scsi_quirk_inquiry_pattern atapi_quirk_patterns[] = {
96 {{T_CDROM, T_REMOV,
97 "ALPS ELECTRIC CO.,LTD. DC544C", "", "SW03D"}, PQUIRK_NOTUR},
98 {{T_CDROM, T_REMOV,
99 "BCD-16X 1997-04-25", "", "VER 2.2"}, PQUIRK_NOSTARTUNIT},
100 {{T_CDROM, T_REMOV,
101 "BCD-24X 1997-06-27", "", "VER 2.0"}, PQUIRK_NOSTARTUNIT},
102 {{T_CDROM, T_REMOV,
103 "CR-2801TE", "", "1.07"}, PQUIRK_NOSENSE},
104 {{T_CDROM, T_REMOV,
105 "CREATIVECD3630E", "", "AC101"}, PQUIRK_NOSENSE},
106 {{T_CDROM, T_REMOV,
107 "FX320S", "", "q01"}, PQUIRK_NOSENSE},
108 {{T_CDROM, T_REMOV,
109 "GCD-R580B", "", "1.00"}, PQUIRK_LITTLETOC},
110 {{T_CDROM, T_REMOV,
111 "MATSHITA CR-574", "", "1.02"}, PQUIRK_NOCAPACITY},
112 {{T_CDROM, T_REMOV,
113 "MATSHITA CR-574", "", "1.06"}, PQUIRK_NOCAPACITY},
114 {{T_CDROM, T_REMOV,
115 "Memorex CRW-2642", "", "1.0g"}, PQUIRK_NOSENSE},
116 {{T_CDROM, T_REMOV,
117 "NEC CD-ROM DRIVE:273", "", "4.21"}, PQUIRK_NOTUR},
118 {{T_CDROM, T_REMOV,
119 "SANYO CRD-256P", "", "1.02"}, PQUIRK_NOCAPACITY},
120 {{T_CDROM, T_REMOV,
121 "SANYO CRD-254P", "", "1.02"}, PQUIRK_NOCAPACITY},
122 {{T_CDROM, T_REMOV,
123 "SANYO CRD-S54P", "", "1.08"}, PQUIRK_NOCAPACITY},
124 {{T_CDROM, T_REMOV,
125 "CD-ROM CDR-S1", "", "1.70"}, PQUIRK_NOCAPACITY}, /* Sanyo */
126 {{T_CDROM, T_REMOV,
127 "CD-ROM CDR-N16", "", "1.25"}, PQUIRK_NOCAPACITY}, /* Sanyo */
128 {{T_CDROM, T_REMOV,
129 "UJDCD8730", "", "1.14"}, PQUIRK_NODOORLOCK}, /* Acer */
130 };
131
132 int
133 atapibusmatch(parent, cf, aux)
134 struct device *parent;
135 struct cfdata *cf;
136 void *aux;
137 {
138 struct ata_atapi_attach *aa = aux;
139
140 if (aa == NULL)
141 return (0);
142
143 if (aa->aa_type != T_ATAPI)
144 return (0);
145
146 if (cf->cf_loc[ATAPICF_CHANNEL] != aa->aa_channel &&
147 cf->cf_loc[ATAPICF_CHANNEL] != ATAPICF_CHANNEL_DEFAULT)
148 return (0);
149
150 return (1);
151 }
152
153 int
154 atapibussubmatch(parent, cf, aux)
155 struct device *parent;
156 struct cfdata *cf;
157 void *aux;
158 {
159 struct scsipibus_attach_args *sa = aux;
160 struct scsipi_periph *periph = sa->sa_periph;
161
162 if (cf->cf_loc[ATAPIBUSCF_DRIVE] != ATAPIBUSCF_DRIVE_DEFAULT &&
163 cf->cf_loc[ATAPIBUSCF_DRIVE] != periph->periph_target)
164 return (0);
165 return ((*cf->cf_attach->ca_match)(parent, cf, aux));
166 }
167
168 #if 0
169 void
170 atapi_fixquirk(periph)
171 struct scsipi_link *ad_link;
172 {
173 struct ataparams *id = &ad_link->id;
174 struct atapi_quirk_inquiry_pattern *quirk;
175
176 /*
177 * Clean up the model name, serial and revision numbers.
178 */
179 btrim(id->model, sizeof(id->model));
180 btrim(id->serial_number, sizeof(id->serial_number));
181 btrim(id->firmware_revision, sizeof(id->firmware_revision));
182 }
183 #endif
184
185 void
186 atapibusattach(parent, self, aux)
187 struct device *parent, *self;
188 void *aux;
189 {
190 struct atapibus_softc *sc = (void *) self;
191 struct ata_atapi_attach *aa = aux;
192 struct scsipi_channel *chan = aa->aa_bus_private;
193
194 sc->sc_channel = chan;
195 sc->sc_drvs = aa->aa_drv_data;
196
197 /* ATAPI has no LUNs. */
198 chan->chan_nluns = 1;
199 printf(": %d targets\n", chan->chan_ntargets);
200
201 /* Initialize the channel. */
202 scsipi_channel_init(chan);
203
204 /* Probe the bus for devices. */
205 atapi_probe_bus(sc, -1);
206 }
207
208 int
209 atapibusactivate(self, act)
210 struct device *self;
211 enum devact act;
212 {
213 struct atapibus_softc *sc = (void *) self;
214 struct scsipi_channel *chan = sc->sc_channel;
215 struct scsipi_periph *periph;
216 int target, error = 0, s;
217
218 s = splbio();
219 switch (act) {
220 case DVACT_ACTIVATE:
221 error = EOPNOTSUPP;
222 break;
223
224 case DVACT_DEACTIVATE:
225 for (target = 0; target < chan->chan_ntargets; target++) {
226 periph = scsipi_lookup_periph(chan, target, 0);
227 if (periph == NULL)
228 continue;
229 error = config_deactivate(periph->periph_dev);
230 if (error)
231 goto out;
232 }
233 break;
234 }
235 out:
236 splx(s);
237 return (error);
238 }
239
240 int
241 atapibusdetach(self, flags)
242 struct device *self;
243 int flags;
244 {
245 struct atapibus_softc *sc = (void *)self;
246 struct scsipi_channel *chan = sc->sc_channel;
247 struct scsipi_periph *periph;
248 int target, error;
249
250 /*
251 * Shut down the channel.
252 */
253 scsipi_channel_shutdown(chan);
254
255 /*
256 * Now detach all of the periphs.
257 */
258 for (target = 0; target < chan->chan_ntargets; target++) {
259 periph = scsipi_lookup_periph(chan, target, 0);
260 if (periph == NULL)
261 continue;
262 error = config_detach(periph->periph_dev, flags);
263 if (error)
264 return (error);
265
266 /*
267 * We have successfully detached the child. Drop the
268 * direct reference for the child so that wdcdetach
269 * won't call detach routine twice.
270 */
271 #ifdef DIAGNOSTIC
272 if (periph->periph_dev != sc->sc_drvs[target].drv_softc)
273 panic("softc mismatch");
274 #endif
275 sc->sc_drvs[target].drv_softc = NULL;
276
277 scsipi_remove_periph(chan, periph);
278 free(periph, M_DEVBUF);
279 }
280 return (0);
281 }
282
283 int
284 atapi_probe_bus(sc, target)
285 struct atapibus_softc *sc;
286 int target;
287 {
288 struct scsipi_channel *chan = sc->sc_channel;
289 int maxtarget, mintarget;
290 int error;
291
292 if (target == -1) {
293 maxtarget = 1;
294 mintarget = 0;
295 } else {
296 if (target < 0 || target >= chan->chan_ntargets)
297 return (ENXIO);
298 maxtarget = mintarget = target;
299 }
300
301 if ((error = scsipi_adapter_addref(chan->chan_adapter)) != 0)
302 return (error);
303 for (target = mintarget; target <= maxtarget; target++)
304 atapi_probe_device(sc, target);
305 scsipi_adapter_delref(chan->chan_adapter);
306 return (0);
307 }
308
309 void
310 atapi_probe_device(sc, target)
311 struct atapibus_softc *sc;
312 int target;
313 {
314 struct scsipi_channel *chan = sc->sc_channel;
315 struct scsipi_periph *periph;
316 struct ataparams ids;
317 struct ataparams *id = &ids;
318 struct ata_drive_datas *drvp = &sc->sc_drvs[target];
319 struct scsi_quirk_inquiry_pattern *finger;
320 struct scsipibus_attach_args sa;
321 struct cfdata *cf;
322 int priority, quirks;
323 char serial_number[21], model[41], firmware_revision[9];
324
325 /* skip if already attached */
326 if (scsipi_lookup_periph(chan, target, 0) != NULL)
327 return;
328
329 if (wdc_atapi_get_params(chan, target,
330 XS_CTL_POLL|XS_CTL_NOSLEEP, id) == 0) {
331 #ifdef ATAPI_DEBUG_PROBE
332 printf("%s drive %d: cmdsz 0x%x drqtype 0x%x\n",
333 sc->sc_dev.dv_xname, target,
334 id->atap_config & ATAPI_CFG_CMD_MASK,
335 id->atap_config & ATAPI_CFG_DRQ_MASK);
336 #endif
337 periph = malloc(sizeof(*periph), M_DEVBUF, M_NOWAIT);
338 if (periph == NULL) {
339 printf("%s: unable to allocate periph for drive %d\n",
340 sc->sc_dev.dv_xname, target);
341 return;
342 }
343 memset(periph, 0, sizeof(*periph));
344
345 periph->periph_dev = NULL;
346 periph->periph_channel = chan;
347 periph->periph_switch = &atapi_probe_periphsw;
348
349 /*
350 * Start with one command opening. The periph
351 * driver will grow this if it knows it can
352 * take advantage of it.
353 */
354 periph->periph_openings = 1;
355 periph->periph_active = 0;
356
357 periph->periph_target = target;
358 periph->periph_lun = 0;
359
360 TAILQ_INIT(&periph->periph_xferq);
361
362 #ifdef SCSIPI_DEBUG
363 if (SCSIPI_DEBUG_TYPE == SCSIPI_BUSTYPE_ATAPI &&
364 SCSIPI_DEBUG_TARGET == target)
365 periph->periph_dbflags |= SCSIPI_DEBUG_FLAGS;
366 #endif
367
368 periph->periph_type = ATAPI_CFG_TYPE(id->atap_config);
369 if (id->atap_config & ATAPI_CFG_REMOV)
370 periph->periph_flags |= PERIPH_REMOVABLE;
371
372 sa.sa_periph = periph;
373 sa.sa_inqbuf.type = ATAPI_CFG_TYPE(id->atap_config);
374 sa.sa_inqbuf.removable = id->atap_config & ATAPI_CFG_REMOV ?
375 T_REMOV : T_FIXED;
376 scsipi_strvis(model, 40, id->atap_model, 40);
377 scsipi_strvis(serial_number, 20, id->atap_serial, 20);
378 scsipi_strvis(firmware_revision, 8, id->atap_revision, 8);
379 sa.sa_inqbuf.vendor = model;
380 sa.sa_inqbuf.product = serial_number;
381 sa.sa_inqbuf.revision = firmware_revision;
382
383 finger = (struct scsi_quirk_inquiry_pattern *)scsipi_inqmatch(
384 &sa.sa_inqbuf, (caddr_t)atapi_quirk_patterns,
385 sizeof(atapi_quirk_patterns) /
386 sizeof(atapi_quirk_patterns[0]),
387 sizeof(atapi_quirk_patterns[0]), &priority);
388
389 if (finger != NULL)
390 quirks = finger->quirks;
391 else
392 quirks = 0;
393
394 /*
395 * Determine the operating mode capabilities of the device.
396 */
397 if ((id->atap_config & ATAPI_CFG_CMD_MASK) == ATAPI_CFG_CMD_16)
398 periph->periph_cap |= PERIPH_CAP_CMD16;
399 /* XXX This is gross. */
400 periph->periph_cap |= (id->atap_config & ATAPI_CFG_DRQ_MASK);
401
402 /*
403 * Now apply any quirks from the table.
404 */
405 periph->periph_quirks |= quirks;
406
407 if ((cf = config_search(atapibussubmatch, &sc->sc_dev,
408 &sa)) != 0) {
409 scsipi_insert_periph(chan, periph);
410 /*
411 * XXX Can't assign periph_dev here, because we'll
412 * XXX need it before config_attach() returns. Must
413 * XXX assign it in periph driver.
414 */
415 drvp->drv_softc = config_attach(&sc->sc_dev, cf, &sa,
416 atapibusprint);
417 wdc_probe_caps(drvp);
418 return;
419 } else {
420 atapibusprint(&sa, sc->sc_dev.dv_xname);
421 printf(" not configured\n");
422 free(periph, M_DEVBUF);
423 return;
424 }
425 }
426 }
427
428 int
429 atapibusprint(aux, pnp)
430 void *aux;
431 const char *pnp;
432 {
433 struct scsipibus_attach_args *sa = aux;
434 struct scsipi_inquiry_pattern *inqbuf;
435 char *dtype;
436
437 if (pnp != NULL)
438 printf("%s", pnp);
439
440 inqbuf = &sa->sa_inqbuf;
441
442 dtype = scsipi_dtype(inqbuf->type & SID_TYPE);
443 printf(" drive %d: <%s, %s, %s> type %d %s %s",
444 sa->sa_periph->periph_target ,inqbuf->vendor,
445 inqbuf->product, inqbuf->revision, inqbuf->type, dtype,
446 inqbuf->removable ? "removable" : "fixed");
447 return (UNCONF);
448 }
449