1 /* $OpenBSD: cac.c,v 1.77 2023/11/28 09:29:20 jsg Exp $ */
2 /* $NetBSD: cac.c,v 1.15 2000/11/08 19:20:35 ad Exp $ */
3
4 /*
5 * Copyright (c) 2001,2003 Michael Shalayeff
6 * All rights reserved.
7 *
8 * The SCSI emulation layer is derived from gdt(4) driver,
9 * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
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 OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*-
33 * Copyright (c) 2000 The NetBSD Foundation, Inc.
34 * All rights reserved.
35 *
36 * This code is derived from software contributed to The NetBSD Foundation
37 * by Andrew Doran.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
49 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
52 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58 * POSSIBILITY OF SUCH DAMAGE.
59 */
60
61 /*
62 * Driver for Compaq array controllers.
63 */
64
65 #include "bio.h"
66
67 /* #define CAC_DEBUG */
68
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/kernel.h>
72 #include <sys/ioctl.h>
73 #include <sys/device.h>
74 #include <sys/queue.h>
75 #include <sys/buf.h>
76 #include <sys/endian.h>
77 #include <sys/malloc.h>
78 #include <sys/pool.h>
79
80 #include <machine/bus.h>
81
82 #include <scsi/scsi_all.h>
83 #include <scsi/scsi_disk.h>
84 #include <scsi/scsiconf.h>
85
86 #include <dev/ic/cacreg.h>
87 #include <dev/ic/cacvar.h>
88
89 #if NBIO > 0
90 #include <dev/biovar.h>
91 #endif
92 #include <sys/sensors.h>
93
94 struct cfdriver cac_cd = {
95 NULL, "cac", DV_DULL
96 };
97
98 void cac_scsi_cmd(struct scsi_xfer *);
99
100 const struct scsi_adapter cac_switch = {
101 cac_scsi_cmd, NULL, NULL, NULL, NULL
102 };
103
104 void *cac_ccb_alloc(void *);
105 void cac_ccb_done(struct cac_softc *, struct cac_ccb *);
106 void cac_ccb_free(void *, void *);
107 int cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int);
108 int cac_ccb_start(struct cac_softc *, struct cac_ccb *);
109 int cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
110 int drive, int blkno, int flags, struct scsi_xfer *xs);
111 int cac_get_dinfo(struct cac_softc *sc, int target);
112
113 struct cac_ccb *cac_l0_completed(struct cac_softc *);
114 int cac_l0_fifo_full(struct cac_softc *);
115 void cac_l0_intr_enable(struct cac_softc *, int);
116 int cac_l0_intr_pending(struct cac_softc *);
117 void cac_l0_submit(struct cac_softc *, struct cac_ccb *);
118
119 #if NBIO > 0
120 int cac_ioctl(struct device *, u_long, caddr_t);
121 int cac_ioctl_vol(struct cac_softc *, struct bioc_vol *);
122
123 #ifndef SMALL_KERNEL
124 int cac_create_sensors(struct cac_softc *);
125 void cac_sensor_refresh(void *);
126 #endif
127 #endif /* NBIO > 0 */
128
129 const
130 struct cac_linkage cac_l0 = {
131 cac_l0_completed,
132 cac_l0_fifo_full,
133 cac_l0_intr_enable,
134 cac_l0_intr_pending,
135 cac_l0_submit
136 };
137
138 /*
139 * Initialise our interface to the controller.
140 */
141 int
cac_init(struct cac_softc * sc,int startfw)142 cac_init(struct cac_softc *sc, int startfw)
143 {
144 struct scsibus_attach_args saa;
145 struct cac_controller_info cinfo;
146 int error, rseg, size, i;
147 bus_dma_segment_t seg[1];
148 struct cac_ccb *ccb;
149
150 SIMPLEQ_INIT(&sc->sc_ccb_free);
151 SIMPLEQ_INIT(&sc->sc_ccb_queue);
152 mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
153 scsi_iopool_init(&sc->sc_iopool, sc, cac_ccb_alloc, cac_ccb_free);
154
155 size = sizeof(struct cac_ccb) * CAC_MAX_CCBS;
156
157 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seg, 1,
158 &rseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO)) != 0) {
159 printf("%s: unable to allocate CCBs, error = %d\n",
160 sc->sc_dv.dv_xname, error);
161 return (-1);
162 }
163
164 if ((error = bus_dmamem_map(sc->sc_dmat, seg, rseg, size,
165 &sc->sc_ccbs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
166 printf("%s: unable to map CCBs, error = %d\n",
167 sc->sc_dv.dv_xname, error);
168 return (-1);
169 }
170
171 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
172 BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
173 printf("%s: unable to create CCB DMA map, error = %d\n",
174 sc->sc_dv.dv_xname, error);
175 return (-1);
176 }
177
178 if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs,
179 size, NULL, BUS_DMA_NOWAIT)) != 0) {
180 printf("%s: unable to load CCB DMA map, error = %d\n",
181 sc->sc_dv.dv_xname, error);
182 return (-1);
183 }
184
185 sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
186 ccb = (struct cac_ccb *)sc->sc_ccbs;
187
188 for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) {
189 /* Create the DMA map for this CCB's data */
190 error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER,
191 CAC_SG_SIZE, CAC_MAX_XFER, 0,
192 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
193 &ccb->ccb_dmamap_xfer);
194
195 if (error) {
196 printf("%s: can't create ccb dmamap (%d)\n",
197 sc->sc_dv.dv_xname, error);
198 break;
199 }
200
201 ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb);
202 mtx_enter(&sc->sc_ccb_mtx);
203 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain);
204 mtx_leave(&sc->sc_ccb_mtx);
205 }
206
207 /* Start firmware background tasks, if needed. */
208 if (startfw) {
209 if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo),
210 0, 0, CAC_CCB_DATA_IN, NULL)) {
211 printf("%s: CAC_CMD_START_FIRMWARE failed\n",
212 sc->sc_dv.dv_xname);
213 return (-1);
214 }
215 }
216
217 if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0,
218 CAC_CCB_DATA_IN, NULL)) {
219 printf("%s: CAC_CMD_GET_CTRL_INFO failed\n",
220 sc->sc_dv.dv_xname);
221 return (-1);
222 }
223
224 if (!cinfo.num_drvs) {
225 printf("%s: no volumes defined\n", sc->sc_dv.dv_xname);
226 return (-1);
227 }
228
229 sc->sc_nunits = cinfo.num_drvs;
230 sc->sc_dinfos = mallocarray(cinfo.num_drvs,
231 sizeof(struct cac_drive_info), M_DEVBUF, M_NOWAIT | M_ZERO);
232 if (sc->sc_dinfos == NULL) {
233 printf("%s: cannot allocate memory for drive_info\n",
234 sc->sc_dv.dv_xname);
235 return (-1);
236 }
237
238 saa.saa_adapter_softc = sc;
239 saa.saa_adapter = &cac_switch;
240 saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET;
241 saa.saa_adapter_buswidth = cinfo.num_drvs;
242 saa.saa_luns = 8;
243 saa.saa_openings = CAC_MAX_CCBS / sc->sc_nunits;
244 if (saa.saa_openings < 4 )
245 saa.saa_openings = 4;
246 saa.saa_pool = &sc->sc_iopool;
247 saa.saa_quirks = saa.saa_flags = 0;
248 saa.saa_wwpn = saa.saa_wwnn = 0;
249
250 sc->sc_scsibus = (struct scsibus_softc *)config_found(&sc->sc_dv, &saa,
251 scsiprint);
252
253 (*sc->sc_cl->cl_intr_enable)(sc, 1);
254
255 #if NBIO > 0
256 if (bio_register(&sc->sc_dv, cac_ioctl) != 0)
257 printf("%s: controller registration failed\n",
258 sc->sc_dv.dv_xname);
259 else
260 sc->sc_ioctl = cac_ioctl;
261
262 #ifndef SMALL_KERNEL
263 if (cac_create_sensors(sc) != 0)
264 printf("%s: unable to create sensors\n", sc->sc_dv.dv_xname);
265 #endif
266 #endif
267
268
269 return (0);
270 }
271
272 int
cac_flush(struct cac_softc * sc)273 cac_flush(struct cac_softc *sc)
274 {
275 u_int8_t buf[512];
276
277 memset(buf, 0, sizeof(buf));
278 buf[0] = 1;
279 return cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0,
280 CAC_CCB_DATA_OUT, NULL);
281 }
282
283 /*
284 * Handle an interrupt from the controller: process finished CCBs and
285 * dequeue any waiting CCBs.
286 */
287 int
cac_intr(void * v)288 cac_intr(void *v)
289 {
290 struct cac_softc *sc = v;
291 struct cac_ccb *ccb;
292 int istat, ret = 0;
293
294 if (!(istat = (*sc->sc_cl->cl_intr_pending)(sc)))
295 return 0;
296
297 if (istat & CAC_INTR_FIFO_NEMPTY)
298 while ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) {
299 ret = 1;
300 cac_ccb_done(sc, ccb);
301 }
302 cac_ccb_start(sc, NULL);
303
304 return (ret);
305 }
306
307 /*
308 * Execute a [polled] command.
309 */
310 int
cac_cmd(struct cac_softc * sc,int command,void * data,int datasize,int drive,int blkno,int flags,struct scsi_xfer * xs)311 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
312 int drive, int blkno, int flags, struct scsi_xfer *xs)
313 {
314 struct cac_ccb *ccb;
315 struct cac_sgb *sgb;
316 int i, rv, size, nsegs;
317
318 #ifdef CAC_DEBUG
319 printf("cac_cmd op=%x drv=%d blk=%d data=%p[%x] fl=%x xs=%p ",
320 command, drive, blkno, data, datasize, flags, xs);
321 #endif
322
323 if (xs) {
324 ccb = xs->io;
325 /*
326 * The xs may have been restarted by the scsi layer, so
327 * ensure the ccb starts in the proper state.
328 */
329 ccb->ccb_flags = 0;
330 } else {
331 /* Internal command. Need to get our own ccb. */
332 ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL | SCSI_NOSLEEP);
333 if (ccb == NULL)
334 return (EBUSY);
335 }
336
337 if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
338 bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer,
339 (void *)data, datasize, NULL, BUS_DMA_NOWAIT);
340
341 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
342 ccb->ccb_dmamap_xfer->dm_mapsize,
343 (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD :
344 BUS_DMASYNC_PREWRITE);
345
346 sgb = ccb->ccb_seg;
347 nsegs = ccb->ccb_dmamap_xfer->dm_nsegs;
348 if (nsegs > CAC_SG_SIZE)
349 panic("cac_cmd: nsegs botch");
350
351 size = 0;
352 for (i = 0; i < nsegs; i++, sgb++) {
353 size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len;
354 sgb->length =
355 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
356 sgb->addr =
357 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
358 }
359 } else {
360 size = datasize;
361 nsegs = 0;
362 }
363
364 ccb->ccb_hdr.drive = drive;
365 ccb->ccb_hdr.priority = 0;
366 ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) +
367 sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2);
368
369 ccb->ccb_req.next = 0;
370 ccb->ccb_req.command = command;
371 ccb->ccb_req.error = 0;
372 ccb->ccb_req.blkno = htole32(blkno);
373 ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE));
374 ccb->ccb_req.sgcount = nsegs;
375 ccb->ccb_req.reserved = 0;
376
377 ccb->ccb_flags = flags;
378 ccb->ccb_datasize = size;
379 ccb->ccb_xs = xs;
380
381 if (!xs || xs->flags & SCSI_POLL) {
382 /* Synchronous commands mustn't wait. */
383 mtx_enter(&sc->sc_ccb_mtx);
384 if ((*sc->sc_cl->cl_fifo_full)(sc)) {
385 mtx_leave(&sc->sc_ccb_mtx);
386 rv = EBUSY;
387 } else {
388 mtx_leave(&sc->sc_ccb_mtx);
389 ccb->ccb_flags |= CAC_CCB_ACTIVE;
390 (*sc->sc_cl->cl_submit)(sc, ccb);
391 rv = cac_ccb_poll(sc, ccb, 2000);
392 }
393 } else
394 rv = cac_ccb_start(sc, ccb);
395
396 if (xs == NULL)
397 scsi_io_put(&sc->sc_iopool, ccb);
398
399 return (rv);
400 }
401
402 /*
403 * Wait for the specified CCB to complete. Must be called at splbio.
404 */
405 int
cac_ccb_poll(struct cac_softc * sc,struct cac_ccb * wantccb,int timo)406 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
407 {
408 struct cac_ccb *ccb;
409 int t;
410
411 t = timo * 100;
412 do {
413 for (; t--; DELAY(10))
414 if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL)
415 break;
416 if (t < 0) {
417 printf("%s: timeout\n", sc->sc_dv.dv_xname);
418 return (EBUSY);
419 }
420 cac_ccb_done(sc, ccb);
421 } while (ccb != wantccb);
422
423 return (0);
424 }
425
426 /*
427 * Enqueue the specified command (if any) and attempt to start all enqueued
428 * commands.
429 */
430 int
cac_ccb_start(struct cac_softc * sc,struct cac_ccb * ccb)431 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb)
432 {
433 if (ccb != NULL) {
434 mtx_enter(&sc->sc_ccb_mtx);
435 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain);
436 mtx_leave(&sc->sc_ccb_mtx);
437 }
438
439 while (1) {
440 mtx_enter(&sc->sc_ccb_mtx);
441 if (SIMPLEQ_EMPTY(&sc->sc_ccb_queue) ||
442 (*sc->sc_cl->cl_fifo_full)(sc)) {
443 mtx_leave(&sc->sc_ccb_mtx);
444 break;
445 }
446 ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue);
447 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain);
448 mtx_leave(&sc->sc_ccb_mtx);
449
450 ccb->ccb_flags |= CAC_CCB_ACTIVE;
451 (*sc->sc_cl->cl_submit)(sc, ccb);
452 }
453
454 return (0);
455 }
456
457 /*
458 * Process a finished CCB.
459 */
460 void
cac_ccb_done(struct cac_softc * sc,struct cac_ccb * ccb)461 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb)
462 {
463 struct scsi_xfer *xs = ccb->ccb_xs;
464 int error = 0;
465
466 if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) {
467 printf("%s: CCB not active, xs=%p\n", sc->sc_dv.dv_xname, xs);
468 if (xs) {
469 xs->error = XS_DRIVER_STUFFUP;
470 scsi_done(xs);
471 }
472 return;
473 }
474
475 if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
476 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
477 ccb->ccb_dmamap_xfer->dm_mapsize,
478 ccb->ccb_flags & CAC_CCB_DATA_IN ?
479 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
480 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
481 }
482
483 if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0)
484 printf("%s: soft error; corrected\n", sc->sc_dv.dv_xname);
485 if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) {
486 error = 1;
487 printf("%s: hard error\n", sc->sc_dv.dv_xname);
488 }
489 if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) {
490 error = 1;
491 printf("%s: invalid request\n", sc->sc_dv.dv_xname);
492 }
493
494 if (xs) {
495 if (error)
496 xs->error = XS_DRIVER_STUFFUP;
497 else
498 xs->resid = 0;
499
500 scsi_done(xs);
501 }
502 }
503
504 /*
505 * Allocate a CCB.
506 */
507 void *
cac_ccb_alloc(void * xsc)508 cac_ccb_alloc(void *xsc)
509 {
510 struct cac_softc *sc = xsc;
511 struct cac_ccb *ccb = NULL;
512
513 mtx_enter(&sc->sc_ccb_mtx);
514 if (SIMPLEQ_EMPTY(&sc->sc_ccb_free)) {
515 #ifdef CAC_DEBUG
516 printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname);
517 #endif
518 } else {
519 ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free);
520 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain);
521 }
522 mtx_leave(&sc->sc_ccb_mtx);
523
524 return (ccb);
525 }
526
527 /*
528 * Put a CCB onto the freelist.
529 */
530 void
cac_ccb_free(void * xsc,void * xccb)531 cac_ccb_free(void *xsc, void *xccb)
532 {
533 struct cac_softc *sc = xsc;
534 struct cac_ccb *ccb = xccb;
535
536 ccb->ccb_flags = 0;
537
538 mtx_enter(&sc->sc_ccb_mtx);
539 SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
540 mtx_leave(&sc->sc_ccb_mtx);
541 }
542
543 int
cac_get_dinfo(struct cac_softc * sc,int target)544 cac_get_dinfo(struct cac_softc *sc, int target)
545 {
546 if (sc->sc_dinfos[target].ncylinders)
547 return (0);
548
549 if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &sc->sc_dinfos[target],
550 sizeof(*sc->sc_dinfos), target, 0, CAC_CCB_DATA_IN, NULL)) {
551 printf("%s: CMD_GET_LOG_DRV_INFO failed\n",
552 sc->sc_dv.dv_xname);
553 return (-1);
554 }
555
556 return (0);
557 }
558
559 void
cac_scsi_cmd(struct scsi_xfer * xs)560 cac_scsi_cmd(struct scsi_xfer *xs)
561 {
562 struct scsi_link *link = xs->sc_link;
563 struct cac_softc *sc = link->bus->sb_adapter_softc;
564 struct cac_drive_info *dinfo;
565 struct scsi_inquiry_data inq;
566 struct scsi_sense_data sd;
567 struct scsi_read_cap_data rcd;
568 u_int8_t target = link->target;
569 u_int32_t blockno, blockcnt, size;
570 struct scsi_rw *rw;
571 struct scsi_rw_10 *rw10;
572 int op, flags, s, error;
573 const char *p;
574
575 if (target >= sc->sc_nunits || link->lun != 0) {
576 xs->error = XS_DRIVER_STUFFUP;
577 scsi_done(xs);
578 return;
579 }
580
581 s = splbio();
582 xs->error = XS_NOERROR;
583 dinfo = &sc->sc_dinfos[target];
584
585 switch (xs->cmd.opcode) {
586 case TEST_UNIT_READY:
587 case START_STOP:
588 #if 0
589 case VERIFY:
590 #endif
591 break;
592
593 case REQUEST_SENSE:
594 bzero(&sd, sizeof sd);
595 sd.error_code = SSD_ERRCODE_CURRENT;
596 sd.segment = 0;
597 sd.flags = SKEY_NO_SENSE;
598 *(u_int32_t*)sd.info = htole32(0);
599 sd.extra_len = 0;
600 scsi_copy_internal_data(xs, &sd, sizeof(sd));
601 break;
602
603 case INQUIRY:
604 if (cac_get_dinfo(sc, target)) {
605 xs->error = XS_DRIVER_STUFFUP;
606 break;
607 }
608 bzero(&inq, sizeof inq);
609 inq.device = T_DIRECT;
610 inq.dev_qual2 = 0;
611 inq.version = SCSI_REV_2;
612 inq.response_format = SID_SCSI2_RESPONSE;
613 inq.additional_length = SID_SCSI2_ALEN;
614 inq.flags |= SID_CmdQue;
615 strlcpy(inq.vendor, "Compaq ", sizeof inq.vendor);
616 switch (CAC_GET1(dinfo->mirror)) {
617 case 0: p = "RAID0"; break;
618 case 1: p = "RAID4"; break;
619 case 2: p = "RAID1"; break;
620 case 3: p = "RAID5"; break;
621 default:p = "<UNK>"; break;
622 }
623 snprintf(inq.product, sizeof inq.product, "%s vol #%02d",
624 p, target);
625 strlcpy(inq.revision, " ", sizeof inq.revision);
626 scsi_copy_internal_data(xs, &inq, sizeof(inq));
627 break;
628
629 case READ_CAPACITY:
630 if (cac_get_dinfo(sc, target)) {
631 xs->error = XS_DRIVER_STUFFUP;
632 break;
633 }
634 bzero(&rcd, sizeof rcd);
635 _lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) *
636 CAC_GET1(dinfo->nsectors) - 1, rcd.addr);
637 _lto4b(CAC_SECTOR_SIZE, rcd.length);
638 scsi_copy_internal_data(xs, &rcd, sizeof(rcd));
639 break;
640
641 case PREVENT_ALLOW:
642 break;
643
644 case SYNCHRONIZE_CACHE:
645 if (cac_flush(sc))
646 xs->error = XS_DRIVER_STUFFUP;
647 break;
648
649 case READ_COMMAND:
650 case READ_10:
651 case WRITE_COMMAND:
652 case WRITE_10:
653
654 flags = 0;
655 /* A read or write operation. */
656 if (xs->cmdlen == 6) {
657 rw = (struct scsi_rw *)&xs->cmd;
658 blockno = _3btol(rw->addr) &
659 (SRW_TOPADDR << 16 | 0xffff);
660 blockcnt = rw->length ? rw->length : 0x100;
661 } else {
662 rw10 = (struct scsi_rw_10 *)&xs->cmd;
663 blockno = _4btol(rw10->addr);
664 blockcnt = _2btol(rw10->length);
665 }
666 size = CAC_GET2(dinfo->ncylinders) *
667 CAC_GET1(dinfo->nheads) * CAC_GET1(dinfo->nsectors);
668 if (blockno >= size || blockno + blockcnt > size) {
669 printf("%s: out of bounds %u-%u >= %u\n",
670 sc->sc_dv.dv_xname, blockno, blockcnt, size);
671 xs->error = XS_DRIVER_STUFFUP;
672 break;
673 }
674
675 switch (xs->cmd.opcode) {
676 case READ_COMMAND:
677 case READ_10:
678 op = CAC_CMD_READ;
679 flags = CAC_CCB_DATA_IN;
680 break;
681 case WRITE_COMMAND:
682 case WRITE_10:
683 op = CAC_CMD_WRITE;
684 flags = CAC_CCB_DATA_OUT;
685 break;
686 }
687
688 if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE,
689 target, blockno, flags, xs))) {
690 splx(s);
691 if (error == EBUSY)
692 xs->error = XS_BUSY;
693 else
694 xs->error = XS_DRIVER_STUFFUP;
695 scsi_done(xs);
696 return;
697 }
698
699 splx(s);
700 return;
701
702 default:
703 #ifdef CAC_DEBUG
704 printf("unsupported scsi command %#x tgt %d ", xs->cmd.opcode, target);
705 #endif
706 xs->error = XS_DRIVER_STUFFUP;
707 }
708
709 splx(s);
710 scsi_done(xs);
711 }
712
713 /*
714 * Board specific linkage shared between multiple bus types.
715 */
716
717 int
cac_l0_fifo_full(struct cac_softc * sc)718 cac_l0_fifo_full(struct cac_softc *sc)
719 {
720
721 return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
722 }
723
724 void
cac_l0_submit(struct cac_softc * sc,struct cac_ccb * ccb)725 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb)
726 {
727 #ifdef CAC_DEBUG
728 printf("submit-%lx ", ccb->ccb_paddr);
729 #endif
730 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
731 sc->sc_dmamap->dm_mapsize,
732 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
733 cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr);
734 }
735
736 struct cac_ccb *
cac_l0_completed(struct cac_softc * sc)737 cac_l0_completed(struct cac_softc *sc)
738 {
739 struct cac_ccb *ccb;
740 paddr_t off, orig_off;
741
742 if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO)))
743 return NULL;
744 #ifdef CAC_DEBUG
745 printf("compl-%lx ", off);
746 #endif
747 orig_off = off;
748
749 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
750 sc->sc_dmamap->dm_mapsize,
751 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
752
753 off = (off & ~3) - sc->sc_ccbs_paddr;
754 ccb = (struct cac_ccb *)(sc->sc_ccbs + off);
755
756 if (orig_off & 3 && ccb->ccb_req.error == 0)
757 ccb->ccb_req.error = CAC_RET_CMD_INVALID;
758
759 return (ccb);
760 }
761
762 int
cac_l0_intr_pending(struct cac_softc * sc)763 cac_l0_intr_pending(struct cac_softc *sc)
764 {
765
766 return (cac_inl(sc, CAC_REG_INTR_PENDING));
767 }
768
769 void
cac_l0_intr_enable(struct cac_softc * sc,int state)770 cac_l0_intr_enable(struct cac_softc *sc, int state)
771 {
772
773 cac_outl(sc, CAC_REG_INTR_MASK,
774 state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE);
775 }
776
777 #if NBIO > 0
778 const int cac_level[] = { 0, 4, 1, 5, 51, 7 };
779 const int cac_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE,
780 BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED,
781 BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING,
782 BIOC_SVOFFLINE, BIOC_SVBUILDING };
783
784 int
cac_ioctl(struct device * dev,u_long cmd,caddr_t addr)785 cac_ioctl(struct device *dev, u_long cmd, caddr_t addr)
786 {
787 struct cac_softc *sc = (struct cac_softc *)dev;
788 struct bioc_inq *bi;
789 struct bioc_disk *bd;
790 cac_lock_t lock;
791 int error = 0;
792
793 lock = CAC_LOCK(sc);
794 switch (cmd) {
795 case BIOCINQ:
796 bi = (struct bioc_inq *)addr;
797 strlcpy(bi->bi_dev, sc->sc_dv.dv_xname, sizeof(bi->bi_dev));
798 bi->bi_novol = sc->sc_nunits;
799 bi->bi_nodisk = 0;
800 break;
801
802 case BIOCVOL:
803 error = cac_ioctl_vol(sc, (struct bioc_vol *)addr);
804 break;
805
806 case BIOCDISK:
807 bd = (struct bioc_disk *)addr;
808 if (bd->bd_volid > sc->sc_nunits) {
809 error = EINVAL;
810 break;
811 }
812 /* No disk information yet */
813 break;
814
815 case BIOCBLINK:
816 case BIOCALARM:
817 case BIOCSETSTATE:
818 default:
819 error = ENOTTY;
820 }
821 CAC_UNLOCK(sc, lock);
822
823 return (error);
824 }
825
826 int
cac_ioctl_vol(struct cac_softc * sc,struct bioc_vol * bv)827 cac_ioctl_vol(struct cac_softc *sc, struct bioc_vol *bv)
828 {
829 struct cac_drive_info dinfo;
830 struct cac_drive_status dstatus;
831 u_int32_t blks;
832
833 if (bv->bv_volid > sc->sc_nunits)
834 return (EINVAL);
835 if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo),
836 bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
837 return (EIO);
838 if (cac_cmd(sc, CAC_CMD_SENSE_DRV_STATUS, &dstatus, sizeof(dstatus),
839 bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
840 return (EIO);
841 bv->bv_status = BIOC_SVINVALID;
842 blks = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) *
843 CAC_GET1(dinfo.nsectors);
844 bv->bv_size = (off_t)blks * CAC_GET2(dinfo.secsize);
845 bv->bv_level = cac_level[CAC_GET1(dinfo.mirror)]; /*XXX limit check */
846 bv->bv_nodisk = 0; /* XXX */
847 bv->bv_status = 0; /* XXX */
848 bv->bv_percent = -1;
849 bv->bv_seconds = 0;
850 if (dstatus.stat < nitems(cac_stat))
851 bv->bv_status = cac_stat[dstatus.stat];
852 if (bv->bv_status == BIOC_SVREBUILD ||
853 bv->bv_status == BIOC_SVBUILDING)
854 bv->bv_percent = ((blks - CAC_GET4(dstatus.prog)) * 1000ULL) /
855 blks;
856
857 return (0);
858 }
859
860 #ifndef SMALL_KERNEL
861 int
cac_create_sensors(struct cac_softc * sc)862 cac_create_sensors(struct cac_softc *sc)
863 {
864 struct device *dev;
865 struct scsibus_softc *ssc = NULL;
866 struct scsi_link *link;
867 int i;
868
869 TAILQ_FOREACH(dev, &alldevs, dv_list) {
870 if (dev->dv_parent != &sc->sc_dv)
871 continue;
872
873 /* check if this is the scsibus for the logical disks */
874 ssc = (struct scsibus_softc *)dev;
875 if (ssc == sc->sc_scsibus)
876 break;
877 ssc = NULL;
878 }
879
880 if (ssc == NULL)
881 return (1);
882
883 sc->sc_sensors = mallocarray(sc->sc_nunits,
884 sizeof(struct ksensor), M_DEVBUF, M_NOWAIT | M_ZERO);
885 if (sc->sc_sensors == NULL)
886 return (1);
887
888 strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname,
889 sizeof(sc->sc_sensordev.xname));
890
891 for (i = 0; i < sc->sc_nunits; i++) {
892 link = scsi_get_link(ssc, i, 0);
893 if (link == NULL)
894 goto bad;
895
896 dev = link->device_softc;
897
898 sc->sc_sensors[i].type = SENSOR_DRIVE;
899 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
900
901 strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
902 sizeof(sc->sc_sensors[i].desc));
903
904 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
905 }
906
907 if (sensor_task_register(sc, cac_sensor_refresh, 10) == NULL)
908 goto bad;
909
910 sensordev_install(&sc->sc_sensordev);
911
912 return (0);
913
914 bad:
915 free(sc->sc_sensors, M_DEVBUF,
916 sc->sc_nunits * sizeof(struct ksensor));
917
918 return (1);
919 }
920
921 void
cac_sensor_refresh(void * arg)922 cac_sensor_refresh(void *arg)
923 {
924 struct cac_softc *sc = arg;
925 struct bioc_vol bv;
926 int i, s;
927
928 for (i = 0; i < sc->sc_nunits; i++) {
929 bzero(&bv, sizeof(bv));
930 bv.bv_volid = i;
931 s = splbio();
932 if (cac_ioctl_vol(sc, &bv)) {
933 splx(s);
934 return;
935 }
936 splx(s);
937
938 switch (bv.bv_status) {
939 case BIOC_SVOFFLINE:
940 sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
941 sc->sc_sensors[i].status = SENSOR_S_CRIT;
942 break;
943
944 case BIOC_SVDEGRADED:
945 sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
946 sc->sc_sensors[i].status = SENSOR_S_WARN;
947 break;
948
949 case BIOC_SVSCRUB:
950 case BIOC_SVONLINE:
951 sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
952 sc->sc_sensors[i].status = SENSOR_S_OK;
953 break;
954
955 case BIOC_SVREBUILD:
956 case BIOC_SVBUILDING:
957 sc->sc_sensors[i].value = SENSOR_DRIVE_REBUILD;
958 sc->sc_sensors[i].status = SENSOR_S_OK;
959 break;
960
961 case BIOC_SVINVALID:
962 /* FALLTHROUGH */
963 default:
964 sc->sc_sensors[i].value = 0; /* unknown */
965 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
966 }
967 }
968 }
969 #endif /* SMALL_KERNEL */
970 #endif /* NBIO > 0 */
971