atapiconf.c revision 1.28.2.4 1 /* $NetBSD: atapiconf.c,v 1.28.2.4 1999/11/01 22:54:18 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 = chan->chan_periphs[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 for (target = 0; target < chan->chan_ntargets; target++) {
251 periph = chan->chan_periphs[target][0];
252 if (periph == NULL)
253 continue;
254 error = config_detach(periph->periph_dev, flags);
255 if (error)
256 return (error);
257
258 /*
259 * We have successfully detached the child. Drop the
260 * direct reference for the child so that wdcdetach
261 * won't call detach routine twice.
262 */
263 #ifdef DIAGNOSTIC
264 if (periph->periph_dev != sc->sc_drvs[target].drv_softc)
265 panic("softc mismatch");
266 #endif
267 sc->sc_drvs[target].drv_softc = NULL;
268
269 free(periph, M_DEVBUF);
270 chan->chan_periphs[target][0] = NULL;
271 }
272 return (0);
273 }
274
275 int
276 atapi_probe_bus(sc, target)
277 struct atapibus_softc *sc;
278 int target;
279 {
280 struct scsipi_channel *chan = sc->sc_channel;
281 int maxtarget, mintarget;
282 int error;
283
284 if (target == -1) {
285 maxtarget = 1;
286 mintarget = 0;
287 } else {
288 if (target < 0 || target >= chan->chan_ntargets)
289 return (ENXIO);
290 maxtarget = mintarget = target;
291 }
292
293 if ((error = scsipi_adapter_addref(chan->chan_adapter)) != 0)
294 return (error);
295 for (target = mintarget; target <= maxtarget; target++)
296 atapi_probe_device(sc, target);
297 scsipi_adapter_delref(chan->chan_adapter);
298 return (0);
299 }
300
301 void
302 atapi_probe_device(sc, target)
303 struct atapibus_softc *sc;
304 int target;
305 {
306 struct scsipi_channel *chan = sc->sc_channel;
307 struct scsipi_periph *periph;
308 struct ataparams ids;
309 struct ataparams *id = &ids;
310 struct ata_drive_datas *drvp = &sc->sc_drvs[target];
311 struct scsi_quirk_inquiry_pattern *finger;
312 struct scsipibus_attach_args sa;
313 struct cfdata *cf;
314 int priority, quirks;
315 char serial_number[21], model[41], firmware_revision[9];
316
317 /* skip if already attached */
318 if (chan->chan_periphs[target][0] != NULL)
319 return;
320
321 if (wdc_atapi_get_params(chan, target,
322 XS_CTL_POLL|XS_CTL_NOSLEEP, id) == 0) {
323 #ifdef ATAPI_DEBUG_PROBE
324 printf("%s drive %d: cmdsz 0x%x drqtype 0x%x\n",
325 sc->sc_dev.dv_xname, target,
326 id->atap_config & ATAPI_CFG_CMD_MASK,
327 id->atap_config & ATAPI_CFG_DRQ_MASK);
328 #endif
329 periph = malloc(sizeof(*periph), M_DEVBUF, M_NOWAIT);
330 if (periph == NULL) {
331 printf("%s: unable to allocate periph for drive %d\n",
332 sc->sc_dev.dv_xname, target);
333 return;
334 }
335 memset(periph, 0, sizeof(*periph));
336
337 periph->periph_dev = NULL;
338 periph->periph_channel = chan;
339 periph->periph_switch = &atapi_probe_periphsw;
340
341 /*
342 * Start with one command opening. The periph
343 * driver will grow this if it knows it can
344 * take advantage of it.
345 */
346 periph->periph_openings = 1;
347 periph->periph_active = 0;
348
349 periph->periph_target = target;
350 periph->periph_lun = 0;
351
352 TAILQ_INIT(&periph->periph_xferq);
353
354 #ifdef SCSIPI_DEBUG
355 if (SCSIPI_DEBUG_TYPE == SCSIPI_BUSTYPE_ATAPI &&
356 SCSIPI_DEBUG_TARGET == target)
357 periph->periph_dbflags |= SCSIPI_DEBUG_FLAGS;
358 #endif
359
360 periph->periph_type = ATAPI_CFG_TYPE(id->atap_config);
361 if (id->atap_config & ATAPI_CFG_REMOV)
362 periph->periph_flags |= PERIPH_REMOVABLE;
363
364 sa.sa_periph = periph;
365 sa.sa_inqbuf.type = ATAPI_CFG_TYPE(id->atap_config);
366 sa.sa_inqbuf.removable = id->atap_config & ATAPI_CFG_REMOV ?
367 T_REMOV : T_FIXED;
368 scsipi_strvis(model, 40, id->atap_model, 40);
369 scsipi_strvis(serial_number, 20, id->atap_serial, 20);
370 scsipi_strvis(firmware_revision, 8, id->atap_revision, 8);
371 sa.sa_inqbuf.vendor = model;
372 sa.sa_inqbuf.product = serial_number;
373 sa.sa_inqbuf.revision = firmware_revision;
374
375 finger = (struct scsi_quirk_inquiry_pattern *)scsipi_inqmatch(
376 &sa.sa_inqbuf, (caddr_t)atapi_quirk_patterns,
377 sizeof(atapi_quirk_patterns) /
378 sizeof(atapi_quirk_patterns[0]),
379 sizeof(atapi_quirk_patterns[0]), &priority);
380
381 if (finger != NULL)
382 quirks = finger->quirks;
383 else
384 quirks = 0;
385
386 /*
387 * Determine the operating mode capabilities of the device.
388 */
389 if ((id->atap_config & ATAPI_CFG_CMD_MASK) == ATAPI_CFG_CMD_16)
390 periph->periph_cap |= PERIPH_CAP_CMD16;
391 /* XXX This is gross. */
392 periph->periph_cap |= (id->atap_config & ATAPI_CFG_DRQ_MASK);
393
394 /*
395 * Now apply any quirks from the table.
396 */
397 periph->periph_quirks |= quirks;
398
399 if ((cf = config_search(atapibussubmatch, &sc->sc_dev,
400 &sa)) != 0) {
401 chan->chan_periphs[target][0] = periph;
402 /*
403 * XXX Can't assign periph_dev here, because we'll
404 * XXX need it before config_attach() returns. Must
405 * XXX assign it in periph driver.
406 */
407 drvp->drv_softc = config_attach(&sc->sc_dev, cf, &sa,
408 atapibusprint);
409 wdc_probe_caps(drvp);
410 return;
411 } else {
412 atapibusprint(&sa, sc->sc_dev.dv_xname);
413 printf(" not configured\n");
414 free(periph, M_DEVBUF);
415 return;
416 }
417 }
418 }
419
420 int
421 atapibusprint(aux, pnp)
422 void *aux;
423 const char *pnp;
424 {
425 struct scsipibus_attach_args *sa = aux;
426 struct scsipi_inquiry_pattern *inqbuf;
427 char *dtype;
428
429 if (pnp != NULL)
430 printf("%s", pnp);
431
432 inqbuf = &sa->sa_inqbuf;
433
434 dtype = scsipi_dtype(inqbuf->type & SID_TYPE);
435 printf(" drive %d: <%s, %s, %s> type %d %s %s",
436 sa->sa_periph->periph_target ,inqbuf->vendor,
437 inqbuf->product, inqbuf->revision, inqbuf->type, dtype,
438 inqbuf->removable ? "removable" : "fixed");
439 return (UNCONF);
440 }
441