[BACK]Return to icp.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / ic

Annotation of src/sys/dev/ic/icp.c, Revision 1.27.2.1

1.27.2.1! yamt        1: /*     $NetBSD: icp.c,v 1.27 2008/04/08 12:07:26 cegger Exp $  */
1.1       ad          2:
                      3: /*-
1.8       thorpej     4:  * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
1.1       ad          5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
1.8       thorpej     8:  * by Andrew Doran, and by Jason R. Thorpe of Wasabi Systems, Inc.
1.1       ad          9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: /*
                     33:  * Copyright (c) 1999, 2000 Niklas Hallqvist.  All rights reserved.
                     34:  *
                     35:  * Redistribution and use in source and binary forms, with or without
                     36:  * modification, are permitted provided that the following conditions
                     37:  * are met:
                     38:  * 1. Redistributions of source code must retain the above copyright
                     39:  *    notice, this list of conditions and the following disclaimer.
                     40:  * 2. Redistributions in binary form must reproduce the above copyright
                     41:  *    notice, this list of conditions and the following disclaimer in the
                     42:  *    documentation and/or other materials provided with the distribution.
                     43:  * 3. All advertising materials mentioning features or use of this software
                     44:  *    must display the following acknowledgement:
                     45:  *     This product includes software developed by Niklas Hallqvist.
                     46:  * 4. The name of the author may not be used to endorse or promote products
                     47:  *    derived from this software without specific prior written permission.
                     48:  *
                     49:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     50:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     51:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     52:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     53:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     54:   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     55:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     56:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     57:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     58:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     59:  *
                     60:  * from OpenBSD: gdt_common.c,v 1.12 2001/07/04 06:43:18 niklas Exp
                     61:  */
                     62:
                     63: /*
                     64:  * This driver would not have written if it was not for the hardware donations
                     65:  * from both ICP-Vortex and Öko.neT.  I want to thank them for their support.
                     66:  *
                     67:  * Re-worked for NetBSD by Andrew Doran.  Test hardware kindly supplied by
                     68:  * Intel.
1.8       thorpej    69:  *
                     70:  * Support for the ICP-Vortex management tools added by
                     71:  * Jason R. Thorpe of Wasabi Systems, Inc., based on code
1.10      thorpej    72:  * provided by Achim Leubner <achim.leubner@intel.com>.
                     73:  *
                     74:  * Additional support for dynamic rescan of cacheservice drives by
                     75:  * Jason R. Thorpe of Wasabi Systems, Inc.
1.1       ad         76:  */
                     77:
                     78: #include <sys/cdefs.h>
1.27.2.1! yamt       79: __KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.27 2008/04/08 12:07:26 cegger Exp $");
1.1       ad         80:
                     81: #include <sys/param.h>
                     82: #include <sys/systm.h>
                     83: #include <sys/kernel.h>
                     84: #include <sys/device.h>
                     85: #include <sys/queue.h>
                     86: #include <sys/proc.h>
                     87: #include <sys/buf.h>
                     88: #include <sys/endian.h>
                     89: #include <sys/malloc.h>
                     90: #include <sys/disk.h>
                     91:
                     92: #include <uvm/uvm_extern.h>
                     93:
1.18      dsl        94: #include <sys/bswap.h>
1.26      ad         95: #include <sys/bus.h>
1.1       ad         96:
                     97: #include <dev/pci/pcireg.h>
                     98: #include <dev/pci/pcivar.h>
                     99: #include <dev/pci/pcidevs.h>
                    100:
                    101: #include <dev/ic/icpreg.h>
                    102: #include <dev/ic/icpvar.h>
                    103:
1.8       thorpej   104: #include <dev/scsipi/scsipi_all.h>
                    105: #include <dev/scsipi/scsiconf.h>
                    106:
1.13      drochner  107: #include "locators.h"
                    108:
1.1       ad        109: int    icp_async_event(struct icp_softc *, int);
                    110: void   icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic);
                    111: void   icp_chain(struct icp_softc *);
                    112: int    icp_print(void *, const char *);
                    113: void   icp_watchdog(void *);
1.8       thorpej   114: void   icp_ucmd_intr(struct icp_ccb *);
1.10      thorpej   115: void   icp_recompute_openings(struct icp_softc *);
1.8       thorpej   116:
                    117: int    icp_count;      /* total # of controllers, for ioctl interface */
                    118:
                    119: /*
                    120:  * Statistics for the ioctl interface to query.
                    121:  *
                    122:  * XXX Global.  They should probably be made per-controller
                    123:  * XXX at some point.
                    124:  */
                    125: gdt_statist_t icp_stats;
1.1       ad        126:
                    127: int
                    128: icp_init(struct icp_softc *icp, const char *intrstr)
                    129: {
                    130:        struct icp_attach_args icpa;
                    131:        struct icp_binfo binfo;
                    132:        struct icp_ccb *ic;
                    133:        u_int16_t cdev_cnt;
1.12      mycroft   134:        int i, j, state, feat, nsegs, rv;
1.15      drochner  135:        int locs[ICPCF_NLOCS];
1.1       ad        136:
1.5       simonb    137:        state = 0;
1.1       ad        138:
                    139:        if (intrstr != NULL)
1.27      cegger    140:                aprint_normal_dev(&icp->icp_dv, "interrupting at %s\n",
1.1       ad        141:                    intrstr);
                    142:
                    143:        SIMPLEQ_INIT(&icp->icp_ccb_queue);
                    144:        SIMPLEQ_INIT(&icp->icp_ccb_freelist);
1.8       thorpej   145:        SIMPLEQ_INIT(&icp->icp_ucmd_queue);
1.25      ad        146:        callout_init(&icp->icp_wdog_callout, 0);
1.1       ad        147:
                    148:        /*
                    149:         * Allocate a scratch area.
                    150:         */
                    151:        if (bus_dmamap_create(icp->icp_dmat, ICP_SCRATCH_SIZE, 1,
                    152:            ICP_SCRATCH_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
                    153:            &icp->icp_scr_dmamap) != 0) {
1.27      cegger    154:                aprint_error_dev(&icp->icp_dv, "cannot create scratch dmamap\n");
1.1       ad        155:                return (1);
                    156:        }
                    157:        state++;
                    158:
                    159:        if (bus_dmamem_alloc(icp->icp_dmat, ICP_SCRATCH_SIZE, PAGE_SIZE, 0,
                    160:            icp->icp_scr_seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0) {
1.27      cegger    161:                aprint_error_dev(&icp->icp_dv, "cannot alloc scratch dmamem\n");
1.1       ad        162:                goto bail_out;
                    163:        }
                    164:        state++;
                    165:
                    166:        if (bus_dmamem_map(icp->icp_dmat, icp->icp_scr_seg, nsegs,
                    167:            ICP_SCRATCH_SIZE, &icp->icp_scr, 0)) {
1.27      cegger    168:                aprint_error_dev(&icp->icp_dv, "cannot map scratch dmamem\n");
1.1       ad        169:                goto bail_out;
                    170:        }
                    171:        state++;
                    172:
                    173:        if (bus_dmamap_load(icp->icp_dmat, icp->icp_scr_dmamap, icp->icp_scr,
                    174:            ICP_SCRATCH_SIZE, NULL, BUS_DMA_NOWAIT)) {
1.27      cegger    175:                aprint_error_dev(&icp->icp_dv, "cannot load scratch dmamap\n");
1.1       ad        176:                goto bail_out;
                    177:        }
                    178:        state++;
                    179:
                    180:        /*
                    181:         * Allocate and initialize the command control blocks.
                    182:         */
                    183:        ic = malloc(sizeof(*ic) * ICP_NCCBS, M_DEVBUF, M_NOWAIT | M_ZERO);
                    184:        if ((icp->icp_ccbs = ic) == NULL) {
1.27      cegger    185:                aprint_error_dev(&icp->icp_dv, "malloc() failed\n");
1.1       ad        186:                goto bail_out;
                    187:        }
                    188:        state++;
                    189:
                    190:        for (i = 0; i < ICP_NCCBS; i++, ic++) {
                    191:                /*
                    192:                 * The first two command indexes have special meanings, so
                    193:                 * we can't use them.
                    194:                 */
                    195:                ic->ic_ident = i + 2;
                    196:                rv = bus_dmamap_create(icp->icp_dmat, ICP_MAX_XFER,
                    197:                    ICP_MAXSG, ICP_MAX_XFER, 0,
                    198:                    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
                    199:                    &ic->ic_xfer_map);
                    200:                if (rv != 0)
                    201:                        break;
                    202:                icp->icp_nccbs++;
                    203:                icp_ccb_free(icp, ic);
                    204:        }
                    205: #ifdef DIAGNOSTIC
                    206:        if (icp->icp_nccbs != ICP_NCCBS)
1.27      cegger    207:                aprint_error_dev(&icp->icp_dv, "%d/%d CCBs usable\n",
1.1       ad        208:                    icp->icp_nccbs, ICP_NCCBS);
                    209: #endif
                    210:
                    211:        /*
                    212:         * Initalize the controller.
                    213:         */
                    214:        if (!icp_cmd(icp, ICP_SCREENSERVICE, ICP_INIT, 0, 0, 0)) {
1.27      cegger    215:                aprint_error_dev(&icp->icp_dv, "screen service init error %d\n",
                    216:                    icp->icp_status);
1.1       ad        217:                goto bail_out;
                    218:        }
                    219:
                    220:        if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
1.27      cegger    221:                aprint_error_dev(&icp->icp_dv, "cache service init error %d\n",
                    222:                    icp->icp_status);
1.1       ad        223:                goto bail_out;
                    224:        }
                    225:
                    226:        icp_cmd(icp, ICP_CACHESERVICE, ICP_UNFREEZE_IO, 0, 0, 0);
                    227:
                    228:        if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_MOUNT, 0xffff, 1, 0)) {
1.27      cegger    229:                aprint_error_dev(&icp->icp_dv, "cache service mount error %d\n",
                    230:                    icp->icp_status);
1.1       ad        231:                goto bail_out;
                    232:        }
                    233:
                    234:        if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
1.27      cegger    235:                aprint_error_dev(&icp->icp_dv, "cache service post-mount init error %d\n",
                    236:                    icp->icp_status);
1.1       ad        237:                goto bail_out;
                    238:        }
                    239:        cdev_cnt = (u_int16_t)icp->icp_info;
1.8       thorpej   240:        icp->icp_fw_vers = icp->icp_service;
1.1       ad        241:
                    242:        if (!icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_INIT, 0, 0, 0)) {
1.27      cegger    243:                aprint_error_dev(&icp->icp_dv, "raw service init error %d\n",
                    244:                    icp->icp_status);
1.1       ad        245:                goto bail_out;
                    246:        }
                    247:
                    248:        /*
                    249:         * Set/get raw service features (scatter/gather).
                    250:         */
                    251:        feat = 0;
                    252:        if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_SET_FEAT, ICP_SCATTER_GATHER,
                    253:            0, 0))
                    254:                if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_GET_FEAT, 0, 0, 0))
                    255:                        feat = icp->icp_info;
                    256:
                    257:        if ((feat & ICP_SCATTER_GATHER) == 0) {
                    258: #ifdef DIAGNOSTIC
1.27      cegger    259:                aprint_normal_dev(&icp->icp_dv,
                    260:                    "scatter/gather not supported (raw service)\n");
1.1       ad        261: #endif
1.10      thorpej   262:        } else
                    263:                icp->icp_features |= ICP_FEAT_RAWSERVICE;
1.1       ad        264:
                    265:        /*
                    266:         * Set/get cache service features (scatter/gather).
                    267:         */
                    268:        feat = 0;
                    269:        if (icp_cmd(icp, ICP_CACHESERVICE, ICP_SET_FEAT, 0,
                    270:            ICP_SCATTER_GATHER, 0))
                    271:                if (icp_cmd(icp, ICP_CACHESERVICE, ICP_GET_FEAT, 0, 0, 0))
                    272:                        feat = icp->icp_info;
                    273:
                    274:        if ((feat & ICP_SCATTER_GATHER) == 0) {
                    275: #ifdef DIAGNOSTIC
1.27      cegger    276:                aprint_normal_dev(&icp->icp_dv,
                    277:                    "scatter/gather not supported (cache service)\n");
1.1       ad        278: #endif
1.10      thorpej   279:        } else
                    280:                icp->icp_features |= ICP_FEAT_CACHESERVICE;
1.1       ad        281:
                    282:        /*
                    283:         * Pull some information from the board and dump.
                    284:         */
                    285:        if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL, ICP_BOARD_INFO,
                    286:            ICP_INVALID_CHANNEL, sizeof(struct icp_binfo))) {
1.27      cegger    287:                aprint_error_dev(&icp->icp_dv, "unable to retrive board info\n");
1.1       ad        288:                goto bail_out;
                    289:        }
                    290:        memcpy(&binfo, icp->icp_scr, sizeof(binfo));
                    291:
1.27      cegger    292:        aprint_normal_dev(&icp->icp_dv,
                    293:            "model <%s>, firmware <%s>, %d channel(s), %dMB memory\n",
                    294:            binfo.bi_type_string, binfo.bi_raid_string,
1.1       ad        295:            binfo.bi_chan_count, le32toh(binfo.bi_memsize) >> 20);
                    296:
                    297:        /*
                    298:         * Determine the number of devices, and number of openings per
                    299:         * device.
                    300:         */
1.10      thorpej   301:        if (icp->icp_features & ICP_FEAT_CACHESERVICE) {
1.1       ad        302:                for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
                    303:                        if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, j, 0,
                    304:                            0))
                    305:                                continue;
                    306:
                    307:                        icp->icp_cdr[j].cd_size = icp->icp_info;
1.10      thorpej   308:                        if (icp->icp_cdr[j].cd_size != 0)
                    309:                                icp->icp_ndevs++;
1.1       ad        310:
                    311:                        if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, j, 0,
                    312:                            0))
                    313:                                icp->icp_cdr[j].cd_type = icp->icp_info;
                    314:                }
                    315:        }
                    316:
1.10      thorpej   317:        if (icp->icp_features & ICP_FEAT_RAWSERVICE) {
                    318:                icp->icp_nchan = binfo.bi_chan_count;
                    319:                icp->icp_ndevs += icp->icp_nchan;
                    320:        }
1.1       ad        321:
1.10      thorpej   322:        icp_recompute_openings(icp);
1.1       ad        323:
                    324:        /*
                    325:         * Attach SCSI channels.
                    326:         */
1.10      thorpej   327:        if (icp->icp_features & ICP_FEAT_RAWSERVICE) {
1.1       ad        328:                struct icp_ioc_version *iv;
                    329:                struct icp_rawioc *ri;
                    330:                struct icp_getch *gc;
                    331:
                    332:                iv = (struct icp_ioc_version *)icp->icp_scr;
                    333:                iv->iv_version = htole32(ICP_IOC_NEWEST);
                    334:                iv->iv_listents = ICP_MAXBUS;
                    335:                iv->iv_firstchan = 0;
                    336:                iv->iv_lastchan = ICP_MAXBUS - 1;
                    337:                iv->iv_listoffset = htole32(sizeof(*iv));
                    338:
                    339:                if (icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
                    340:                    ICP_IOCHAN_RAW_DESC, ICP_INVALID_CHANNEL,
                    341:                    sizeof(*iv) + ICP_MAXBUS * sizeof(*ri))) {
                    342:                        ri = (struct icp_rawioc *)(iv + 1);
                    343:                        for (j = 0; j < binfo.bi_chan_count; j++, ri++)
                    344:                                icp->icp_bus_id[j] = ri->ri_procid;
                    345:                } else {
                    346:                        /*
                    347:                         * Fall back to the old method.
                    348:                         */
                    349:                        gc = (struct icp_getch *)icp->icp_scr;
                    350:
1.12      mycroft   351:                        for (j = 0; j < binfo.bi_chan_count; j++) {
1.1       ad        352:                                if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
                    353:                                    ICP_SCSI_CHAN_CNT | ICP_L_CTRL_PATTERN,
                    354:                                    ICP_IO_CHANNEL | ICP_INVALID_CHANNEL,
                    355:                                    sizeof(*gc))) {
1.27      cegger    356:                                        aprint_error_dev(&icp->icp_dv,
                    357:                                            "unable to get chan info");
1.1       ad        358:                                        goto bail_out;
                    359:                                }
                    360:                                icp->icp_bus_id[j] = gc->gc_scsiid;
                    361:                        }
                    362:                }
                    363:
                    364:                for (j = 0; j < binfo.bi_chan_count; j++) {
                    365:                        if (icp->icp_bus_id[j] > ICP_MAXID_FC)
                    366:                                icp->icp_bus_id[j] = ICP_MAXID_FC;
                    367:
                    368:                        icpa.icpa_unit = j + ICPA_UNIT_SCSI;
1.13      drochner  369:
1.15      drochner  370:                        locs[ICPCF_UNIT] = j + ICPA_UNIT_SCSI;
1.13      drochner  371:
1.10      thorpej   372:                        icp->icp_children[icpa.icpa_unit] =
1.15      drochner  373:                                config_found_sm_loc(&icp->icp_dv, "icp", locs,
1.16      drochner  374:                                        &icpa, icp_print, config_stdsubmatch);
1.1       ad        375:                }
                    376:        }
                    377:
                    378:        /*
                    379:         * Attach cache devices.
                    380:         */
1.10      thorpej   381:        if (icp->icp_features & ICP_FEAT_CACHESERVICE) {
1.1       ad        382:                for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
                    383:                        if (icp->icp_cdr[j].cd_size == 0)
                    384:                                continue;
1.14      perry     385:
1.1       ad        386:                        icpa.icpa_unit = j;
1.13      drochner  387:
1.15      drochner  388:                        locs[ICPCF_UNIT] = j;
1.13      drochner  389:
1.10      thorpej   390:                        icp->icp_children[icpa.icpa_unit] =
1.15      drochner  391:                            config_found_sm_loc(&icp->icp_dv, "icp", locs,
1.16      drochner  392:                                &icpa, icp_print, config_stdsubmatch);
1.1       ad        393:                }
                    394:        }
                    395:
                    396:        /*
                    397:         * Start the watchdog.
                    398:         */
                    399:        icp_watchdog(icp);
1.8       thorpej   400:
                    401:        /*
                    402:         * Count the controller, and we're done!
                    403:         */
1.24      ad        404:        if (icp_count++ == 0)
                    405:                mutex_init(&icp_ioctl_mutex, MUTEX_DEFAULT, IPL_NONE);
1.8       thorpej   406:
1.1       ad        407:        return (0);
                    408:
                    409:  bail_out:
                    410:        if (state > 4)
                    411:                for (j = 0; j < i; j++)
                    412:                        bus_dmamap_destroy(icp->icp_dmat,
                    413:                            icp->icp_ccbs[j].ic_xfer_map);
                    414:        if (state > 3)
                    415:                free(icp->icp_ccbs, M_DEVBUF);
                    416:        if (state > 2)
                    417:                bus_dmamap_unload(icp->icp_dmat, icp->icp_scr_dmamap);
                    418:        if (state > 1)
                    419:                bus_dmamem_unmap(icp->icp_dmat, icp->icp_scr,
                    420:                    ICP_SCRATCH_SIZE);
                    421:        if (state > 0)
                    422:                bus_dmamem_free(icp->icp_dmat, icp->icp_scr_seg, nsegs);
                    423:        bus_dmamap_destroy(icp->icp_dmat, icp->icp_scr_dmamap);
                    424:
                    425:        return (1);
                    426: }
                    427:
                    428: void
1.10      thorpej   429: icp_register_servicecb(struct icp_softc *icp, int unit,
                    430:     const struct icp_servicecb *cb)
                    431: {
                    432:
                    433:        icp->icp_servicecb[unit] = cb;
                    434: }
                    435:
                    436: void
                    437: icp_rescan(struct icp_softc *icp, int unit)
                    438: {
                    439:        struct icp_attach_args icpa;
                    440:        u_int newsize, newtype;
1.15      drochner  441:        int locs[ICPCF_NLOCS];
1.10      thorpej   442:
                    443:        /*
                    444:         * NOTE: It is very important that the queue be frozen and not
                    445:         * commands running when this is called.  The ioctl mutex must
                    446:         * also be held.
                    447:         */
                    448:
                    449:        KASSERT(icp->icp_qfreeze != 0);
                    450:        KASSERT(icp->icp_running == 0);
                    451:        KASSERT(unit < ICP_MAX_HDRIVES);
                    452:
                    453:        if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, unit, 0, 0)) {
                    454: #ifdef ICP_DEBUG
                    455:                printf("%s: rescan: unit %d ICP_INFO failed -> 0x%04x\n",
1.27      cegger    456:                    device_xname(&icp->icp_dv), unit, icp->icp_status);
1.10      thorpej   457: #endif
                    458:                goto gone;
                    459:        }
                    460:        if ((newsize = icp->icp_info) == 0) {
                    461: #ifdef ICP_DEBUG
                    462:                printf("%s: rescan: unit %d has zero size\n",
1.27.2.1! yamt      463:                    device_xname(&icp->icp_dv), unit);
1.10      thorpej   464: #endif
                    465:  gone:
                    466:                /*
                    467:                 * Host drive is no longer present; detach if a child
                    468:                 * is currently there.
                    469:                 */
                    470:                if (icp->icp_cdr[unit].cd_size != 0)
                    471:                        icp->icp_ndevs--;
                    472:                icp->icp_cdr[unit].cd_size = 0;
                    473:                if (icp->icp_children[unit] != NULL) {
                    474:                        (void) config_detach(icp->icp_children[unit],
                    475:                            DETACH_FORCE);
                    476:                        icp->icp_children[unit] = NULL;
                    477:                }
                    478:                return;
                    479:        }
                    480:
                    481:        if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, unit, 0, 0))
                    482:                newtype = icp->icp_info;
                    483:        else {
                    484: #ifdef ICP_DEBUG
                    485:                printf("%s: rescan: unit %d ICP_DEVTYPE failed\n",
1.27      cegger    486:                    device_xname(&icp->icp_dv), unit);
1.10      thorpej   487: #endif
                    488:                newtype = 0;    /* XXX? */
                    489:        }
                    490:
                    491: #ifdef ICP_DEBUG
                    492:        printf("%s: rescan: unit %d old %u/%u, new %u/%u\n",
1.27      cegger    493:            device_xname(&icp->icp_dv), unit, icp->icp_cdr[unit].cd_size,
1.10      thorpej   494:            icp->icp_cdr[unit].cd_type, newsize, newtype);
                    495: #endif
                    496:
                    497:        /*
                    498:         * If the type or size changed, detach any old child (if it exists)
                    499:         * and attach a new one.
                    500:         */
                    501:        if (icp->icp_children[unit] == NULL ||
                    502:            newsize != icp->icp_cdr[unit].cd_size ||
                    503:            newtype != icp->icp_cdr[unit].cd_type) {
                    504:                if (icp->icp_cdr[unit].cd_size == 0)
                    505:                        icp->icp_ndevs++;
                    506:                icp->icp_cdr[unit].cd_size = newsize;
                    507:                icp->icp_cdr[unit].cd_type = newtype;
                    508:                if (icp->icp_children[unit] != NULL)
                    509:                        (void) config_detach(icp->icp_children[unit],
                    510:                            DETACH_FORCE);
                    511:
                    512:                icpa.icpa_unit = unit;
1.13      drochner  513:
1.15      drochner  514:                locs[ICPCF_UNIT] = unit;
1.13      drochner  515:
                    516:                icp->icp_children[unit] = config_found_sm_loc(&icp->icp_dv,
1.16      drochner  517:                        "icp", locs, &icpa, icp_print, config_stdsubmatch);
1.10      thorpej   518:        }
                    519:
                    520:        icp_recompute_openings(icp);
                    521: }
                    522:
                    523: void
                    524: icp_rescan_all(struct icp_softc *icp)
                    525: {
                    526:        int unit;
                    527:        u_int16_t cdev_cnt;
                    528:
                    529:        /*
                    530:         * This is the old method of rescanning the host drives.  We
                    531:         * start by reinitializing the cache service.
                    532:         */
                    533:        if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
                    534:                printf("%s: unable to re-initialize cache service for rescan\n",
1.27      cegger    535:                    device_xname(&icp->icp_dv));
1.10      thorpej   536:                return;
                    537:        }
                    538:        cdev_cnt = (u_int16_t) icp->icp_info;
                    539:
                    540:        /* For each host drive, do the new-style rescan. */
                    541:        for (unit = 0; unit < cdev_cnt && unit < ICP_MAX_HDRIVES; unit++)
                    542:                icp_rescan(icp, unit);
                    543:
                    544:        /* Now detach anything in the slots after cdev_cnt. */
                    545:        for (; unit < ICP_MAX_HDRIVES; unit++) {
                    546:                if (icp->icp_cdr[unit].cd_size != 0) {
                    547: #ifdef ICP_DEBUG
                    548:                        printf("%s: rescan all: unit %d < new cdev_cnt (%d)\n",
1.27      cegger    549:                            device_xname(&icp->icp_dv), unit, cdev_cnt);
1.10      thorpej   550: #endif
                    551:                        icp->icp_ndevs--;
                    552:                        icp->icp_cdr[unit].cd_size = 0;
                    553:                        if (icp->icp_children[unit] != NULL) {
                    554:                                (void) config_detach(icp->icp_children[unit],
                    555:                                    DETACH_FORCE);
                    556:                                icp->icp_children[unit] = NULL;
                    557:                        }
                    558:                }
                    559:        }
                    560:
                    561:        icp_recompute_openings(icp);
                    562: }
                    563:
                    564: void
                    565: icp_recompute_openings(struct icp_softc *icp)
                    566: {
                    567:        int unit, openings;
                    568:
                    569:        if (icp->icp_ndevs != 0)
                    570:                openings =
                    571:                    (icp->icp_nccbs - ICP_NCCB_RESERVE) / icp->icp_ndevs;
                    572:        else
                    573:                openings = 0;
                    574:        if (openings == icp->icp_openings)
                    575:                return;
                    576:        icp->icp_openings = openings;
                    577:
                    578: #ifdef ICP_DEBUG
                    579:        printf("%s: %d device%s, %d openings per device\n",
1.27      cegger    580:            device_xname(&icp->icp_dv), icp->icp_ndevs,
1.10      thorpej   581:            icp->icp_ndevs == 1 ? "" : "s", icp->icp_openings);
                    582: #endif
                    583:
                    584:        for (unit = 0; unit < ICP_MAX_HDRIVES + ICP_MAXBUS; unit++) {
                    585:                if (icp->icp_children[unit] != NULL)
                    586:                        (*icp->icp_servicecb[unit]->iscb_openings)(
                    587:                            icp->icp_children[unit], icp->icp_openings);
                    588:        }
                    589: }
                    590:
                    591: void
1.1       ad        592: icp_watchdog(void *cookie)
                    593: {
                    594:        struct icp_softc *icp;
                    595:        int s;
                    596:
                    597:        icp = cookie;
                    598:
                    599:        s = splbio();
                    600:        icp_intr(icp);
1.8       thorpej   601:        if (ICP_HAS_WORK(icp))
1.1       ad        602:                icp_ccb_enqueue(icp, NULL);
                    603:        splx(s);
                    604:
                    605:        callout_reset(&icp->icp_wdog_callout, hz * ICP_WATCHDOG_FREQ,
                    606:            icp_watchdog, icp);
                    607: }
                    608:
                    609: int
                    610: icp_print(void *aux, const char *pnp)
                    611: {
                    612:        struct icp_attach_args *icpa;
                    613:        const char *str;
                    614:
                    615:        icpa = (struct icp_attach_args *)aux;
                    616:
                    617:        if (pnp != NULL) {
                    618:                if (icpa->icpa_unit < ICPA_UNIT_SCSI)
                    619:                        str = "block device";
                    620:                else
                    621:                        str = "SCSI channel";
1.6       thorpej   622:                aprint_normal("%s at %s", str, pnp);
1.1       ad        623:        }
1.6       thorpej   624:        aprint_normal(" unit %d", icpa->icpa_unit);
1.1       ad        625:
                    626:        return (UNCONF);
                    627: }
                    628:
                    629: int
1.8       thorpej   630: icp_async_event(struct icp_softc *icp, int service)
1.1       ad        631: {
                    632:
1.8       thorpej   633:        if (service == ICP_SCREENSERVICE) {
                    634:                if (icp->icp_status == ICP_S_MSG_REQUEST) {
                    635:                        /* XXX */
                    636:                }
                    637:        } else {
                    638:                if ((icp->icp_fw_vers & 0xff) >= 0x1a) {
                    639:                        icp->icp_evt.size = 0;
1.19      thorpej   640:                        icp->icp_evt.eu.async.ionode =
                    641:                            device_unit(&icp->icp_dv);
1.8       thorpej   642:                        icp->icp_evt.eu.async.status = icp->icp_status;
                    643:                        /*
                    644:                         * Severity and event string are filled in by the
                    645:                         * hardware interface interrupt handler.
                    646:                         */
1.27      cegger    647:                        printf("%s: %s\n", device_xname(&icp->icp_dv),
1.8       thorpej   648:                            icp->icp_evt.event_string);
                    649:                } else {
                    650:                        icp->icp_evt.size = sizeof(icp->icp_evt.eu.async);
1.19      thorpej   651:                        icp->icp_evt.eu.async.ionode =
                    652:                            device_unit(&icp->icp_dv);
1.8       thorpej   653:                        icp->icp_evt.eu.async.service = service;
                    654:                        icp->icp_evt.eu.async.status = icp->icp_status;
                    655:                        icp->icp_evt.eu.async.info = icp->icp_info;
                    656:                        /* XXXJRT FIX THIS */
1.14      perry     657:                        *(u_int32_t *) icp->icp_evt.eu.async.scsi_coord =
1.8       thorpej   658:                            icp->icp_info2;
                    659:                }
                    660:                icp_store_event(icp, GDT_ES_ASYNC, service, &icp->icp_evt);
                    661:        }
                    662:
                    663:        return (0);
1.1       ad        664: }
                    665:
                    666: int
                    667: icp_intr(void *cookie)
                    668: {
                    669:        struct icp_softc *icp;
                    670:        struct icp_intr_ctx ctx;
                    671:        struct icp_ccb *ic;
                    672:
                    673:        icp = cookie;
                    674:
                    675:        ctx.istatus = (*icp->icp_get_status)(icp);
                    676:        if (!ctx.istatus) {
                    677:                icp->icp_status = ICP_S_NO_STATUS;
                    678:                return (0);
                    679:        }
                    680:
                    681:        (*icp->icp_intr)(icp, &ctx);
                    682:
                    683:        icp->icp_status = ctx.cmd_status;
1.8       thorpej   684:        icp->icp_service = ctx.service;
1.1       ad        685:        icp->icp_info = ctx.info;
                    686:        icp->icp_info2 = ctx.info2;
                    687:
                    688:        switch (ctx.istatus) {
                    689:        case ICP_ASYNCINDEX:
                    690:                icp_async_event(icp, ctx.service);
                    691:                return (1);
                    692:
                    693:        case ICP_SPEZINDEX:
1.27      cegger    694:                aprint_error_dev(&icp->icp_dv, "uninitialized or unknown service (%d/%d)\n",
                    695:                    ctx.info, ctx.info2);
1.8       thorpej   696:                icp->icp_evt.size = sizeof(icp->icp_evt.eu.driver);
1.19      thorpej   697:                icp->icp_evt.eu.driver.ionode = device_unit(&icp->icp_dv);
1.8       thorpej   698:                icp_store_event(icp, GDT_ES_DRIVER, 4, &icp->icp_evt);
1.1       ad        699:                return (1);
                    700:        }
                    701:
                    702:        if ((ctx.istatus - 2) > icp->icp_nccbs)
                    703:                panic("icp_intr: bad command index returned");
                    704:
                    705:        ic = &icp->icp_ccbs[ctx.istatus - 2];
                    706:        ic->ic_status = icp->icp_status;
                    707:
1.8       thorpej   708:        if ((ic->ic_flags & IC_ALLOCED) == 0) {
                    709:                /* XXX ICP's "iir" driver just sends an event here. */
1.1       ad        710:                panic("icp_intr: inactive CCB identified");
1.8       thorpej   711:        }
1.1       ad        712:
1.10      thorpej   713:        /*
                    714:         * Try to protect ourselves from the running command count already
                    715:         * being 0 (e.g. if a polled command times out).
                    716:         */
                    717:        KDASSERT(icp->icp_running != 0);
                    718:        if (--icp->icp_running == 0 &&
                    719:            (icp->icp_flags & ICP_F_WAIT_FREEZE) != 0) {
                    720:                icp->icp_flags &= ~ICP_F_WAIT_FREEZE;
                    721:                wakeup(&icp->icp_qfreeze);
                    722:        }
                    723:
1.1       ad        724:        switch (icp->icp_status) {
                    725:        case ICP_S_BSY:
                    726: #ifdef ICP_DEBUG
1.27      cegger    727:                printf("%s: ICP_S_BSY received\n", device_xname(&icp->icp_dv));
1.1       ad        728: #endif
1.8       thorpej   729:                if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
                    730:                        SIMPLEQ_INSERT_HEAD(&icp->icp_ucmd_queue, ic, ic_chain);
                    731:                else
                    732:                        SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_queue, ic, ic_chain);
1.1       ad        733:                break;
                    734:
                    735:        default:
                    736:                ic->ic_flags |= IC_COMPLETE;
                    737:
                    738:                if ((ic->ic_flags & IC_WAITING) != 0)
                    739:                        wakeup(ic);
                    740:                else if (ic->ic_intr != NULL)
                    741:                        (*ic->ic_intr)(ic);
                    742:
1.8       thorpej   743:                if (ICP_HAS_WORK(icp))
1.1       ad        744:                        icp_ccb_enqueue(icp, NULL);
                    745:
                    746:                break;
                    747:        }
                    748:
                    749:        return (1);
                    750: }
                    751:
1.8       thorpej   752: struct icp_ucmd_ctx {
                    753:        gdt_ucmd_t *iu_ucmd;
                    754:        u_int32_t iu_cnt;
                    755: };
                    756:
                    757: void
                    758: icp_ucmd_intr(struct icp_ccb *ic)
                    759: {
                    760:        struct icp_softc *icp = (void *) ic->ic_dv;
                    761:        struct icp_ucmd_ctx *iu = ic->ic_context;
                    762:        gdt_ucmd_t *ucmd = iu->iu_ucmd;
                    763:
                    764:        ucmd->status = icp->icp_status;
                    765:        ucmd->info = icp->icp_info;
                    766:
                    767:        if (iu->iu_cnt != 0) {
                    768:                bus_dmamap_sync(icp->icp_dmat,
                    769:                    icp->icp_scr_dmamap,
                    770:                    ICP_SCRATCH_UCMD, iu->iu_cnt,
                    771:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
                    772:                memcpy(ucmd->data,
1.23      christos  773:                    (char *)icp->icp_scr + ICP_SCRATCH_UCMD, iu->iu_cnt);
1.8       thorpej   774:        }
                    775:
                    776:        icp->icp_ucmd_ccb = NULL;
                    777:
                    778:        ic->ic_flags |= IC_COMPLETE;
                    779:        wakeup(ic);
                    780: }
                    781:
                    782: /*
                    783:  * NOTE: We assume that it is safe to sleep here!
                    784:  */
1.1       ad        785: int
                    786: icp_cmd(struct icp_softc *icp, u_int8_t service, u_int16_t opcode,
                    787:        u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
                    788: {
                    789:        struct icp_ioctlcmd *icmd;
                    790:        struct icp_cachecmd *cc;
                    791:        struct icp_rawcmd *rc;
                    792:        int retries, rv;
                    793:        struct icp_ccb *ic;
                    794:
                    795:        retries = ICP_RETRIES;
                    796:
                    797:        do {
1.8       thorpej   798:                ic = icp_ccb_alloc_wait(icp);
1.1       ad        799:                memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
                    800:                ic->ic_cmd.cmd_opcode = htole16(opcode);
                    801:
                    802:                switch (service) {
                    803:                case ICP_CACHESERVICE:
                    804:                        if (opcode == ICP_IOCTL) {
                    805:                                icmd = &ic->ic_cmd.cmd_packet.ic;
                    806:                                icmd->ic_subfunc = htole16(arg1);
                    807:                                icmd->ic_channel = htole32(arg2);
                    808:                                icmd->ic_bufsize = htole32(arg3);
                    809:                                icmd->ic_addr =
                    810:                                    htole32(icp->icp_scr_seg[0].ds_addr);
                    811:
                    812:                                bus_dmamap_sync(icp->icp_dmat,
                    813:                                    icp->icp_scr_dmamap, 0, arg3,
                    814:                                    BUS_DMASYNC_PREWRITE |
                    815:                                    BUS_DMASYNC_PREREAD);
                    816:                        } else {
                    817:                                cc = &ic->ic_cmd.cmd_packet.cc;
                    818:                                cc->cc_deviceno = htole16(arg1);
                    819:                                cc->cc_blockno = htole32(arg2);
                    820:                        }
                    821:                        break;
                    822:
                    823:                case ICP_SCSIRAWSERVICE:
                    824:                        rc = &ic->ic_cmd.cmd_packet.rc;
                    825:                        rc->rc_direction = htole32(arg1);
                    826:                        rc->rc_bus = arg2;
                    827:                        rc->rc_target = arg3;
                    828:                        rc->rc_lun = arg3 >> 8;
                    829:                        break;
                    830:                }
                    831:
                    832:                ic->ic_service = service;
                    833:                ic->ic_cmdlen = sizeof(ic->ic_cmd);
                    834:                rv = icp_ccb_poll(icp, ic, 10000);
                    835:
                    836:                switch (service) {
                    837:                case ICP_CACHESERVICE:
                    838:                        if (opcode == ICP_IOCTL) {
                    839:                                bus_dmamap_sync(icp->icp_dmat,
                    840:                                    icp->icp_scr_dmamap, 0, arg3,
                    841:                                    BUS_DMASYNC_POSTWRITE |
                    842:                                    BUS_DMASYNC_POSTREAD);
                    843:                        }
                    844:                        break;
                    845:                }
                    846:
                    847:                icp_ccb_free(icp, ic);
                    848:        } while (rv != 0 && --retries > 0);
                    849:
                    850:        return (icp->icp_status == ICP_S_OK);
                    851: }
                    852:
1.8       thorpej   853: int
                    854: icp_ucmd(struct icp_softc *icp, gdt_ucmd_t *ucmd)
                    855: {
                    856:        struct icp_ccb *ic;
                    857:        struct icp_ucmd_ctx iu;
                    858:        u_int32_t cnt;
                    859:        int error;
                    860:
                    861:        if (ucmd->service == ICP_CACHESERVICE) {
                    862:                if (ucmd->command.cmd_opcode == ICP_IOCTL) {
                    863:                        cnt = ucmd->command.cmd_packet.ic.ic_bufsize;
                    864:                        if (cnt > GDT_SCRATCH_SZ) {
1.27      cegger    865:                                aprint_error_dev(&icp->icp_dv, "scratch buffer too small (%d/%d)\n",
                    866:                                    GDT_SCRATCH_SZ, cnt);
1.8       thorpej   867:                                return (EINVAL);
                    868:                        }
                    869:                } else {
                    870:                        cnt = ucmd->command.cmd_packet.cc.cc_blockcnt *
                    871:                            ICP_SECTOR_SIZE;
                    872:                        if (cnt > GDT_SCRATCH_SZ) {
1.27      cegger    873:                                aprint_error_dev(&icp->icp_dv, "scratch buffer too small (%d/%d)\n",
                    874:                                    GDT_SCRATCH_SZ, cnt);
1.8       thorpej   875:                                return (EINVAL);
                    876:                        }
                    877:                }
                    878:        } else {
                    879:                cnt = ucmd->command.cmd_packet.rc.rc_sdlen +
                    880:                    ucmd->command.cmd_packet.rc.rc_sense_len;
                    881:                if (cnt > GDT_SCRATCH_SZ) {
1.27      cegger    882:                        aprint_error_dev(&icp->icp_dv, "scratch buffer too small (%d/%d)\n",
                    883:                            GDT_SCRATCH_SZ, cnt);
1.8       thorpej   884:                        return (EINVAL);
                    885:                }
                    886:        }
                    887:
                    888:        iu.iu_ucmd = ucmd;
                    889:        iu.iu_cnt = cnt;
                    890:
                    891:        ic = icp_ccb_alloc_wait(icp);
                    892:        memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
                    893:        ic->ic_cmd.cmd_opcode = htole16(ucmd->command.cmd_opcode);
                    894:
                    895:        if (ucmd->service == ICP_CACHESERVICE) {
                    896:                if (ucmd->command.cmd_opcode == ICP_IOCTL) {
                    897:                        struct icp_ioctlcmd *icmd, *uicmd;
                    898:
                    899:                        icmd = &ic->ic_cmd.cmd_packet.ic;
                    900:                        uicmd = &ucmd->command.cmd_packet.ic;
                    901:
                    902:                        icmd->ic_subfunc = htole16(uicmd->ic_subfunc);
                    903:                        icmd->ic_channel = htole32(uicmd->ic_channel);
                    904:                        icmd->ic_bufsize = htole32(uicmd->ic_bufsize);
                    905:                        icmd->ic_addr =
                    906:                            htole32(icp->icp_scr_seg[0].ds_addr +
                    907:                                    ICP_SCRATCH_UCMD);
                    908:                } else {
                    909:                        struct icp_cachecmd *cc, *ucc;
                    910:
                    911:                        cc = &ic->ic_cmd.cmd_packet.cc;
                    912:                        ucc = &ucmd->command.cmd_packet.cc;
                    913:
                    914:                        cc->cc_deviceno = htole16(ucc->cc_deviceno);
                    915:                        cc->cc_blockno = htole32(ucc->cc_blockno);
                    916:                        cc->cc_blockcnt = htole32(ucc->cc_blockcnt);
                    917:                        cc->cc_addr = htole32(0xffffffffU);
                    918:                        cc->cc_nsgent = htole32(1);
                    919:                        cc->cc_sg[0].sg_addr =
                    920:                            htole32(icp->icp_scr_seg[0].ds_addr +
                    921:                                    ICP_SCRATCH_UCMD);
                    922:                        cc->cc_sg[0].sg_len = htole32(cnt);
                    923:                }
                    924:        } else {
                    925:                struct icp_rawcmd *rc, *urc;
                    926:
                    927:                rc = &ic->ic_cmd.cmd_packet.rc;
                    928:                urc = &ucmd->command.cmd_packet.rc;
                    929:
                    930:                rc->rc_direction = htole32(urc->rc_direction);
                    931:                rc->rc_sdata = htole32(0xffffffffU);
                    932:                rc->rc_sdlen = htole32(urc->rc_sdlen);
                    933:                rc->rc_clen = htole32(urc->rc_clen);
                    934:                memcpy(rc->rc_cdb, urc->rc_cdb, sizeof(rc->rc_cdb));
                    935:                rc->rc_target = urc->rc_target;
                    936:                rc->rc_lun = urc->rc_lun;
                    937:                rc->rc_bus = urc->rc_bus;
                    938:                rc->rc_sense_len = htole32(urc->rc_sense_len);
                    939:                rc->rc_sense_addr =
                    940:                    htole32(icp->icp_scr_seg[0].ds_addr +
                    941:                            ICP_SCRATCH_UCMD + urc->rc_sdlen);
                    942:                rc->rc_nsgent = htole32(1);
                    943:                rc->rc_sg[0].sg_addr =
                    944:                    htole32(icp->icp_scr_seg[0].ds_addr + ICP_SCRATCH_UCMD);
                    945:                rc->rc_sg[0].sg_len = htole32(cnt - urc->rc_sense_len);
                    946:        }
                    947:
                    948:        ic->ic_service = ucmd->service;
                    949:        ic->ic_cmdlen = sizeof(ic->ic_cmd);
                    950:        ic->ic_context = &iu;
                    951:
                    952:        /*
                    953:         * XXX What units are ucmd->timeout in?  Until we know, we
                    954:         * XXX just pull a number out of thin air.
                    955:         */
                    956:        if (__predict_false((error = icp_ccb_wait_user(icp, ic, 30000)) != 0))
1.27      cegger    957:                aprint_error_dev(&icp->icp_dv, "error %d waiting for ucmd to complete\n",
                    958:                    error);
1.8       thorpej   959:
                    960:        /* icp_ucmd_intr() has updated ucmd. */
                    961:        icp_ccb_free(icp, ic);
                    962:
                    963:        return (error);
                    964: }
                    965:
1.1       ad        966: struct icp_ccb *
                    967: icp_ccb_alloc(struct icp_softc *icp)
                    968: {
                    969:        struct icp_ccb *ic;
                    970:        int s;
                    971:
                    972:        s = splbio();
1.8       thorpej   973:        if (__predict_false((ic =
                    974:                             SIMPLEQ_FIRST(&icp->icp_ccb_freelist)) == NULL)) {
                    975:                splx(s);
                    976:                return (NULL);
                    977:        }
                    978:        SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic_chain);
                    979:        splx(s);
                    980:
                    981:        ic->ic_flags = IC_ALLOCED;
                    982:        return (ic);
                    983: }
                    984:
                    985: struct icp_ccb *
                    986: icp_ccb_alloc_wait(struct icp_softc *icp)
                    987: {
                    988:        struct icp_ccb *ic;
                    989:        int s;
                    990:
                    991:        s = splbio();
                    992:        while ((ic = SIMPLEQ_FIRST(&icp->icp_ccb_freelist)) == NULL) {
                    993:                icp->icp_flags |= ICP_F_WAIT_CCB;
                    994:                (void) tsleep(&icp->icp_ccb_freelist, PRIBIO, "icpccb", 0);
                    995:        }
1.2       lukem     996:        SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic_chain);
1.1       ad        997:        splx(s);
                    998:
                    999:        ic->ic_flags = IC_ALLOCED;
                   1000:        return (ic);
                   1001: }
                   1002:
                   1003: void
                   1004: icp_ccb_free(struct icp_softc *icp, struct icp_ccb *ic)
                   1005: {
                   1006:        int s;
                   1007:
                   1008:        s = splbio();
                   1009:        ic->ic_flags = 0;
                   1010:        ic->ic_intr = NULL;
                   1011:        SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_freelist, ic, ic_chain);
1.8       thorpej  1012:        if (__predict_false((icp->icp_flags & ICP_F_WAIT_CCB) != 0)) {
                   1013:                icp->icp_flags &= ~ICP_F_WAIT_CCB;
                   1014:                wakeup(&icp->icp_ccb_freelist);
                   1015:        }
1.1       ad       1016:        splx(s);
                   1017: }
                   1018:
                   1019: void
                   1020: icp_ccb_enqueue(struct icp_softc *icp, struct icp_ccb *ic)
                   1021: {
                   1022:        int s;
                   1023:
                   1024:        s = splbio();
                   1025:
1.8       thorpej  1026:        if (ic != NULL) {
                   1027:                if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
                   1028:                        SIMPLEQ_INSERT_TAIL(&icp->icp_ucmd_queue, ic, ic_chain);
                   1029:                else
                   1030:                        SIMPLEQ_INSERT_TAIL(&icp->icp_ccb_queue, ic, ic_chain);
                   1031:        }
                   1032:
1.10      thorpej  1033:        for (; icp->icp_qfreeze == 0;) {
1.8       thorpej  1034:                if (__predict_false((ic =
                   1035:                            SIMPLEQ_FIRST(&icp->icp_ucmd_queue)) != NULL)) {
                   1036:                        struct icp_ucmd_ctx *iu = ic->ic_context;
                   1037:                        gdt_ucmd_t *ucmd = iu->iu_ucmd;
1.1       ad       1038:
1.8       thorpej  1039:                        /*
                   1040:                         * All user-generated commands share the same
                   1041:                         * scratch space, so if one is already running,
                   1042:                         * we have to stall the command queue.
                   1043:                         */
                   1044:                        if (icp->icp_ucmd_ccb != NULL)
                   1045:                                break;
1.9       thorpej  1046:                        if ((*icp->icp_test_busy)(icp))
                   1047:                                break;
1.8       thorpej  1048:                        icp->icp_ucmd_ccb = ic;
                   1049:
                   1050:                        if (iu->iu_cnt != 0) {
1.23      christos 1051:                                memcpy((char *)icp->icp_scr + ICP_SCRATCH_UCMD,
1.8       thorpej  1052:                                    ucmd->data, iu->iu_cnt);
                   1053:                                bus_dmamap_sync(icp->icp_dmat,
                   1054:                                    icp->icp_scr_dmamap,
                   1055:                                    ICP_SCRATCH_UCMD, iu->iu_cnt,
                   1056:                                    BUS_DMASYNC_PREREAD |
                   1057:                                    BUS_DMASYNC_PREWRITE);
                   1058:                        }
1.9       thorpej  1059:                } else if (__predict_true((ic =
                   1060:                                SIMPLEQ_FIRST(&icp->icp_ccb_queue)) != NULL)) {
                   1061:                        if ((*icp->icp_test_busy)(icp))
                   1062:                                break;
                   1063:                } else {
                   1064:                        /* no command found */
1.1       ad       1065:                        break;
1.9       thorpej  1066:                }
1.1       ad       1067:                icp_ccb_submit(icp, ic);
1.8       thorpej  1068:                if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
                   1069:                        SIMPLEQ_REMOVE_HEAD(&icp->icp_ucmd_queue, ic_chain);
                   1070:                else
                   1071:                        SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_queue, ic_chain);
1.1       ad       1072:        }
                   1073:
                   1074:        splx(s);
                   1075: }
                   1076:
                   1077: int
                   1078: icp_ccb_map(struct icp_softc *icp, struct icp_ccb *ic, void *data, int size,
                   1079:            int dir)
                   1080: {
                   1081:        struct icp_sg *sg;
                   1082:        int nsegs, i, rv;
                   1083:        bus_dmamap_t xfer;
                   1084:
                   1085:        xfer = ic->ic_xfer_map;
                   1086:
                   1087:        rv = bus_dmamap_load(icp->icp_dmat, xfer, data, size, NULL,
                   1088:            BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
                   1089:            ((dir & IC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
                   1090:        if (rv != 0)
                   1091:                return (rv);
                   1092:
                   1093:        nsegs = xfer->dm_nsegs;
                   1094:        ic->ic_xfer_size = size;
                   1095:        ic->ic_nsgent = nsegs;
                   1096:        ic->ic_flags |= dir;
                   1097:        sg = ic->ic_sg;
                   1098:
                   1099:        if (sg != NULL) {
                   1100:                for (i = 0; i < nsegs; i++, sg++) {
                   1101:                        sg->sg_addr = htole32(xfer->dm_segs[i].ds_addr);
                   1102:                        sg->sg_len = htole32(xfer->dm_segs[i].ds_len);
                   1103:                }
                   1104:        } else if (nsegs > 1)
1.4       provos   1105:                panic("icp_ccb_map: no SG list specified, but nsegs > 1");
1.1       ad       1106:
                   1107:        if ((dir & IC_XFER_OUT) != 0)
                   1108:                i = BUS_DMASYNC_PREWRITE;
                   1109:        else /* if ((dir & IC_XFER_IN) != 0) */
                   1110:                i = BUS_DMASYNC_PREREAD;
                   1111:
                   1112:        bus_dmamap_sync(icp->icp_dmat, xfer, 0, ic->ic_xfer_size, i);
                   1113:        return (0);
                   1114: }
                   1115:
                   1116: void
                   1117: icp_ccb_unmap(struct icp_softc *icp, struct icp_ccb *ic)
                   1118: {
                   1119:        int i;
                   1120:
                   1121:        if ((ic->ic_flags & IC_XFER_OUT) != 0)
                   1122:                i = BUS_DMASYNC_POSTWRITE;
                   1123:        else /* if ((ic->ic_flags & IC_XFER_IN) != 0) */
                   1124:                i = BUS_DMASYNC_POSTREAD;
                   1125:
                   1126:        bus_dmamap_sync(icp->icp_dmat, ic->ic_xfer_map, 0, ic->ic_xfer_size, i);
                   1127:        bus_dmamap_unload(icp->icp_dmat, ic->ic_xfer_map);
                   1128: }
                   1129:
                   1130: int
                   1131: icp_ccb_poll(struct icp_softc *icp, struct icp_ccb *ic, int timo)
                   1132: {
1.10      thorpej  1133:        int s, rv;
                   1134:
                   1135:        s = splbio();
1.1       ad       1136:
                   1137:        for (timo = ICP_BUSY_WAIT_MS * 100; timo != 0; timo--) {
                   1138:                if (!(*icp->icp_test_busy)(icp))
                   1139:                        break;
                   1140:                DELAY(10);
                   1141:        }
                   1142:        if (timo == 0) {
1.27      cegger   1143:                printf("%s: submit: busy\n", device_xname(&icp->icp_dv));
1.1       ad       1144:                return (EAGAIN);
                   1145:        }
                   1146:
                   1147:        icp_ccb_submit(icp, ic);
                   1148:
1.10      thorpej  1149:        if (cold) {
                   1150:                for (timo *= 10; timo != 0; timo--) {
                   1151:                        DELAY(100);
                   1152:                        icp_intr(icp);
                   1153:                        if ((ic->ic_flags & IC_COMPLETE) != 0)
                   1154:                                break;
                   1155:                }
                   1156:        } else {
                   1157:                ic->ic_flags |= IC_WAITING;
                   1158:                while ((ic->ic_flags & IC_COMPLETE) == 0) {
                   1159:                        if ((rv = tsleep(ic, PRIBIO, "icpwccb",
                   1160:                                         mstohz(timo))) != 0) {
                   1161:                                timo = 0;
                   1162:                                break;
                   1163:                        }
                   1164:                }
1.1       ad       1165:        }
                   1166:
                   1167:        if (timo != 0) {
                   1168:                if (ic->ic_status != ICP_S_OK) {
                   1169: #ifdef ICP_DEBUG
                   1170:                        printf("%s: request failed; status=0x%04x\n",
1.27      cegger   1171:                            device_xname(&icp->icp_dv), ic->ic_status);
1.1       ad       1172: #endif
                   1173:                        rv = EIO;
                   1174:                } else
                   1175:                        rv = 0;
                   1176:        } else {
1.27      cegger   1177:                aprint_error_dev(&icp->icp_dv, "command timed out\n");
1.1       ad       1178:                rv = EIO;
                   1179:        }
                   1180:
                   1181:        while ((*icp->icp_test_busy)(icp) != 0)
                   1182:                DELAY(10);
                   1183:
1.10      thorpej  1184:        splx(s);
                   1185:
1.1       ad       1186:        return (rv);
                   1187: }
                   1188:
                   1189: int
                   1190: icp_ccb_wait(struct icp_softc *icp, struct icp_ccb *ic, int timo)
                   1191: {
                   1192:        int s, rv;
                   1193:
                   1194:        ic->ic_flags |= IC_WAITING;
                   1195:
                   1196:        s = splbio();
                   1197:        icp_ccb_enqueue(icp, ic);
1.8       thorpej  1198:        while ((ic->ic_flags & IC_COMPLETE) == 0) {
                   1199:                if ((rv = tsleep(ic, PRIBIO, "icpwccb", mstohz(timo))) != 0) {
                   1200:                        splx(s);
                   1201:                        return (rv);
                   1202:                }
1.1       ad       1203:        }
                   1204:        splx(s);
                   1205:
                   1206:        if (ic->ic_status != ICP_S_OK) {
1.27      cegger   1207:                aprint_error_dev(&icp->icp_dv, "command failed; status=%x\n",
1.1       ad       1208:                    ic->ic_status);
                   1209:                return (EIO);
                   1210:        }
                   1211:
                   1212:        return (0);
                   1213: }
                   1214:
1.8       thorpej  1215: int
                   1216: icp_ccb_wait_user(struct icp_softc *icp, struct icp_ccb *ic, int timo)
                   1217: {
                   1218:        int s, rv;
                   1219:
                   1220:        ic->ic_dv = &icp->icp_dv;
                   1221:        ic->ic_intr = icp_ucmd_intr;
                   1222:        ic->ic_flags |= IC_UCMD;
                   1223:
                   1224:        s = splbio();
                   1225:        icp_ccb_enqueue(icp, ic);
                   1226:        while ((ic->ic_flags & IC_COMPLETE) == 0) {
                   1227:                if ((rv = tsleep(ic, PRIBIO, "icpwuccb", mstohz(timo))) != 0) {
                   1228:                        splx(s);
                   1229:                        return (rv);
                   1230:                }
                   1231:        }
                   1232:        splx(s);
                   1233:
                   1234:        return (0);
                   1235: }
                   1236:
1.1       ad       1237: void
                   1238: icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic)
                   1239: {
                   1240:
                   1241:        ic->ic_cmdlen = (ic->ic_cmdlen + 3) & ~3;
                   1242:
                   1243:        (*icp->icp_set_sema0)(icp);
                   1244:        DELAY(10);
                   1245:
                   1246:        ic->ic_cmd.cmd_boardnode = htole32(ICP_LOCALBOARD);
                   1247:        ic->ic_cmd.cmd_cmdindex = htole32(ic->ic_ident);
                   1248:
1.10      thorpej  1249:        icp->icp_running++;
                   1250:
1.1       ad       1251:        (*icp->icp_copy_cmd)(icp, ic);
                   1252:        (*icp->icp_release_event)(icp, ic);
1.10      thorpej  1253: }
                   1254:
                   1255: int
                   1256: icp_freeze(struct icp_softc *icp)
                   1257: {
                   1258:        int s, error = 0;
                   1259:
                   1260:        s = splbio();
                   1261:        if (icp->icp_qfreeze++ == 0) {
                   1262:                while (icp->icp_running != 0) {
                   1263:                        icp->icp_flags |= ICP_F_WAIT_FREEZE;
                   1264:                        error = tsleep(&icp->icp_qfreeze, PRIBIO|PCATCH,
                   1265:                            "icpqfrz", 0);
                   1266:                        if (error != 0 && --icp->icp_qfreeze == 0 &&
                   1267:                            ICP_HAS_WORK(icp)) {
                   1268:                                icp_ccb_enqueue(icp, NULL);
                   1269:                                break;
                   1270:                        }
                   1271:                }
                   1272:        }
                   1273:        splx(s);
                   1274:
                   1275:        return (error);
                   1276: }
                   1277:
                   1278: void
                   1279: icp_unfreeze(struct icp_softc *icp)
                   1280: {
                   1281:        int s;
                   1282:
                   1283:        s = splbio();
                   1284:        KDASSERT(icp->icp_qfreeze != 0);
                   1285:        if (--icp->icp_qfreeze == 0 && ICP_HAS_WORK(icp))
                   1286:                icp_ccb_enqueue(icp, NULL);
                   1287:        splx(s);
1.8       thorpej  1288: }
                   1289:
                   1290: /* XXX Global - should be per-controller? XXX */
                   1291: static gdt_evt_str icp_event_buffer[ICP_MAX_EVENTS];
                   1292: static int icp_event_oldidx;
                   1293: static int icp_event_lastidx;
                   1294:
                   1295: gdt_evt_str *
1.22      christos 1296: icp_store_event(struct icp_softc *icp, u_int16_t source, u_int16_t idx,
1.8       thorpej  1297:     gdt_evt_data *evt)
                   1298: {
                   1299:        gdt_evt_str *e;
                   1300:
                   1301:        /* no source == no event */
                   1302:        if (source == 0)
                   1303:                return (NULL);
                   1304:
                   1305:        e = &icp_event_buffer[icp_event_lastidx];
                   1306:        if (e->event_source == source && e->event_idx == idx &&
                   1307:            ((evt->size != 0 && e->event_data.size != 0 &&
                   1308:              memcmp(&e->event_data.eu, &evt->eu, evt->size) == 0) ||
                   1309:             (evt->size == 0 && e->event_data.size == 0 &&
                   1310:              strcmp((char *) e->event_data.event_string,
                   1311:                     (char *) evt->event_string) == 0))) {
1.20      kardel   1312:                e->last_stamp = time_second;
1.8       thorpej  1313:                e->same_count++;
                   1314:        } else {
                   1315:                if (icp_event_buffer[icp_event_lastidx].event_source != 0) {
                   1316:                        icp_event_lastidx++;
                   1317:                        if (icp_event_lastidx == ICP_MAX_EVENTS)
                   1318:                                icp_event_lastidx = 0;
                   1319:                        if (icp_event_lastidx == icp_event_oldidx) {
                   1320:                                icp_event_oldidx++;
                   1321:                                if (icp_event_oldidx == ICP_MAX_EVENTS)
                   1322:                                        icp_event_oldidx = 0;
                   1323:                        }
                   1324:                }
                   1325:                e = &icp_event_buffer[icp_event_lastidx];
                   1326:                e->event_source = source;
                   1327:                e->event_idx = idx;
1.20      kardel   1328:                e->first_stamp = e->last_stamp = time_second;
1.8       thorpej  1329:                e->same_count = 1;
                   1330:                e->event_data = *evt;
                   1331:                e->application = 0;
                   1332:        }
                   1333:        return (e);
                   1334: }
                   1335:
                   1336: int
1.22      christos 1337: icp_read_event(struct icp_softc *icp, int handle, gdt_evt_str *estr)
1.8       thorpej  1338: {
                   1339:        gdt_evt_str *e;
                   1340:        int eindex, s;
                   1341:
                   1342:        s = splbio();
                   1343:
                   1344:        if (handle == -1)
                   1345:                eindex = icp_event_oldidx;
                   1346:        else
                   1347:                eindex = handle;
                   1348:
                   1349:        estr->event_source = 0;
                   1350:
                   1351:        if (eindex < 0 || eindex >= ICP_MAX_EVENTS) {
                   1352:                splx(s);
                   1353:                return (eindex);
                   1354:        }
                   1355:
                   1356:        e = &icp_event_buffer[eindex];
                   1357:        if (e->event_source != 0) {
                   1358:                if (eindex != icp_event_lastidx) {
                   1359:                        eindex++;
                   1360:                        if (eindex == ICP_MAX_EVENTS)
                   1361:                                eindex = 0;
                   1362:                } else
                   1363:                        eindex = -1;
                   1364:                memcpy(estr, e, sizeof(gdt_evt_str));
                   1365:        }
                   1366:
                   1367:        splx(s);
                   1368:
                   1369:        return (eindex);
                   1370: }
                   1371:
                   1372: void
1.22      christos 1373: icp_readapp_event(struct icp_softc *icp, u_int8_t application,
1.8       thorpej  1374:     gdt_evt_str *estr)
                   1375: {
                   1376:        gdt_evt_str *e;
                   1377:        int found = 0, eindex, s;
                   1378:
                   1379:        s = splbio();
                   1380:
                   1381:        eindex = icp_event_oldidx;
                   1382:        for (;;) {
                   1383:                e = &icp_event_buffer[eindex];
                   1384:                if (e->event_source == 0)
                   1385:                        break;
                   1386:                if ((e->application & application) == 0) {
                   1387:                        e->application |= application;
                   1388:                        found = 1;
                   1389:                        break;
                   1390:                }
                   1391:                if (eindex == icp_event_lastidx)
                   1392:                        break;
                   1393:                eindex++;
                   1394:                if (eindex == ICP_MAX_EVENTS)
                   1395:                        eindex = 0;
                   1396:        }
                   1397:        if (found)
                   1398:                memcpy(estr, e, sizeof(gdt_evt_str));
                   1399:        else
                   1400:                estr->event_source = 0;
                   1401:
                   1402:        splx(s);
                   1403: }
                   1404:
                   1405: void
1.22      christos 1406: icp_clear_events(struct icp_softc *icp)
1.8       thorpej  1407: {
                   1408:        int s;
                   1409:
                   1410:        s = splbio();
                   1411:        icp_event_oldidx = icp_event_lastidx = 0;
                   1412:        memset(icp_event_buffer, 0, sizeof(icp_event_buffer));
                   1413:        splx(s);
1.1       ad       1414: }

CVSweb <webmaster@jp.NetBSD.org>