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