1 | /* $NetBSD: arcmsr.c,v 1.36 2016/06/19 21:12:44 dholland Exp $ */ |
2 | /* $OpenBSD: arc.c,v 1.68 2007/10/27 03:28:27 dlg Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 2007, 2008 Juan Romero Pardines <xtraeme@netbsd.org> |
6 | * Copyright (c) 2006 David Gwynne <dlg@openbsd.org> |
7 | * |
8 | * Permission to use, copy, modify, and distribute this software for any |
9 | * purpose with or without fee is hereby granted, provided that the above |
10 | * copyright notice and this permission notice appear in all copies. |
11 | * |
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
19 | */ |
20 | |
21 | #include "bio.h" |
22 | |
23 | #include <sys/cdefs.h> |
24 | __KERNEL_RCSID(0, "$NetBSD: arcmsr.c,v 1.36 2016/06/19 21:12:44 dholland Exp $" ); |
25 | |
26 | #include <sys/param.h> |
27 | #include <sys/buf.h> |
28 | #include <sys/kernel.h> |
29 | #include <sys/malloc.h> |
30 | #include <sys/device.h> |
31 | #include <sys/kmem.h> |
32 | #include <sys/kthread.h> |
33 | #include <sys/mutex.h> |
34 | #include <sys/condvar.h> |
35 | #include <sys/rwlock.h> |
36 | |
37 | #if NBIO > 0 |
38 | #include <sys/ioctl.h> |
39 | #include <dev/biovar.h> |
40 | #endif |
41 | |
42 | #include <dev/pci/pcireg.h> |
43 | #include <dev/pci/pcivar.h> |
44 | #include <dev/pci/pcidevs.h> |
45 | |
46 | #include <dev/scsipi/scsipi_all.h> |
47 | #include <dev/scsipi/scsi_all.h> |
48 | #include <dev/scsipi/scsiconf.h> |
49 | |
50 | #include <dev/sysmon/sysmonvar.h> |
51 | |
52 | #include <sys/bus.h> |
53 | |
54 | #include <dev/pci/arcmsrvar.h> |
55 | |
56 | /* #define ARC_DEBUG */ |
57 | #ifdef ARC_DEBUG |
58 | #define ARC_D_INIT (1<<0) |
59 | #define ARC_D_RW (1<<1) |
60 | #define ARC_D_DB (1<<2) |
61 | |
62 | int arcdebug = 0; |
63 | |
64 | #define DPRINTF(p...) do { if (arcdebug) printf(p); } while (0) |
65 | #define DNPRINTF(n, p...) do { if ((n) & arcdebug) printf(p); } while (0) |
66 | |
67 | #else |
68 | #define DPRINTF(p, ...) /* p */ |
69 | #define DNPRINTF(n, p, ...) /* n, p */ |
70 | #endif |
71 | |
72 | /* |
73 | * the fw header must always equal this. |
74 | */ |
75 | #if NBIO > 0 |
76 | static struct arc_fw_hdr arc_fw_hdr = { 0x5e, 0x01, 0x61 }; |
77 | #endif |
78 | |
79 | /* |
80 | * autoconf(9) glue. |
81 | */ |
82 | static int arc_match(device_t, cfdata_t, void *); |
83 | static void arc_attach(device_t, device_t, void *); |
84 | static int arc_detach(device_t, int); |
85 | static bool arc_shutdown(device_t, int); |
86 | static int arc_intr(void *); |
87 | static void arc_minphys(struct buf *); |
88 | |
89 | CFATTACH_DECL_NEW(arcmsr, sizeof(struct arc_softc), |
90 | arc_match, arc_attach, arc_detach, NULL); |
91 | |
92 | /* |
93 | * bio(4) and sysmon_envsys(9) glue. |
94 | */ |
95 | #if NBIO > 0 |
96 | static int arc_bioctl(device_t, u_long, void *); |
97 | static int arc_bio_inq(struct arc_softc *, struct bioc_inq *); |
98 | static int arc_bio_vol(struct arc_softc *, struct bioc_vol *); |
99 | static int arc_bio_disk_volume(struct arc_softc *, struct bioc_disk *); |
100 | static int arc_bio_disk_novol(struct arc_softc *, struct bioc_disk *); |
101 | static void arc_bio_disk_filldata(struct arc_softc *, struct bioc_disk *, |
102 | struct arc_fw_diskinfo *, int); |
103 | static int arc_bio_alarm(struct arc_softc *, struct bioc_alarm *); |
104 | static int arc_bio_alarm_state(struct arc_softc *, struct bioc_alarm *); |
105 | static int arc_bio_getvol(struct arc_softc *, int, |
106 | struct arc_fw_volinfo *); |
107 | static int arc_bio_setstate(struct arc_softc *, struct bioc_setstate *); |
108 | static int arc_bio_volops(struct arc_softc *, struct bioc_volops *); |
109 | static void arc_create_sensors(void *); |
110 | static void arc_refresh_sensors(struct sysmon_envsys *, envsys_data_t *); |
111 | static int arc_fw_parse_status_code(struct arc_softc *, uint8_t *); |
112 | #endif |
113 | |
114 | /* |
115 | * interface for scsi midlayer to talk to. |
116 | */ |
117 | static void arc_scsi_cmd(struct scsipi_channel *, scsipi_adapter_req_t, |
118 | void *); |
119 | |
120 | /* |
121 | * code to deal with getting bits in and out of the bus space. |
122 | */ |
123 | static uint32_t arc_read(struct arc_softc *, bus_size_t); |
124 | static void arc_read_region(struct arc_softc *, bus_size_t, void *, |
125 | size_t); |
126 | static void arc_write(struct arc_softc *, bus_size_t, uint32_t); |
127 | #if NBIO > 0 |
128 | static void arc_write_region(struct arc_softc *, bus_size_t, void *, |
129 | size_t); |
130 | #endif |
131 | static int arc_wait_eq(struct arc_softc *, bus_size_t, uint32_t, |
132 | uint32_t); |
133 | #ifdef unused |
134 | static int arc_wait_ne(struct arc_softc *, bus_size_t, uint32_t, |
135 | uint32_t); |
136 | #endif |
137 | static int arc_msg0(struct arc_softc *, uint32_t); |
138 | static struct arc_dmamem *arc_dmamem_alloc(struct arc_softc *, size_t); |
139 | static void arc_dmamem_free(struct arc_softc *, |
140 | struct arc_dmamem *); |
141 | |
142 | static int arc_alloc_ccbs(device_t); |
143 | static struct arc_ccb *arc_get_ccb(struct arc_softc *); |
144 | static void arc_put_ccb(struct arc_softc *, struct arc_ccb *); |
145 | static int arc_load_xs(struct arc_ccb *); |
146 | static int arc_complete(struct arc_softc *, struct arc_ccb *, int); |
147 | static void arc_scsi_cmd_done(struct arc_softc *, struct arc_ccb *, |
148 | uint32_t); |
149 | |
150 | /* |
151 | * real stuff for dealing with the hardware. |
152 | */ |
153 | static int arc_map_pci_resources(device_t, struct pci_attach_args *); |
154 | static void arc_unmap_pci_resources(struct arc_softc *); |
155 | static int arc_query_firmware(device_t); |
156 | |
157 | /* |
158 | * stuff to do messaging via the doorbells. |
159 | */ |
160 | #if NBIO > 0 |
161 | static void arc_lock(struct arc_softc *); |
162 | static void arc_unlock(struct arc_softc *); |
163 | static void arc_wait(struct arc_softc *); |
164 | static uint8_t arc_msg_cksum(void *, uint16_t); |
165 | static int arc_msgbuf(struct arc_softc *, void *, size_t, void *, size_t); |
166 | #endif |
167 | |
168 | #define arc_push(_s, _r) arc_write((_s), ARC_REG_POST_QUEUE, (_r)) |
169 | #define arc_pop(_s) arc_read((_s), ARC_REG_REPLY_QUEUE) |
170 | |
171 | static int |
172 | arc_match(device_t parent, cfdata_t match, void *aux) |
173 | { |
174 | struct pci_attach_args *pa = aux; |
175 | |
176 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ARECA) { |
177 | switch (PCI_PRODUCT(pa->pa_id)) { |
178 | case PCI_PRODUCT_ARECA_ARC1110: |
179 | case PCI_PRODUCT_ARECA_ARC1120: |
180 | case PCI_PRODUCT_ARECA_ARC1130: |
181 | case PCI_PRODUCT_ARECA_ARC1160: |
182 | case PCI_PRODUCT_ARECA_ARC1170: |
183 | case PCI_PRODUCT_ARECA_ARC1200: |
184 | case PCI_PRODUCT_ARECA_ARC1202: |
185 | case PCI_PRODUCT_ARECA_ARC1210: |
186 | case PCI_PRODUCT_ARECA_ARC1220: |
187 | case PCI_PRODUCT_ARECA_ARC1230: |
188 | case PCI_PRODUCT_ARECA_ARC1260: |
189 | case PCI_PRODUCT_ARECA_ARC1270: |
190 | case PCI_PRODUCT_ARECA_ARC1280: |
191 | case PCI_PRODUCT_ARECA_ARC1380: |
192 | case PCI_PRODUCT_ARECA_ARC1381: |
193 | case PCI_PRODUCT_ARECA_ARC1680: |
194 | case PCI_PRODUCT_ARECA_ARC1681: |
195 | return 1; |
196 | default: |
197 | break; |
198 | } |
199 | } |
200 | |
201 | return 0; |
202 | } |
203 | |
204 | static void |
205 | arc_attach(device_t parent, device_t self, void *aux) |
206 | { |
207 | struct arc_softc *sc = device_private(self); |
208 | struct pci_attach_args *pa = aux; |
209 | struct scsipi_adapter *adapt = &sc->sc_adapter; |
210 | struct scsipi_channel *chan = &sc->sc_chan; |
211 | |
212 | sc->sc_dev = self; |
213 | sc->sc_talking = 0; |
214 | rw_init(&sc->sc_rwlock); |
215 | mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_BIO); |
216 | cv_init(&sc->sc_condvar, "arcdb" ); |
217 | |
218 | if (arc_map_pci_resources(self, pa) != 0) { |
219 | /* error message printed by arc_map_pci_resources */ |
220 | return; |
221 | } |
222 | |
223 | if (arc_query_firmware(self) != 0) { |
224 | /* error message printed by arc_query_firmware */ |
225 | goto unmap_pci; |
226 | } |
227 | |
228 | if (arc_alloc_ccbs(self) != 0) { |
229 | /* error message printed by arc_alloc_ccbs */ |
230 | goto unmap_pci; |
231 | } |
232 | |
233 | if (!pmf_device_register1(self, NULL, NULL, arc_shutdown)) |
234 | panic("%s: couldn't establish shutdown handler\n" , |
235 | device_xname(self)); |
236 | |
237 | memset(adapt, 0, sizeof(*adapt)); |
238 | adapt->adapt_dev = self; |
239 | adapt->adapt_nchannels = 1; |
240 | adapt->adapt_openings = sc->sc_req_count / ARC_MAX_TARGET; |
241 | adapt->adapt_max_periph = adapt->adapt_openings; |
242 | adapt->adapt_minphys = arc_minphys; |
243 | adapt->adapt_request = arc_scsi_cmd; |
244 | |
245 | memset(chan, 0, sizeof(*chan)); |
246 | chan->chan_adapter = adapt; |
247 | chan->chan_bustype = &scsi_bustype; |
248 | chan->chan_nluns = ARC_MAX_LUN; |
249 | chan->chan_ntargets = ARC_MAX_TARGET; |
250 | chan->chan_id = ARC_MAX_TARGET; |
251 | chan->chan_flags = SCSIPI_CHAN_NOSETTLE; |
252 | |
253 | /* |
254 | * Save the device_t returned, because we could to attach |
255 | * devices via the management interface. |
256 | */ |
257 | sc->sc_scsibus_dv = config_found(self, &sc->sc_chan, scsiprint); |
258 | |
259 | /* enable interrupts */ |
260 | arc_write(sc, ARC_REG_INTRMASK, |
261 | ~(ARC_REG_INTRMASK_POSTQUEUE|ARC_REG_INTRSTAT_DOORBELL)); |
262 | |
263 | #if NBIO > 0 |
264 | /* |
265 | * Register the driver to bio(4) and setup the sensors. |
266 | */ |
267 | if (bio_register(self, arc_bioctl) != 0) |
268 | panic("%s: bioctl registration failed\n" , device_xname(self)); |
269 | |
270 | /* |
271 | * you need to talk to the firmware to get volume info. our firmware |
272 | * interface relies on being able to sleep, so we need to use a thread |
273 | * to do the work. |
274 | */ |
275 | if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, |
276 | arc_create_sensors, sc, &sc->sc_lwp, "arcmsr_sensors" ) != 0) |
277 | panic("%s: unable to create a kernel thread for sensors\n" , |
278 | device_xname(self)); |
279 | #endif |
280 | |
281 | return; |
282 | |
283 | unmap_pci: |
284 | arc_unmap_pci_resources(sc); |
285 | } |
286 | |
287 | static int |
288 | arc_detach(device_t self, int flags) |
289 | { |
290 | struct arc_softc *sc = device_private(self); |
291 | |
292 | if (arc_msg0(sc, ARC_REG_INB_MSG0_STOP_BGRB) != 0) |
293 | aprint_error_dev(self, "timeout waiting to stop bg rebuild\n" ); |
294 | |
295 | if (arc_msg0(sc, ARC_REG_INB_MSG0_FLUSH_CACHE) != 0) |
296 | aprint_error_dev(self, "timeout waiting to flush cache\n" ); |
297 | |
298 | if (sc->sc_sme != NULL) |
299 | sysmon_envsys_unregister(sc->sc_sme); |
300 | |
301 | return 0; |
302 | } |
303 | |
304 | static bool |
305 | arc_shutdown(device_t self, int how) |
306 | { |
307 | struct arc_softc *sc = device_private(self); |
308 | |
309 | if (arc_msg0(sc, ARC_REG_INB_MSG0_STOP_BGRB) != 0) |
310 | aprint_error_dev(self, "timeout waiting to stop bg rebuild\n" ); |
311 | |
312 | if (arc_msg0(sc, ARC_REG_INB_MSG0_FLUSH_CACHE) != 0) |
313 | aprint_error_dev(self, "timeout waiting to flush cache\n" ); |
314 | |
315 | return true; |
316 | } |
317 | |
318 | static void |
319 | arc_minphys(struct buf *bp) |
320 | { |
321 | if (bp->b_bcount > MAXPHYS) |
322 | bp->b_bcount = MAXPHYS; |
323 | minphys(bp); |
324 | } |
325 | |
326 | static int |
327 | arc_intr(void *arg) |
328 | { |
329 | struct arc_softc *sc = arg; |
330 | struct arc_ccb *ccb = NULL; |
331 | char *kva = ARC_DMA_KVA(sc->sc_requests); |
332 | struct arc_io_cmd *cmd; |
333 | uint32_t reg, intrstat; |
334 | |
335 | mutex_spin_enter(&sc->sc_mutex); |
336 | intrstat = arc_read(sc, ARC_REG_INTRSTAT); |
337 | if (intrstat == 0x0) { |
338 | mutex_spin_exit(&sc->sc_mutex); |
339 | return 0; |
340 | } |
341 | |
342 | intrstat &= ARC_REG_INTRSTAT_POSTQUEUE | ARC_REG_INTRSTAT_DOORBELL; |
343 | arc_write(sc, ARC_REG_INTRSTAT, intrstat); |
344 | |
345 | if (intrstat & ARC_REG_INTRSTAT_DOORBELL) { |
346 | if (sc->sc_talking) { |
347 | arc_write(sc, ARC_REG_INTRMASK, |
348 | ~ARC_REG_INTRMASK_POSTQUEUE); |
349 | cv_broadcast(&sc->sc_condvar); |
350 | } else { |
351 | /* otherwise drop it */ |
352 | reg = arc_read(sc, ARC_REG_OUTB_DOORBELL); |
353 | arc_write(sc, ARC_REG_OUTB_DOORBELL, reg); |
354 | if (reg & ARC_REG_OUTB_DOORBELL_WRITE_OK) |
355 | arc_write(sc, ARC_REG_INB_DOORBELL, |
356 | ARC_REG_INB_DOORBELL_READ_OK); |
357 | } |
358 | } |
359 | mutex_spin_exit(&sc->sc_mutex); |
360 | |
361 | while ((reg = arc_pop(sc)) != 0xffffffff) { |
362 | cmd = (struct arc_io_cmd *)(kva + |
363 | ((reg << ARC_REG_REPLY_QUEUE_ADDR_SHIFT) - |
364 | (uint32_t)ARC_DMA_DVA(sc->sc_requests))); |
365 | ccb = &sc->sc_ccbs[htole32(cmd->cmd.context)]; |
366 | |
367 | bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), |
368 | ccb->ccb_offset, ARC_MAX_IOCMDLEN, |
369 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); |
370 | |
371 | arc_scsi_cmd_done(sc, ccb, reg); |
372 | } |
373 | |
374 | |
375 | return 1; |
376 | } |
377 | |
378 | void |
379 | arc_scsi_cmd(struct scsipi_channel *chan, scsipi_adapter_req_t req, void *arg) |
380 | { |
381 | struct scsipi_periph *periph; |
382 | struct scsipi_xfer *xs; |
383 | struct scsipi_adapter *adapt = chan->chan_adapter; |
384 | struct arc_softc *sc = device_private(adapt->adapt_dev); |
385 | struct arc_ccb *ccb; |
386 | struct arc_msg_scsicmd *cmd; |
387 | uint32_t reg; |
388 | uint8_t target; |
389 | |
390 | switch (req) { |
391 | case ADAPTER_REQ_GROW_RESOURCES: |
392 | /* Not supported. */ |
393 | return; |
394 | case ADAPTER_REQ_SET_XFER_MODE: |
395 | /* Not supported. */ |
396 | return; |
397 | case ADAPTER_REQ_RUN_XFER: |
398 | break; |
399 | } |
400 | |
401 | mutex_spin_enter(&sc->sc_mutex); |
402 | |
403 | xs = arg; |
404 | periph = xs->xs_periph; |
405 | target = periph->periph_target; |
406 | |
407 | if (xs->cmdlen > ARC_MSG_CDBLEN) { |
408 | memset(&xs->sense, 0, sizeof(xs->sense)); |
409 | xs->sense.scsi_sense.response_code = SSD_RCODE_VALID | 0x70; |
410 | xs->sense.scsi_sense.flags = SKEY_ILLEGAL_REQUEST; |
411 | xs->sense.scsi_sense.asc = 0x20; |
412 | xs->error = XS_SENSE; |
413 | xs->status = SCSI_CHECK; |
414 | mutex_spin_exit(&sc->sc_mutex); |
415 | scsipi_done(xs); |
416 | return; |
417 | } |
418 | |
419 | ccb = arc_get_ccb(sc); |
420 | if (ccb == NULL) { |
421 | xs->error = XS_RESOURCE_SHORTAGE; |
422 | mutex_spin_exit(&sc->sc_mutex); |
423 | scsipi_done(xs); |
424 | return; |
425 | } |
426 | |
427 | ccb->ccb_xs = xs; |
428 | |
429 | if (arc_load_xs(ccb) != 0) { |
430 | xs->error = XS_DRIVER_STUFFUP; |
431 | arc_put_ccb(sc, ccb); |
432 | mutex_spin_exit(&sc->sc_mutex); |
433 | scsipi_done(xs); |
434 | return; |
435 | } |
436 | |
437 | cmd = &ccb->ccb_cmd->cmd; |
438 | reg = ccb->ccb_cmd_post; |
439 | |
440 | /* bus is always 0 */ |
441 | cmd->target = target; |
442 | cmd->lun = periph->periph_lun; |
443 | cmd->function = 1; /* XXX magic number */ |
444 | |
445 | cmd->cdb_len = xs->cmdlen; |
446 | cmd->sgl_len = ccb->ccb_dmamap->dm_nsegs; |
447 | if (xs->xs_control & XS_CTL_DATA_OUT) |
448 | cmd->flags = ARC_MSG_SCSICMD_FLAG_WRITE; |
449 | if (ccb->ccb_dmamap->dm_nsegs > ARC_SGL_256LEN) { |
450 | cmd->flags |= ARC_MSG_SCSICMD_FLAG_SGL_BSIZE_512; |
451 | reg |= ARC_REG_POST_QUEUE_BIGFRAME; |
452 | } |
453 | |
454 | cmd->context = htole32(ccb->ccb_id); |
455 | cmd->data_len = htole32(xs->datalen); |
456 | |
457 | memcpy(cmd->cdb, xs->cmd, xs->cmdlen); |
458 | |
459 | /* we've built the command, let's put it on the hw */ |
460 | bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), |
461 | ccb->ccb_offset, ARC_MAX_IOCMDLEN, |
462 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); |
463 | |
464 | arc_push(sc, reg); |
465 | if (xs->xs_control & XS_CTL_POLL) { |
466 | if (arc_complete(sc, ccb, xs->timeout) != 0) { |
467 | xs->error = XS_DRIVER_STUFFUP; |
468 | mutex_spin_exit(&sc->sc_mutex); |
469 | scsipi_done(xs); |
470 | return; |
471 | } |
472 | } |
473 | |
474 | mutex_spin_exit(&sc->sc_mutex); |
475 | } |
476 | |
477 | int |
478 | arc_load_xs(struct arc_ccb *ccb) |
479 | { |
480 | struct arc_softc *sc = ccb->ccb_sc; |
481 | struct scsipi_xfer *xs = ccb->ccb_xs; |
482 | bus_dmamap_t dmap = ccb->ccb_dmamap; |
483 | struct arc_sge *sgl = ccb->ccb_cmd->sgl, *sge; |
484 | uint64_t addr; |
485 | int i, error; |
486 | |
487 | if (xs->datalen == 0) |
488 | return 0; |
489 | |
490 | error = bus_dmamap_load(sc->sc_dmat, dmap, |
491 | xs->data, xs->datalen, NULL, |
492 | (xs->xs_control & XS_CTL_NOSLEEP) ? |
493 | BUS_DMA_NOWAIT : BUS_DMA_WAITOK); |
494 | if (error != 0) { |
495 | aprint_error("%s: error %d loading dmamap\n" , |
496 | device_xname(sc->sc_dev), error); |
497 | return 1; |
498 | } |
499 | |
500 | for (i = 0; i < dmap->dm_nsegs; i++) { |
501 | sge = &sgl[i]; |
502 | |
503 | sge->sg_hdr = htole32(ARC_SGE_64BIT | dmap->dm_segs[i].ds_len); |
504 | addr = dmap->dm_segs[i].ds_addr; |
505 | sge->sg_hi_addr = htole32((uint32_t)(addr >> 32)); |
506 | sge->sg_lo_addr = htole32((uint32_t)addr); |
507 | } |
508 | |
509 | bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize, |
510 | (xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMASYNC_PREREAD : |
511 | BUS_DMASYNC_PREWRITE); |
512 | |
513 | return 0; |
514 | } |
515 | |
516 | void |
517 | arc_scsi_cmd_done(struct arc_softc *sc, struct arc_ccb *ccb, uint32_t reg) |
518 | { |
519 | struct scsipi_xfer *xs = ccb->ccb_xs; |
520 | struct arc_msg_scsicmd *cmd; |
521 | |
522 | if (xs->datalen != 0) { |
523 | bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, |
524 | ccb->ccb_dmamap->dm_mapsize, |
525 | (xs->xs_control & XS_CTL_DATA_IN) ? |
526 | BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); |
527 | bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); |
528 | } |
529 | |
530 | /* timeout_del */ |
531 | xs->status |= XS_STS_DONE; |
532 | |
533 | if (reg & ARC_REG_REPLY_QUEUE_ERR) { |
534 | cmd = &ccb->ccb_cmd->cmd; |
535 | |
536 | switch (cmd->status) { |
537 | case ARC_MSG_STATUS_SELTIMEOUT: |
538 | case ARC_MSG_STATUS_ABORTED: |
539 | case ARC_MSG_STATUS_INIT_FAIL: |
540 | xs->status = SCSI_OK; |
541 | xs->error = XS_SELTIMEOUT; |
542 | break; |
543 | |
544 | case SCSI_CHECK: |
545 | memset(&xs->sense, 0, sizeof(xs->sense)); |
546 | memcpy(&xs->sense, cmd->sense_data, |
547 | min(ARC_MSG_SENSELEN, sizeof(xs->sense))); |
548 | xs->sense.scsi_sense.response_code = |
549 | SSD_RCODE_VALID | 0x70; |
550 | xs->status = SCSI_CHECK; |
551 | xs->error = XS_SENSE; |
552 | xs->resid = 0; |
553 | break; |
554 | |
555 | default: |
556 | /* unknown device status */ |
557 | xs->error = XS_BUSY; /* try again later? */ |
558 | xs->status = SCSI_BUSY; |
559 | break; |
560 | } |
561 | } else { |
562 | xs->status = SCSI_OK; |
563 | xs->error = XS_NOERROR; |
564 | xs->resid = 0; |
565 | } |
566 | |
567 | arc_put_ccb(sc, ccb); |
568 | scsipi_done(xs); |
569 | } |
570 | |
571 | int |
572 | arc_complete(struct arc_softc *sc, struct arc_ccb *nccb, int timeout) |
573 | { |
574 | struct arc_ccb *ccb = NULL; |
575 | char *kva = ARC_DMA_KVA(sc->sc_requests); |
576 | struct arc_io_cmd *cmd; |
577 | uint32_t reg; |
578 | |
579 | do { |
580 | reg = arc_pop(sc); |
581 | if (reg == 0xffffffff) { |
582 | if (timeout-- == 0) |
583 | return 1; |
584 | |
585 | delay(1000); |
586 | continue; |
587 | } |
588 | |
589 | cmd = (struct arc_io_cmd *)(kva + |
590 | ((reg << ARC_REG_REPLY_QUEUE_ADDR_SHIFT) - |
591 | ARC_DMA_DVA(sc->sc_requests))); |
592 | ccb = &sc->sc_ccbs[htole32(cmd->cmd.context)]; |
593 | |
594 | bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), |
595 | ccb->ccb_offset, ARC_MAX_IOCMDLEN, |
596 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); |
597 | |
598 | arc_scsi_cmd_done(sc, ccb, reg); |
599 | } while (nccb != ccb); |
600 | |
601 | return 0; |
602 | } |
603 | |
604 | int |
605 | arc_map_pci_resources(device_t self, struct pci_attach_args *pa) |
606 | { |
607 | struct arc_softc *sc = device_private(self); |
608 | pcireg_t memtype; |
609 | pci_intr_handle_t ih; |
610 | char intrbuf[PCI_INTRSTR_LEN]; |
611 | |
612 | sc->sc_pc = pa->pa_pc; |
613 | sc->sc_tag = pa->pa_tag; |
614 | sc->sc_dmat = pa->pa_dmat; |
615 | |
616 | memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, ARC_PCI_BAR); |
617 | if (pci_mapreg_map(pa, ARC_PCI_BAR, memtype, 0, &sc->sc_iot, |
618 | &sc->sc_ioh, NULL, &sc->sc_ios) != 0) { |
619 | aprint_error(": unable to map system interface register\n" ); |
620 | return 1; |
621 | } |
622 | |
623 | if (pci_intr_map(pa, &ih) != 0) { |
624 | aprint_error(": unable to map interrupt\n" ); |
625 | goto unmap; |
626 | } |
627 | |
628 | sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, |
629 | arc_intr, sc); |
630 | if (sc->sc_ih == NULL) { |
631 | aprint_error(": unable to map interrupt [2]\n" ); |
632 | goto unmap; |
633 | } |
634 | |
635 | aprint_normal("\n" ); |
636 | aprint_normal_dev(self, "interrupting at %s\n" , |
637 | pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf))); |
638 | |
639 | return 0; |
640 | |
641 | unmap: |
642 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); |
643 | sc->sc_ios = 0; |
644 | return 1; |
645 | } |
646 | |
647 | void |
648 | arc_unmap_pci_resources(struct arc_softc *sc) |
649 | { |
650 | pci_intr_disestablish(sc->sc_pc, sc->sc_ih); |
651 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); |
652 | sc->sc_ios = 0; |
653 | } |
654 | |
655 | int |
656 | arc_query_firmware(device_t self) |
657 | { |
658 | struct arc_softc *sc = device_private(self); |
659 | struct arc_msg_firmware_info fwinfo; |
660 | char string[81]; /* sizeof(vendor)*2+1 */ |
661 | |
662 | if (arc_wait_eq(sc, ARC_REG_OUTB_ADDR1, ARC_REG_OUTB_ADDR1_FIRMWARE_OK, |
663 | ARC_REG_OUTB_ADDR1_FIRMWARE_OK) != 0) { |
664 | aprint_debug_dev(self, "timeout waiting for firmware ok\n" ); |
665 | return 1; |
666 | } |
667 | |
668 | if (arc_msg0(sc, ARC_REG_INB_MSG0_GET_CONFIG) != 0) { |
669 | aprint_debug_dev(self, "timeout waiting for get config\n" ); |
670 | return 1; |
671 | } |
672 | |
673 | if (arc_msg0(sc, ARC_REG_INB_MSG0_START_BGRB) != 0) { |
674 | aprint_debug_dev(self, "timeout waiting to start bg rebuild\n" ); |
675 | return 1; |
676 | } |
677 | |
678 | arc_read_region(sc, ARC_REG_MSGBUF, &fwinfo, sizeof(fwinfo)); |
679 | |
680 | DNPRINTF(ARC_D_INIT, "%s: signature: 0x%08x\n" , |
681 | device_xname(self), htole32(fwinfo.signature)); |
682 | |
683 | if (htole32(fwinfo.signature) != ARC_FWINFO_SIGNATURE_GET_CONFIG) { |
684 | aprint_error_dev(self, "invalid firmware info from iop\n" ); |
685 | return 1; |
686 | } |
687 | |
688 | DNPRINTF(ARC_D_INIT, "%s: request_len: %d\n" , |
689 | device_xname(self), htole32(fwinfo.request_len)); |
690 | DNPRINTF(ARC_D_INIT, "%s: queue_len: %d\n" , |
691 | device_xname(self), htole32(fwinfo.queue_len)); |
692 | DNPRINTF(ARC_D_INIT, "%s: sdram_size: %d\n" , |
693 | device_xname(self), htole32(fwinfo.sdram_size)); |
694 | DNPRINTF(ARC_D_INIT, "%s: sata_ports: %d\n" , |
695 | device_xname(self), htole32(fwinfo.sata_ports)); |
696 | |
697 | strnvisx(string, sizeof(string), fwinfo.vendor, sizeof(fwinfo.vendor), |
698 | VIS_TRIM|VIS_SAFE|VIS_OCTAL); |
699 | DNPRINTF(ARC_D_INIT, "%s: vendor: \"%s\"\n" , |
700 | device_xname(self), string); |
701 | |
702 | strnvisx(string, sizeof(string), fwinfo.model, sizeof(fwinfo.model), |
703 | VIS_TRIM|VIS_SAFE|VIS_OCTAL); |
704 | aprint_normal_dev(self, "Areca %s Host Adapter RAID controller\n" , |
705 | string); |
706 | |
707 | strnvisx(string, sizeof(string), fwinfo.fw_version, |
708 | sizeof(fwinfo.fw_version), VIS_TRIM|VIS_SAFE|VIS_OCTAL); |
709 | DNPRINTF(ARC_D_INIT, "%s: version: \"%s\"\n" , |
710 | device_xname(self), string); |
711 | |
712 | aprint_normal_dev(self, "%d ports, %dMB SDRAM, firmware <%s>\n" , |
713 | htole32(fwinfo.sata_ports), htole32(fwinfo.sdram_size), string); |
714 | |
715 | if (htole32(fwinfo.request_len) != ARC_MAX_IOCMDLEN) { |
716 | aprint_error_dev(self, |
717 | "unexpected request frame size (%d != %d)\n" , |
718 | htole32(fwinfo.request_len), ARC_MAX_IOCMDLEN); |
719 | return 1; |
720 | } |
721 | |
722 | sc->sc_req_count = htole32(fwinfo.queue_len); |
723 | |
724 | return 0; |
725 | } |
726 | |
727 | #if NBIO > 0 |
728 | static int |
729 | arc_bioctl(device_t self, u_long cmd, void *addr) |
730 | { |
731 | struct arc_softc *sc = device_private(self); |
732 | int error = 0; |
733 | |
734 | switch (cmd) { |
735 | case BIOCINQ: |
736 | error = arc_bio_inq(sc, (struct bioc_inq *)addr); |
737 | break; |
738 | |
739 | case BIOCVOL: |
740 | error = arc_bio_vol(sc, (struct bioc_vol *)addr); |
741 | break; |
742 | |
743 | case BIOCDISK: |
744 | error = arc_bio_disk_volume(sc, (struct bioc_disk *)addr); |
745 | break; |
746 | |
747 | case BIOCDISK_NOVOL: |
748 | error = arc_bio_disk_novol(sc, (struct bioc_disk *)addr); |
749 | break; |
750 | |
751 | case BIOCALARM: |
752 | error = arc_bio_alarm(sc, (struct bioc_alarm *)addr); |
753 | break; |
754 | |
755 | case BIOCSETSTATE: |
756 | error = arc_bio_setstate(sc, (struct bioc_setstate *)addr); |
757 | break; |
758 | |
759 | case BIOCVOLOPS: |
760 | error = arc_bio_volops(sc, (struct bioc_volops *)addr); |
761 | break; |
762 | |
763 | default: |
764 | error = ENOTTY; |
765 | break; |
766 | } |
767 | |
768 | return error; |
769 | } |
770 | |
771 | static int |
772 | arc_fw_parse_status_code(struct arc_softc *sc, uint8_t *reply) |
773 | { |
774 | switch (*reply) { |
775 | case ARC_FW_CMD_RAIDINVAL: |
776 | printf("%s: firmware error (invalid raid set)\n" , |
777 | device_xname(sc->sc_dev)); |
778 | return EINVAL; |
779 | case ARC_FW_CMD_VOLINVAL: |
780 | printf("%s: firmware error (invalid volume set)\n" , |
781 | device_xname(sc->sc_dev)); |
782 | return EINVAL; |
783 | case ARC_FW_CMD_NORAID: |
784 | printf("%s: firmware error (unexistent raid set)\n" , |
785 | device_xname(sc->sc_dev)); |
786 | return ENODEV; |
787 | case ARC_FW_CMD_NOVOLUME: |
788 | printf("%s: firmware error (unexistent volume set)\n" , |
789 | device_xname(sc->sc_dev)); |
790 | return ENODEV; |
791 | case ARC_FW_CMD_NOPHYSDRV: |
792 | printf("%s: firmware error (unexistent physical drive)\n" , |
793 | device_xname(sc->sc_dev)); |
794 | return ENODEV; |
795 | case ARC_FW_CMD_PARAM_ERR: |
796 | printf("%s: firmware error (parameter error)\n" , |
797 | device_xname(sc->sc_dev)); |
798 | return EINVAL; |
799 | case ARC_FW_CMD_UNSUPPORTED: |
800 | printf("%s: firmware error (unsupported command)\n" , |
801 | device_xname(sc->sc_dev)); |
802 | return EOPNOTSUPP; |
803 | case ARC_FW_CMD_DISKCFG_CHGD: |
804 | printf("%s: firmware error (disk configuration changed)\n" , |
805 | device_xname(sc->sc_dev)); |
806 | return EINVAL; |
807 | case ARC_FW_CMD_PASS_INVAL: |
808 | printf("%s: firmware error (invalid password)\n" , |
809 | device_xname(sc->sc_dev)); |
810 | return EINVAL; |
811 | case ARC_FW_CMD_NODISKSPACE: |
812 | printf("%s: firmware error (no disk space available)\n" , |
813 | device_xname(sc->sc_dev)); |
814 | return EOPNOTSUPP; |
815 | case ARC_FW_CMD_CHECKSUM_ERR: |
816 | printf("%s: firmware error (checksum error)\n" , |
817 | device_xname(sc->sc_dev)); |
818 | return EINVAL; |
819 | case ARC_FW_CMD_PASS_REQD: |
820 | printf("%s: firmware error (password required)\n" , |
821 | device_xname(sc->sc_dev)); |
822 | return EPERM; |
823 | case ARC_FW_CMD_OK: |
824 | default: |
825 | return 0; |
826 | } |
827 | } |
828 | |
829 | static int |
830 | arc_bio_alarm(struct arc_softc *sc, struct bioc_alarm *ba) |
831 | { |
832 | uint8_t request[2], reply[1]; |
833 | size_t len; |
834 | int error = 0; |
835 | |
836 | switch (ba->ba_opcode) { |
837 | case BIOC_SAENABLE: |
838 | case BIOC_SADISABLE: |
839 | request[0] = ARC_FW_SET_ALARM; |
840 | request[1] = (ba->ba_opcode == BIOC_SAENABLE) ? |
841 | ARC_FW_SET_ALARM_ENABLE : ARC_FW_SET_ALARM_DISABLE; |
842 | len = sizeof(request); |
843 | |
844 | break; |
845 | |
846 | case BIOC_SASILENCE: |
847 | request[0] = ARC_FW_MUTE_ALARM; |
848 | len = 1; |
849 | |
850 | break; |
851 | |
852 | case BIOC_GASTATUS: |
853 | /* system info is too big/ugly to deal with here */ |
854 | return arc_bio_alarm_state(sc, ba); |
855 | |
856 | default: |
857 | return EOPNOTSUPP; |
858 | } |
859 | |
860 | error = arc_msgbuf(sc, request, len, reply, sizeof(reply)); |
861 | if (error != 0) |
862 | return error; |
863 | |
864 | return arc_fw_parse_status_code(sc, &reply[0]); |
865 | } |
866 | |
867 | static int |
868 | arc_bio_alarm_state(struct arc_softc *sc, struct bioc_alarm *ba) |
869 | { |
870 | struct arc_fw_sysinfo *sysinfo; |
871 | uint8_t request; |
872 | int error = 0; |
873 | |
874 | sysinfo = kmem_zalloc(sizeof(*sysinfo), KM_SLEEP); |
875 | |
876 | request = ARC_FW_SYSINFO; |
877 | error = arc_msgbuf(sc, &request, sizeof(request), |
878 | sysinfo, sizeof(struct arc_fw_sysinfo)); |
879 | |
880 | if (error != 0) |
881 | goto out; |
882 | |
883 | ba->ba_status = sysinfo->alarm; |
884 | |
885 | out: |
886 | kmem_free(sysinfo, sizeof(*sysinfo)); |
887 | return error; |
888 | } |
889 | |
890 | static int |
891 | arc_bio_volops(struct arc_softc *sc, struct bioc_volops *bc) |
892 | { |
893 | /* to create a raid set */ |
894 | struct req_craidset { |
895 | uint8_t cmdcode; |
896 | uint32_t devmask; |
897 | uint8_t raidset_name[16]; |
898 | } __packed; |
899 | |
900 | /* to create a volume set */ |
901 | struct req_cvolset { |
902 | uint8_t cmdcode; |
903 | uint8_t raidset; |
904 | uint8_t volset_name[16]; |
905 | uint64_t capacity; |
906 | uint8_t raidlevel; |
907 | uint8_t stripe; |
908 | uint8_t scsi_chan; |
909 | uint8_t scsi_target; |
910 | uint8_t scsi_lun; |
911 | uint8_t tagqueue; |
912 | uint8_t cache; |
913 | uint8_t speed; |
914 | uint8_t quick_init; |
915 | } __packed; |
916 | |
917 | struct scsibus_softc *scsibus_sc = NULL; |
918 | struct req_craidset req_craidset; |
919 | struct req_cvolset req_cvolset; |
920 | uint8_t request[2]; |
921 | uint8_t reply[1]; |
922 | int error = 0; |
923 | |
924 | switch (bc->bc_opcode) { |
925 | case BIOC_VCREATE_VOLUME: |
926 | { |
927 | /* |
928 | * Zero out the structs so that we use some defaults |
929 | * in raid and volume sets. |
930 | */ |
931 | memset(&req_craidset, 0, sizeof(req_craidset)); |
932 | memset(&req_cvolset, 0, sizeof(req_cvolset)); |
933 | |
934 | /* |
935 | * Firstly we have to create the raid set and |
936 | * use the default name for all them. |
937 | */ |
938 | req_craidset.cmdcode = ARC_FW_CREATE_RAIDSET; |
939 | req_craidset.devmask = bc->bc_devmask; |
940 | error = arc_msgbuf(sc, &req_craidset, sizeof(req_craidset), |
941 | reply, sizeof(reply)); |
942 | if (error != 0) |
943 | return error; |
944 | |
945 | error = arc_fw_parse_status_code(sc, &reply[0]); |
946 | if (error) { |
947 | printf("%s: create raidset%d failed\n" , |
948 | device_xname(sc->sc_dev), bc->bc_volid); |
949 | return error; |
950 | } |
951 | |
952 | /* |
953 | * At this point the raid set was created, so it's |
954 | * time to create the volume set. |
955 | */ |
956 | req_cvolset.cmdcode = ARC_FW_CREATE_VOLUME; |
957 | req_cvolset.raidset = bc->bc_volid; |
958 | req_cvolset.capacity = bc->bc_size * ARC_BLOCKSIZE; |
959 | |
960 | /* |
961 | * Set the RAID level. |
962 | */ |
963 | switch (bc->bc_level) { |
964 | case 0: |
965 | case 1: |
966 | req_cvolset.raidlevel = bc->bc_level; |
967 | break; |
968 | case BIOC_SVOL_RAID10: |
969 | req_cvolset.raidlevel = 1; |
970 | break; |
971 | case 3: |
972 | req_cvolset.raidlevel = ARC_FW_VOL_RAIDLEVEL_3; |
973 | break; |
974 | case 5: |
975 | req_cvolset.raidlevel = ARC_FW_VOL_RAIDLEVEL_5; |
976 | break; |
977 | case 6: |
978 | req_cvolset.raidlevel = ARC_FW_VOL_RAIDLEVEL_6; |
979 | break; |
980 | default: |
981 | return EOPNOTSUPP; |
982 | } |
983 | |
984 | /* |
985 | * Set the stripe size. |
986 | */ |
987 | switch (bc->bc_stripe) { |
988 | case 4: |
989 | req_cvolset.stripe = 0; |
990 | break; |
991 | case 8: |
992 | req_cvolset.stripe = 1; |
993 | break; |
994 | case 16: |
995 | req_cvolset.stripe = 2; |
996 | break; |
997 | case 32: |
998 | req_cvolset.stripe = 3; |
999 | break; |
1000 | case 64: |
1001 | req_cvolset.stripe = 4; |
1002 | break; |
1003 | case 128: |
1004 | req_cvolset.stripe = 5; |
1005 | break; |
1006 | default: |
1007 | req_cvolset.stripe = 4; /* by default 64K */ |
1008 | break; |
1009 | } |
1010 | |
1011 | req_cvolset.scsi_chan = bc->bc_channel; |
1012 | req_cvolset.scsi_target = bc->bc_target; |
1013 | req_cvolset.scsi_lun = bc->bc_lun; |
1014 | req_cvolset.tagqueue = 1; /* always enabled */ |
1015 | req_cvolset.cache = 1; /* always enabled */ |
1016 | req_cvolset.speed = 4; /* always max speed */ |
1017 | |
1018 | /* RAID 1 and 1+0 levels need foreground initialization */ |
1019 | if (bc->bc_level == 1 || bc->bc_level == BIOC_SVOL_RAID10) |
1020 | req_cvolset.quick_init = 1; /* foreground init */ |
1021 | |
1022 | error = arc_msgbuf(sc, &req_cvolset, sizeof(req_cvolset), |
1023 | reply, sizeof(reply)); |
1024 | if (error != 0) |
1025 | return error; |
1026 | |
1027 | error = arc_fw_parse_status_code(sc, &reply[0]); |
1028 | if (error) { |
1029 | printf("%s: create volumeset%d failed\n" , |
1030 | device_xname(sc->sc_dev), bc->bc_volid); |
1031 | return error; |
1032 | } |
1033 | |
1034 | /* |
1035 | * If we are creating a RAID 1 or RAID 1+0 volume, |
1036 | * the volume will be created immediately but it won't |
1037 | * be available until the initialization is done... so |
1038 | * don't bother attaching the sd(4) device. |
1039 | */ |
1040 | if (bc->bc_level == 1 || bc->bc_level == BIOC_SVOL_RAID10) |
1041 | break; |
1042 | |
1043 | /* |
1044 | * Do a rescan on the bus to attach the device associated |
1045 | * with the new volume. |
1046 | */ |
1047 | scsibus_sc = device_private(sc->sc_scsibus_dv); |
1048 | (void)scsi_probe_bus(scsibus_sc, bc->bc_target, bc->bc_lun); |
1049 | |
1050 | break; |
1051 | } |
1052 | case BIOC_VREMOVE_VOLUME: |
1053 | { |
1054 | /* |
1055 | * Remove the volume set specified in bc_volid. |
1056 | */ |
1057 | request[0] = ARC_FW_DELETE_VOLUME; |
1058 | request[1] = bc->bc_volid; |
1059 | error = arc_msgbuf(sc, request, sizeof(request), |
1060 | reply, sizeof(reply)); |
1061 | if (error != 0) |
1062 | return error; |
1063 | |
1064 | error = arc_fw_parse_status_code(sc, &reply[0]); |
1065 | if (error) { |
1066 | printf("%s: delete volumeset%d failed\n" , |
1067 | device_xname(sc->sc_dev), bc->bc_volid); |
1068 | return error; |
1069 | } |
1070 | |
1071 | /* |
1072 | * Detach the sd(4) device associated with the volume, |
1073 | * but if there's an error don't make it a priority. |
1074 | */ |
1075 | error = scsipi_target_detach(&sc->sc_chan, bc->bc_target, |
1076 | bc->bc_lun, 0); |
1077 | if (error) |
1078 | printf("%s: couldn't detach sd device for volume %d " |
1079 | "at %u:%u.%u (error=%d)\n" , |
1080 | device_xname(sc->sc_dev), bc->bc_volid, |
1081 | bc->bc_channel, bc->bc_target, bc->bc_lun, error); |
1082 | |
1083 | /* |
1084 | * and remove the raid set specified in bc_volid, |
1085 | * we only care about volumes. |
1086 | */ |
1087 | request[0] = ARC_FW_DELETE_RAIDSET; |
1088 | request[1] = bc->bc_volid; |
1089 | error = arc_msgbuf(sc, request, sizeof(request), |
1090 | reply, sizeof(reply)); |
1091 | if (error != 0) |
1092 | return error; |
1093 | |
1094 | error = arc_fw_parse_status_code(sc, &reply[0]); |
1095 | if (error) { |
1096 | printf("%s: delete raidset%d failed\n" , |
1097 | device_xname(sc->sc_dev), bc->bc_volid); |
1098 | return error; |
1099 | } |
1100 | |
1101 | break; |
1102 | } |
1103 | default: |
1104 | return EOPNOTSUPP; |
1105 | } |
1106 | |
1107 | return error; |
1108 | } |
1109 | |
1110 | static int |
1111 | arc_bio_setstate(struct arc_softc *sc, struct bioc_setstate *bs) |
1112 | { |
1113 | /* for a hotspare disk */ |
1114 | struct request_hs { |
1115 | uint8_t cmdcode; |
1116 | uint32_t devmask; |
1117 | } __packed; |
1118 | |
1119 | /* for a pass-through disk */ |
1120 | struct request_pt { |
1121 | uint8_t cmdcode; |
1122 | uint8_t devid; |
1123 | uint8_t scsi_chan; |
1124 | uint8_t scsi_id; |
1125 | uint8_t scsi_lun; |
1126 | uint8_t tagged_queue; |
1127 | uint8_t cache_mode; |
1128 | uint8_t max_speed; |
1129 | } __packed; |
1130 | |
1131 | struct scsibus_softc *scsibus_sc = NULL; |
1132 | struct request_hs req_hs; /* to add/remove hotspare */ |
1133 | struct request_pt req_pt; /* to add a pass-through */ |
1134 | uint8_t req_gen[2]; |
1135 | uint8_t reply[1]; |
1136 | int error = 0; |
1137 | |
1138 | switch (bs->bs_status) { |
1139 | case BIOC_SSHOTSPARE: |
1140 | { |
1141 | req_hs.cmdcode = ARC_FW_CREATE_HOTSPARE; |
1142 | req_hs.devmask = (1 << bs->bs_target); |
1143 | goto hotspare; |
1144 | } |
1145 | case BIOC_SSDELHOTSPARE: |
1146 | { |
1147 | req_hs.cmdcode = ARC_FW_DELETE_HOTSPARE; |
1148 | req_hs.devmask = (1 << bs->bs_target); |
1149 | goto hotspare; |
1150 | } |
1151 | case BIOC_SSPASSTHRU: |
1152 | { |
1153 | req_pt.cmdcode = ARC_FW_CREATE_PASSTHRU; |
1154 | req_pt.devid = bs->bs_other_id; /* this wants device# */ |
1155 | req_pt.scsi_chan = bs->bs_channel; |
1156 | req_pt.scsi_id = bs->bs_target; |
1157 | req_pt.scsi_lun = bs->bs_lun; |
1158 | req_pt.tagged_queue = 1; /* always enabled */ |
1159 | req_pt.cache_mode = 1; /* always enabled */ |
1160 | req_pt.max_speed = 4; /* always max speed */ |
1161 | |
1162 | error = arc_msgbuf(sc, &req_pt, sizeof(req_pt), |
1163 | reply, sizeof(reply)); |
1164 | if (error != 0) |
1165 | return error; |
1166 | |
1167 | /* |
1168 | * Do a rescan on the bus to attach the new device |
1169 | * associated with the pass-through disk. |
1170 | */ |
1171 | scsibus_sc = device_private(sc->sc_scsibus_dv); |
1172 | (void)scsi_probe_bus(scsibus_sc, bs->bs_target, bs->bs_lun); |
1173 | |
1174 | goto out; |
1175 | } |
1176 | case BIOC_SSDELPASSTHRU: |
1177 | { |
1178 | req_gen[0] = ARC_FW_DELETE_PASSTHRU; |
1179 | req_gen[1] = bs->bs_target; |
1180 | error = arc_msgbuf(sc, &req_gen, sizeof(req_gen), |
1181 | reply, sizeof(reply)); |
1182 | if (error != 0) |
1183 | return error; |
1184 | |
1185 | /* |
1186 | * Detach the sd device associated with this pass-through disk. |
1187 | */ |
1188 | error = scsipi_target_detach(&sc->sc_chan, bs->bs_target, |
1189 | bs->bs_lun, 0); |
1190 | if (error) |
1191 | printf("%s: couldn't detach sd device for the " |
1192 | "pass-through disk at %u:%u.%u (error=%d)\n" , |
1193 | device_xname(sc->sc_dev), |
1194 | bs->bs_channel, bs->bs_target, bs->bs_lun, error); |
1195 | |
1196 | goto out; |
1197 | } |
1198 | case BIOC_SSCHECKSTART_VOL: |
1199 | { |
1200 | req_gen[0] = ARC_FW_START_CHECKVOL; |
1201 | req_gen[1] = bs->bs_volid; |
1202 | error = arc_msgbuf(sc, &req_gen, sizeof(req_gen), |
1203 | reply, sizeof(reply)); |
1204 | if (error != 0) |
1205 | return error; |
1206 | |
1207 | goto out; |
1208 | } |
1209 | case BIOC_SSCHECKSTOP_VOL: |
1210 | { |
1211 | uint8_t req = ARC_FW_STOP_CHECKVOL; |
1212 | error = arc_msgbuf(sc, &req, 1, reply, sizeof(reply)); |
1213 | if (error != 0) |
1214 | return error; |
1215 | |
1216 | goto out; |
1217 | } |
1218 | default: |
1219 | return EOPNOTSUPP; |
1220 | } |
1221 | |
1222 | hotspare: |
1223 | error = arc_msgbuf(sc, &req_hs, sizeof(req_hs), |
1224 | reply, sizeof(reply)); |
1225 | if (error != 0) |
1226 | return error; |
1227 | |
1228 | out: |
1229 | return arc_fw_parse_status_code(sc, &reply[0]); |
1230 | } |
1231 | |
1232 | static int |
1233 | arc_bio_inq(struct arc_softc *sc, struct bioc_inq *bi) |
1234 | { |
1235 | uint8_t request[2]; |
1236 | struct arc_fw_sysinfo *sysinfo = NULL; |
1237 | struct arc_fw_raidinfo *raidinfo; |
1238 | int nvols = 0, i; |
1239 | int error = 0; |
1240 | |
1241 | raidinfo = kmem_zalloc(sizeof(*raidinfo), KM_SLEEP); |
1242 | |
1243 | if (!sc->sc_maxraidset || !sc->sc_maxvolset || !sc->sc_cchans) { |
1244 | sysinfo = kmem_zalloc(sizeof(*sysinfo), KM_SLEEP); |
1245 | |
1246 | request[0] = ARC_FW_SYSINFO; |
1247 | error = arc_msgbuf(sc, request, 1, sysinfo, |
1248 | sizeof(struct arc_fw_sysinfo)); |
1249 | if (error != 0) |
1250 | goto out; |
1251 | |
1252 | sc->sc_maxraidset = sysinfo->max_raid_set; |
1253 | sc->sc_maxvolset = sysinfo->max_volume_set; |
1254 | sc->sc_cchans = sysinfo->ide_channels; |
1255 | } |
1256 | |
1257 | request[0] = ARC_FW_RAIDINFO; |
1258 | for (i = 0; i < sc->sc_maxraidset; i++) { |
1259 | request[1] = i; |
1260 | error = arc_msgbuf(sc, request, sizeof(request), raidinfo, |
1261 | sizeof(struct arc_fw_raidinfo)); |
1262 | if (error != 0) |
1263 | goto out; |
1264 | |
1265 | nvols += raidinfo->volumes; |
1266 | } |
1267 | |
1268 | strlcpy(bi->bi_dev, device_xname(sc->sc_dev), sizeof(bi->bi_dev)); |
1269 | bi->bi_novol = nvols; |
1270 | bi->bi_nodisk = sc->sc_cchans; |
1271 | |
1272 | out: |
1273 | if (sysinfo) |
1274 | kmem_free(sysinfo, sizeof(*sysinfo)); |
1275 | kmem_free(raidinfo, sizeof(*raidinfo)); |
1276 | return error; |
1277 | } |
1278 | |
1279 | static int |
1280 | arc_bio_getvol(struct arc_softc *sc, int vol, struct arc_fw_volinfo *volinfo) |
1281 | { |
1282 | uint8_t request[2]; |
1283 | int error = 0; |
1284 | int nvols = 0, i; |
1285 | |
1286 | request[0] = ARC_FW_VOLINFO; |
1287 | for (i = 0; i < sc->sc_maxvolset; i++) { |
1288 | request[1] = i; |
1289 | error = arc_msgbuf(sc, request, sizeof(request), volinfo, |
1290 | sizeof(struct arc_fw_volinfo)); |
1291 | if (error != 0) |
1292 | goto out; |
1293 | |
1294 | if (volinfo->capacity == 0 && volinfo->capacity2 == 0) |
1295 | continue; |
1296 | |
1297 | if (nvols == vol) |
1298 | break; |
1299 | |
1300 | nvols++; |
1301 | } |
1302 | |
1303 | if (nvols != vol || |
1304 | (volinfo->capacity == 0 && volinfo->capacity2 == 0)) { |
1305 | error = ENODEV; |
1306 | goto out; |
1307 | } |
1308 | |
1309 | out: |
1310 | return error; |
1311 | } |
1312 | |
1313 | static int |
1314 | arc_bio_vol(struct arc_softc *sc, struct bioc_vol *bv) |
1315 | { |
1316 | struct arc_fw_volinfo *volinfo; |
1317 | uint64_t blocks; |
1318 | uint32_t status; |
1319 | int error = 0; |
1320 | |
1321 | volinfo = kmem_zalloc(sizeof(*volinfo), KM_SLEEP); |
1322 | |
1323 | error = arc_bio_getvol(sc, bv->bv_volid, volinfo); |
1324 | if (error != 0) |
1325 | goto out; |
1326 | |
1327 | bv->bv_percent = -1; |
1328 | bv->bv_seconds = 0; |
1329 | |
1330 | status = htole32(volinfo->volume_status); |
1331 | if (status == 0x0) { |
1332 | if (htole32(volinfo->fail_mask) == 0x0) |
1333 | bv->bv_status = BIOC_SVONLINE; |
1334 | else |
1335 | bv->bv_status = BIOC_SVDEGRADED; |
1336 | } else if (status & ARC_FW_VOL_STATUS_NEED_REGEN) { |
1337 | bv->bv_status = BIOC_SVDEGRADED; |
1338 | } else if (status & ARC_FW_VOL_STATUS_FAILED) { |
1339 | bv->bv_status = BIOC_SVOFFLINE; |
1340 | } else if (status & ARC_FW_VOL_STATUS_INITTING) { |
1341 | bv->bv_status = BIOC_SVBUILDING; |
1342 | bv->bv_percent = htole32(volinfo->progress); |
1343 | } else if (status & ARC_FW_VOL_STATUS_REBUILDING) { |
1344 | bv->bv_status = BIOC_SVREBUILD; |
1345 | bv->bv_percent = htole32(volinfo->progress); |
1346 | } else if (status & ARC_FW_VOL_STATUS_MIGRATING) { |
1347 | bv->bv_status = BIOC_SVMIGRATING; |
1348 | bv->bv_percent = htole32(volinfo->progress); |
1349 | } else if (status & ARC_FW_VOL_STATUS_CHECKING) { |
1350 | bv->bv_status = BIOC_SVCHECKING; |
1351 | bv->bv_percent = htole32(volinfo->progress); |
1352 | } else if (status & ARC_FW_VOL_STATUS_NEED_INIT) { |
1353 | bv->bv_status = BIOC_SVOFFLINE; |
1354 | } else { |
1355 | printf("%s: volume %d status 0x%x\n" , |
1356 | device_xname(sc->sc_dev), bv->bv_volid, status); |
1357 | } |
1358 | |
1359 | blocks = (uint64_t)htole32(volinfo->capacity2) << 32; |
1360 | blocks += (uint64_t)htole32(volinfo->capacity); |
1361 | bv->bv_size = blocks * ARC_BLOCKSIZE; /* XXX */ |
1362 | |
1363 | switch (volinfo->raid_level) { |
1364 | case ARC_FW_VOL_RAIDLEVEL_0: |
1365 | bv->bv_level = 0; |
1366 | break; |
1367 | case ARC_FW_VOL_RAIDLEVEL_1: |
1368 | if (volinfo->member_disks > 2) |
1369 | bv->bv_level = BIOC_SVOL_RAID10; |
1370 | else |
1371 | bv->bv_level = 1; |
1372 | break; |
1373 | case ARC_FW_VOL_RAIDLEVEL_3: |
1374 | bv->bv_level = 3; |
1375 | break; |
1376 | case ARC_FW_VOL_RAIDLEVEL_5: |
1377 | bv->bv_level = 5; |
1378 | break; |
1379 | case ARC_FW_VOL_RAIDLEVEL_6: |
1380 | bv->bv_level = 6; |
1381 | break; |
1382 | case ARC_FW_VOL_RAIDLEVEL_PASSTHRU: |
1383 | bv->bv_level = BIOC_SVOL_PASSTHRU; |
1384 | break; |
1385 | default: |
1386 | bv->bv_level = -1; |
1387 | break; |
1388 | } |
1389 | |
1390 | bv->bv_nodisk = volinfo->member_disks; |
1391 | bv->bv_stripe_size = volinfo->stripe_size / 2; |
1392 | snprintf(bv->bv_dev, sizeof(bv->bv_dev), "sd%d" , bv->bv_volid); |
1393 | strnvisx(bv->bv_vendor, sizeof(bv->bv_vendor), volinfo->set_name, |
1394 | sizeof(volinfo->set_name), VIS_TRIM|VIS_SAFE|VIS_OCTAL); |
1395 | |
1396 | out: |
1397 | kmem_free(volinfo, sizeof(*volinfo)); |
1398 | return error; |
1399 | } |
1400 | |
1401 | static int |
1402 | arc_bio_disk_novol(struct arc_softc *sc, struct bioc_disk *bd) |
1403 | { |
1404 | struct arc_fw_diskinfo *diskinfo; |
1405 | uint8_t request[2]; |
1406 | int error = 0; |
1407 | |
1408 | diskinfo = kmem_zalloc(sizeof(*diskinfo), KM_SLEEP); |
1409 | |
1410 | if (bd->bd_diskid >= sc->sc_cchans) { |
1411 | error = ENODEV; |
1412 | goto out; |
1413 | } |
1414 | |
1415 | request[0] = ARC_FW_DISKINFO; |
1416 | request[1] = bd->bd_diskid; |
1417 | error = arc_msgbuf(sc, request, sizeof(request), |
1418 | diskinfo, sizeof(struct arc_fw_diskinfo)); |
1419 | if (error != 0) |
1420 | goto out; |
1421 | |
1422 | /* skip disks with no capacity */ |
1423 | if (htole32(diskinfo->capacity) == 0 && |
1424 | htole32(diskinfo->capacity2) == 0) |
1425 | goto out; |
1426 | |
1427 | bd->bd_disknovol = true; |
1428 | arc_bio_disk_filldata(sc, bd, diskinfo, bd->bd_diskid); |
1429 | |
1430 | out: |
1431 | kmem_free(diskinfo, sizeof(*diskinfo)); |
1432 | return error; |
1433 | } |
1434 | |
1435 | static void |
1436 | arc_bio_disk_filldata(struct arc_softc *sc, struct bioc_disk *bd, |
1437 | struct arc_fw_diskinfo *diskinfo, int diskid) |
1438 | { |
1439 | uint64_t blocks; |
1440 | char model[81]; |
1441 | char serial[41]; |
1442 | char rev[17]; |
1443 | |
1444 | /* Ignore bit zero for now, we don't know what it means */ |
1445 | diskinfo->device_state &= ~0x1; |
1446 | |
1447 | switch (diskinfo->device_state) { |
1448 | case ARC_FW_DISK_FAILED: |
1449 | bd->bd_status = BIOC_SDFAILED; |
1450 | break; |
1451 | case ARC_FW_DISK_PASSTHRU: |
1452 | bd->bd_status = BIOC_SDPASSTHRU; |
1453 | break; |
1454 | case ARC_FW_DISK_NORMAL: |
1455 | bd->bd_status = BIOC_SDONLINE; |
1456 | break; |
1457 | case ARC_FW_DISK_HOTSPARE: |
1458 | bd->bd_status = BIOC_SDHOTSPARE; |
1459 | break; |
1460 | case ARC_FW_DISK_UNUSED: |
1461 | bd->bd_status = BIOC_SDUNUSED; |
1462 | break; |
1463 | case 0: |
1464 | /* disk has been disconnected */ |
1465 | bd->bd_status = BIOC_SDOFFLINE; |
1466 | bd->bd_channel = 1; |
1467 | bd->bd_target = 0; |
1468 | bd->bd_lun = 0; |
1469 | strlcpy(bd->bd_vendor, "disk missing" , sizeof(bd->bd_vendor)); |
1470 | break; |
1471 | default: |
1472 | printf("%s: unknown disk device_state: 0x%x\n" , __func__, |
1473 | diskinfo->device_state); |
1474 | bd->bd_status = BIOC_SDINVALID; |
1475 | return; |
1476 | } |
1477 | |
1478 | blocks = (uint64_t)htole32(diskinfo->capacity2) << 32; |
1479 | blocks += (uint64_t)htole32(diskinfo->capacity); |
1480 | bd->bd_size = blocks * ARC_BLOCKSIZE; /* XXX */ |
1481 | |
1482 | strnvisx(model, sizeof(model), diskinfo->model, |
1483 | sizeof(diskinfo->model), VIS_TRIM|VIS_SAFE|VIS_OCTAL); |
1484 | strnvisx(serial, sizeof(serial), diskinfo->serial, |
1485 | sizeof(diskinfo->serial), VIS_TRIM|VIS_SAFE|VIS_OCTAL); |
1486 | strnvisx(rev, sizeof(rev), diskinfo->firmware_rev, |
1487 | sizeof(diskinfo->firmware_rev), VIS_TRIM|VIS_SAFE|VIS_OCTAL); |
1488 | |
1489 | snprintf(bd->bd_vendor, sizeof(bd->bd_vendor), "%s %s" , model, rev); |
1490 | strlcpy(bd->bd_serial, serial, sizeof(bd->bd_serial)); |
1491 | |
1492 | #if 0 |
1493 | bd->bd_channel = diskinfo->scsi_attr.channel; |
1494 | bd->bd_target = diskinfo->scsi_attr.target; |
1495 | bd->bd_lun = diskinfo->scsi_attr.lun; |
1496 | #endif |
1497 | |
1498 | /* |
1499 | * the firwmare doesnt seem to fill scsi_attr in, so fake it with |
1500 | * the diskid. |
1501 | */ |
1502 | bd->bd_channel = 0; |
1503 | bd->bd_target = diskid; |
1504 | bd->bd_lun = 0; |
1505 | } |
1506 | |
1507 | static int |
1508 | arc_bio_disk_volume(struct arc_softc *sc, struct bioc_disk *bd) |
1509 | { |
1510 | struct arc_fw_raidinfo *raidinfo; |
1511 | struct arc_fw_volinfo *volinfo; |
1512 | struct arc_fw_diskinfo *diskinfo; |
1513 | uint8_t request[2]; |
1514 | int error = 0; |
1515 | |
1516 | volinfo = kmem_zalloc(sizeof(*volinfo), KM_SLEEP); |
1517 | raidinfo = kmem_zalloc(sizeof(*raidinfo), KM_SLEEP); |
1518 | diskinfo = kmem_zalloc(sizeof(*diskinfo), KM_SLEEP); |
1519 | |
1520 | error = arc_bio_getvol(sc, bd->bd_volid, volinfo); |
1521 | if (error != 0) |
1522 | goto out; |
1523 | |
1524 | request[0] = ARC_FW_RAIDINFO; |
1525 | request[1] = volinfo->raid_set_number; |
1526 | |
1527 | error = arc_msgbuf(sc, request, sizeof(request), raidinfo, |
1528 | sizeof(struct arc_fw_raidinfo)); |
1529 | if (error != 0) |
1530 | goto out; |
1531 | |
1532 | if (bd->bd_diskid >= sc->sc_cchans || |
1533 | bd->bd_diskid >= raidinfo->member_devices) { |
1534 | error = ENODEV; |
1535 | goto out; |
1536 | } |
1537 | |
1538 | if (raidinfo->device_array[bd->bd_diskid] == 0xff) { |
1539 | /* |
1540 | * The disk has been disconnected, mark it offline |
1541 | * and put it on another bus. |
1542 | */ |
1543 | bd->bd_channel = 1; |
1544 | bd->bd_target = 0; |
1545 | bd->bd_lun = 0; |
1546 | bd->bd_status = BIOC_SDOFFLINE; |
1547 | strlcpy(bd->bd_vendor, "disk missing" , sizeof(bd->bd_vendor)); |
1548 | goto out; |
1549 | } |
1550 | |
1551 | request[0] = ARC_FW_DISKINFO; |
1552 | request[1] = raidinfo->device_array[bd->bd_diskid]; |
1553 | error = arc_msgbuf(sc, request, sizeof(request), diskinfo, |
1554 | sizeof(struct arc_fw_diskinfo)); |
1555 | if (error != 0) |
1556 | goto out; |
1557 | |
1558 | /* now fill our bio disk with data from the firmware */ |
1559 | arc_bio_disk_filldata(sc, bd, diskinfo, |
1560 | raidinfo->device_array[bd->bd_diskid]); |
1561 | |
1562 | out: |
1563 | kmem_free(raidinfo, sizeof(*raidinfo)); |
1564 | kmem_free(volinfo, sizeof(*volinfo)); |
1565 | kmem_free(diskinfo, sizeof(*diskinfo)); |
1566 | return error; |
1567 | } |
1568 | |
1569 | static uint8_t |
1570 | arc_msg_cksum(void *cmd, uint16_t len) |
1571 | { |
1572 | uint8_t *buf = cmd; |
1573 | uint8_t cksum; |
1574 | int i; |
1575 | |
1576 | cksum = (uint8_t)(len >> 8) + (uint8_t)len; |
1577 | for (i = 0; i < len; i++) |
1578 | cksum += buf[i]; |
1579 | |
1580 | return cksum; |
1581 | } |
1582 | |
1583 | |
1584 | static int |
1585 | arc_msgbuf(struct arc_softc *sc, void *wptr, size_t wbuflen, void *rptr, |
1586 | size_t rbuflen) |
1587 | { |
1588 | uint8_t rwbuf[ARC_REG_IOC_RWBUF_MAXLEN]; |
1589 | uint8_t *wbuf, *rbuf; |
1590 | int wlen, wdone = 0, rlen, rdone = 0; |
1591 | struct arc_fw_bufhdr *bufhdr; |
1592 | uint32_t reg, rwlen; |
1593 | int error = 0; |
1594 | #ifdef ARC_DEBUG |
1595 | int i; |
1596 | #endif |
1597 | |
1598 | wbuf = rbuf = NULL; |
1599 | |
1600 | DNPRINTF(ARC_D_DB, "%s: arc_msgbuf wbuflen: %d rbuflen: %d\n" , |
1601 | device_xname(sc->sc_dev), wbuflen, rbuflen); |
1602 | |
1603 | wlen = sizeof(struct arc_fw_bufhdr) + wbuflen + 1; /* 1 for cksum */ |
1604 | wbuf = kmem_alloc(wlen, KM_SLEEP); |
1605 | |
1606 | rlen = sizeof(struct arc_fw_bufhdr) + rbuflen + 1; /* 1 for cksum */ |
1607 | rbuf = kmem_alloc(rlen, KM_SLEEP); |
1608 | |
1609 | DNPRINTF(ARC_D_DB, "%s: arc_msgbuf wlen: %d rlen: %d\n" , |
1610 | device_xname(sc->sc_dev), wlen, rlen); |
1611 | |
1612 | bufhdr = (struct arc_fw_bufhdr *)wbuf; |
1613 | bufhdr->hdr = arc_fw_hdr; |
1614 | bufhdr->len = htole16(wbuflen); |
1615 | memcpy(wbuf + sizeof(struct arc_fw_bufhdr), wptr, wbuflen); |
1616 | wbuf[wlen - 1] = arc_msg_cksum(wptr, wbuflen); |
1617 | |
1618 | arc_lock(sc); |
1619 | if (arc_read(sc, ARC_REG_OUTB_DOORBELL) != 0) { |
1620 | error = EBUSY; |
1621 | goto out; |
1622 | } |
1623 | |
1624 | reg = ARC_REG_OUTB_DOORBELL_READ_OK; |
1625 | |
1626 | do { |
1627 | if ((reg & ARC_REG_OUTB_DOORBELL_READ_OK) && wdone < wlen) { |
1628 | memset(rwbuf, 0, sizeof(rwbuf)); |
1629 | rwlen = (wlen - wdone) % sizeof(rwbuf); |
1630 | memcpy(rwbuf, &wbuf[wdone], rwlen); |
1631 | |
1632 | #ifdef ARC_DEBUG |
1633 | if (arcdebug & ARC_D_DB) { |
1634 | printf("%s: write %d:" , |
1635 | device_xname(sc->sc_dev), rwlen); |
1636 | for (i = 0; i < rwlen; i++) |
1637 | printf(" 0x%02x" , rwbuf[i]); |
1638 | printf("\n" ); |
1639 | } |
1640 | #endif |
1641 | |
1642 | /* copy the chunk to the hw */ |
1643 | arc_write(sc, ARC_REG_IOC_WBUF_LEN, rwlen); |
1644 | arc_write_region(sc, ARC_REG_IOC_WBUF, rwbuf, |
1645 | sizeof(rwbuf)); |
1646 | |
1647 | /* say we have a buffer for the hw */ |
1648 | arc_write(sc, ARC_REG_INB_DOORBELL, |
1649 | ARC_REG_INB_DOORBELL_WRITE_OK); |
1650 | |
1651 | wdone += rwlen; |
1652 | } |
1653 | |
1654 | while ((reg = arc_read(sc, ARC_REG_OUTB_DOORBELL)) == 0) |
1655 | arc_wait(sc); |
1656 | |
1657 | arc_write(sc, ARC_REG_OUTB_DOORBELL, reg); |
1658 | |
1659 | DNPRINTF(ARC_D_DB, "%s: reg: 0x%08x\n" , |
1660 | device_xname(sc->sc_dev), reg); |
1661 | |
1662 | if ((reg & ARC_REG_OUTB_DOORBELL_WRITE_OK) && rdone < rlen) { |
1663 | rwlen = arc_read(sc, ARC_REG_IOC_RBUF_LEN); |
1664 | if (rwlen > sizeof(rwbuf)) { |
1665 | DNPRINTF(ARC_D_DB, "%s: rwlen too big\n" , |
1666 | device_xname(sc->sc_dev)); |
1667 | error = EIO; |
1668 | goto out; |
1669 | } |
1670 | |
1671 | arc_read_region(sc, ARC_REG_IOC_RBUF, rwbuf, |
1672 | sizeof(rwbuf)); |
1673 | |
1674 | arc_write(sc, ARC_REG_INB_DOORBELL, |
1675 | ARC_REG_INB_DOORBELL_READ_OK); |
1676 | |
1677 | #ifdef ARC_DEBUG |
1678 | printf("%s: len: %d+%d=%d/%d\n" , |
1679 | device_xname(sc->sc_dev), |
1680 | rwlen, rdone, rwlen + rdone, rlen); |
1681 | if (arcdebug & ARC_D_DB) { |
1682 | printf("%s: read:" , |
1683 | device_xname(sc->sc_dev)); |
1684 | for (i = 0; i < rwlen; i++) |
1685 | printf(" 0x%02x" , rwbuf[i]); |
1686 | printf("\n" ); |
1687 | } |
1688 | #endif |
1689 | |
1690 | if ((rdone + rwlen) > rlen) { |
1691 | DNPRINTF(ARC_D_DB, "%s: rwbuf too big\n" , |
1692 | device_xname(sc->sc_dev)); |
1693 | error = EIO; |
1694 | goto out; |
1695 | } |
1696 | |
1697 | memcpy(&rbuf[rdone], rwbuf, rwlen); |
1698 | rdone += rwlen; |
1699 | } |
1700 | } while (rdone != rlen); |
1701 | |
1702 | bufhdr = (struct arc_fw_bufhdr *)rbuf; |
1703 | if (memcmp(&bufhdr->hdr, &arc_fw_hdr, sizeof(bufhdr->hdr)) != 0 || |
1704 | bufhdr->len != htole16(rbuflen)) { |
1705 | DNPRINTF(ARC_D_DB, "%s: rbuf hdr is wrong\n" , |
1706 | device_xname(sc->sc_dev)); |
1707 | error = EIO; |
1708 | goto out; |
1709 | } |
1710 | |
1711 | memcpy(rptr, rbuf + sizeof(struct arc_fw_bufhdr), rbuflen); |
1712 | |
1713 | if (rbuf[rlen - 1] != arc_msg_cksum(rptr, rbuflen)) { |
1714 | DNPRINTF(ARC_D_DB, "%s: invalid cksum\n" , |
1715 | device_xname(sc->sc_dev)); |
1716 | error = EIO; |
1717 | goto out; |
1718 | } |
1719 | |
1720 | out: |
1721 | arc_unlock(sc); |
1722 | kmem_free(wbuf, wlen); |
1723 | kmem_free(rbuf, rlen); |
1724 | |
1725 | return error; |
1726 | } |
1727 | |
1728 | static void |
1729 | arc_lock(struct arc_softc *sc) |
1730 | { |
1731 | rw_enter(&sc->sc_rwlock, RW_WRITER); |
1732 | mutex_spin_enter(&sc->sc_mutex); |
1733 | arc_write(sc, ARC_REG_INTRMASK, ~ARC_REG_INTRMASK_POSTQUEUE); |
1734 | sc->sc_talking = 1; |
1735 | } |
1736 | |
1737 | static void |
1738 | arc_unlock(struct arc_softc *sc) |
1739 | { |
1740 | KASSERT(mutex_owned(&sc->sc_mutex)); |
1741 | |
1742 | arc_write(sc, ARC_REG_INTRMASK, |
1743 | ~(ARC_REG_INTRMASK_POSTQUEUE|ARC_REG_INTRMASK_DOORBELL)); |
1744 | sc->sc_talking = 0; |
1745 | mutex_spin_exit(&sc->sc_mutex); |
1746 | rw_exit(&sc->sc_rwlock); |
1747 | } |
1748 | |
1749 | static void |
1750 | arc_wait(struct arc_softc *sc) |
1751 | { |
1752 | KASSERT(mutex_owned(&sc->sc_mutex)); |
1753 | |
1754 | arc_write(sc, ARC_REG_INTRMASK, |
1755 | ~(ARC_REG_INTRMASK_POSTQUEUE|ARC_REG_INTRMASK_DOORBELL)); |
1756 | if (cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz) == EWOULDBLOCK) |
1757 | arc_write(sc, ARC_REG_INTRMASK, ~ARC_REG_INTRMASK_POSTQUEUE); |
1758 | } |
1759 | |
1760 | |
1761 | static void |
1762 | arc_create_sensors(void *arg) |
1763 | { |
1764 | struct arc_softc *sc = arg; |
1765 | struct bioc_inq bi; |
1766 | struct bioc_vol bv; |
1767 | int i, j; |
1768 | size_t slen, count = 0; |
1769 | |
1770 | memset(&bi, 0, sizeof(bi)); |
1771 | if (arc_bio_inq(sc, &bi) != 0) { |
1772 | aprint_error("%s: unable to query firmware for sensor info\n" , |
1773 | device_xname(sc->sc_dev)); |
1774 | kthread_exit(0); |
1775 | } |
1776 | |
1777 | /* There's no point to continue if there are no volumes */ |
1778 | if (!bi.bi_novol) |
1779 | kthread_exit(0); |
1780 | |
1781 | for (i = 0; i < bi.bi_novol; i++) { |
1782 | memset(&bv, 0, sizeof(bv)); |
1783 | bv.bv_volid = i; |
1784 | if (arc_bio_vol(sc, &bv) != 0) |
1785 | kthread_exit(0); |
1786 | |
1787 | /* Skip passthrough volumes */ |
1788 | if (bv.bv_level == BIOC_SVOL_PASSTHRU) |
1789 | continue; |
1790 | |
1791 | /* new volume found */ |
1792 | sc->sc_nsensors++; |
1793 | /* new disk in a volume found */ |
1794 | sc->sc_nsensors+= bv.bv_nodisk; |
1795 | } |
1796 | |
1797 | /* No valid volumes */ |
1798 | if (!sc->sc_nsensors) |
1799 | kthread_exit(0); |
1800 | |
1801 | sc->sc_sme = sysmon_envsys_create(); |
1802 | slen = sizeof(arc_edata_t) * sc->sc_nsensors; |
1803 | sc->sc_arc_sensors = kmem_zalloc(slen, KM_SLEEP); |
1804 | |
1805 | /* Attach sensors for volumes and disks */ |
1806 | for (i = 0; i < bi.bi_novol; i++) { |
1807 | memset(&bv, 0, sizeof(bv)); |
1808 | bv.bv_volid = i; |
1809 | if (arc_bio_vol(sc, &bv) != 0) |
1810 | goto bad; |
1811 | |
1812 | sc->sc_arc_sensors[count].arc_sensor.units = ENVSYS_DRIVE; |
1813 | sc->sc_arc_sensors[count].arc_sensor.state = ENVSYS_SINVALID; |
1814 | sc->sc_arc_sensors[count].arc_sensor.value_cur = |
1815 | ENVSYS_DRIVE_EMPTY; |
1816 | sc->sc_arc_sensors[count].arc_sensor.flags = |
1817 | ENVSYS_FMONSTCHANGED; |
1818 | |
1819 | /* Skip passthrough volumes */ |
1820 | if (bv.bv_level == BIOC_SVOL_PASSTHRU) |
1821 | continue; |
1822 | |
1823 | if (bv.bv_level == BIOC_SVOL_RAID10) |
1824 | snprintf(sc->sc_arc_sensors[count].arc_sensor.desc, |
1825 | sizeof(sc->sc_arc_sensors[count].arc_sensor.desc), |
1826 | "RAID 1+0 volume%d (%s)" , i, bv.bv_dev); |
1827 | else |
1828 | snprintf(sc->sc_arc_sensors[count].arc_sensor.desc, |
1829 | sizeof(sc->sc_arc_sensors[count].arc_sensor.desc), |
1830 | "RAID %d volume%d (%s)" , bv.bv_level, i, |
1831 | bv.bv_dev); |
1832 | |
1833 | sc->sc_arc_sensors[count].arc_volid = i; |
1834 | |
1835 | if (sysmon_envsys_sensor_attach(sc->sc_sme, |
1836 | &sc->sc_arc_sensors[count].arc_sensor)) |
1837 | goto bad; |
1838 | |
1839 | count++; |
1840 | |
1841 | /* Attach disk sensors for this volume */ |
1842 | for (j = 0; j < bv.bv_nodisk; j++) { |
1843 | sc->sc_arc_sensors[count].arc_sensor.state = |
1844 | ENVSYS_SINVALID; |
1845 | sc->sc_arc_sensors[count].arc_sensor.units = |
1846 | ENVSYS_DRIVE; |
1847 | sc->sc_arc_sensors[count].arc_sensor.value_cur = |
1848 | ENVSYS_DRIVE_EMPTY; |
1849 | sc->sc_arc_sensors[count].arc_sensor.flags = |
1850 | ENVSYS_FMONSTCHANGED; |
1851 | |
1852 | snprintf(sc->sc_arc_sensors[count].arc_sensor.desc, |
1853 | sizeof(sc->sc_arc_sensors[count].arc_sensor.desc), |
1854 | "disk%d volume%d (%s)" , j, i, bv.bv_dev); |
1855 | sc->sc_arc_sensors[count].arc_volid = i; |
1856 | sc->sc_arc_sensors[count].arc_diskid = j + 10; |
1857 | |
1858 | if (sysmon_envsys_sensor_attach(sc->sc_sme, |
1859 | &sc->sc_arc_sensors[count].arc_sensor)) |
1860 | goto bad; |
1861 | |
1862 | count++; |
1863 | } |
1864 | } |
1865 | |
1866 | /* |
1867 | * Register our envsys driver with the framework now that the |
1868 | * sensors were all attached. |
1869 | */ |
1870 | sc->sc_sme->sme_name = device_xname(sc->sc_dev); |
1871 | sc->sc_sme->sme_cookie = sc; |
1872 | sc->sc_sme->sme_refresh = arc_refresh_sensors; |
1873 | |
1874 | if (sysmon_envsys_register(sc->sc_sme)) { |
1875 | aprint_debug("%s: unable to register with sysmon\n" , |
1876 | device_xname(sc->sc_dev)); |
1877 | goto bad; |
1878 | } |
1879 | kthread_exit(0); |
1880 | |
1881 | bad: |
1882 | sysmon_envsys_destroy(sc->sc_sme); |
1883 | kmem_free(sc->sc_arc_sensors, slen); |
1884 | |
1885 | sc->sc_sme = NULL; |
1886 | sc->sc_arc_sensors = NULL; |
1887 | |
1888 | kthread_exit(0); |
1889 | } |
1890 | |
1891 | static void |
1892 | arc_refresh_sensors(struct sysmon_envsys *sme, envsys_data_t *edata) |
1893 | { |
1894 | struct arc_softc *sc = sme->sme_cookie; |
1895 | struct bioc_vol bv; |
1896 | struct bioc_disk bd; |
1897 | arc_edata_t *arcdata = (arc_edata_t *)edata; |
1898 | |
1899 | /* sanity check */ |
1900 | if (edata->units != ENVSYS_DRIVE) |
1901 | return; |
1902 | |
1903 | memset(&bv, 0, sizeof(bv)); |
1904 | bv.bv_volid = arcdata->arc_volid; |
1905 | |
1906 | if (arc_bio_vol(sc, &bv)) { |
1907 | bv.bv_status = BIOC_SVINVALID; |
1908 | bio_vol_to_envsys(edata, &bv); |
1909 | return; |
1910 | } |
1911 | |
1912 | if (arcdata->arc_diskid) { |
1913 | /* Current sensor is handling a disk volume member */ |
1914 | memset(&bd, 0, sizeof(bd)); |
1915 | bd.bd_volid = arcdata->arc_volid; |
1916 | bd.bd_diskid = arcdata->arc_diskid - 10; |
1917 | |
1918 | if (arc_bio_disk_volume(sc, &bd)) |
1919 | bd.bd_status = BIOC_SDOFFLINE; |
1920 | bio_disk_to_envsys(edata, &bd); |
1921 | } else { |
1922 | /* Current sensor is handling a volume */ |
1923 | bio_vol_to_envsys(edata, &bv); |
1924 | } |
1925 | } |
1926 | #endif /* NBIO > 0 */ |
1927 | |
1928 | static uint32_t |
1929 | arc_read(struct arc_softc *sc, bus_size_t r) |
1930 | { |
1931 | uint32_t v; |
1932 | |
1933 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, |
1934 | BUS_SPACE_BARRIER_READ); |
1935 | v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r); |
1936 | |
1937 | DNPRINTF(ARC_D_RW, "%s: arc_read 0x%lx 0x%08x\n" , |
1938 | device_xname(sc->sc_dev), r, v); |
1939 | |
1940 | return v; |
1941 | } |
1942 | |
1943 | static void |
1944 | arc_read_region(struct arc_softc *sc, bus_size_t r, void *buf, size_t len) |
1945 | { |
1946 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, len, |
1947 | BUS_SPACE_BARRIER_READ); |
1948 | bus_space_read_region_4(sc->sc_iot, sc->sc_ioh, r, |
1949 | (uint32_t *)buf, len >> 2); |
1950 | } |
1951 | |
1952 | static void |
1953 | arc_write(struct arc_softc *sc, bus_size_t r, uint32_t v) |
1954 | { |
1955 | DNPRINTF(ARC_D_RW, "%s: arc_write 0x%lx 0x%08x\n" , |
1956 | device_xname(sc->sc_dev), r, v); |
1957 | |
1958 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v); |
1959 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, |
1960 | BUS_SPACE_BARRIER_WRITE); |
1961 | } |
1962 | |
1963 | #if NBIO > 0 |
1964 | static void |
1965 | arc_write_region(struct arc_softc *sc, bus_size_t r, void *buf, size_t len) |
1966 | { |
1967 | bus_space_write_region_4(sc->sc_iot, sc->sc_ioh, r, |
1968 | (const uint32_t *)buf, len >> 2); |
1969 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, len, |
1970 | BUS_SPACE_BARRIER_WRITE); |
1971 | } |
1972 | #endif /* NBIO > 0 */ |
1973 | |
1974 | static int |
1975 | arc_wait_eq(struct arc_softc *sc, bus_size_t r, uint32_t mask, |
1976 | uint32_t target) |
1977 | { |
1978 | int i; |
1979 | |
1980 | DNPRINTF(ARC_D_RW, "%s: arc_wait_eq 0x%lx 0x%08x 0x%08x\n" , |
1981 | device_xname(sc->sc_dev), r, mask, target); |
1982 | |
1983 | for (i = 0; i < 10000; i++) { |
1984 | if ((arc_read(sc, r) & mask) == target) |
1985 | return 0; |
1986 | delay(1000); |
1987 | } |
1988 | |
1989 | return 1; |
1990 | } |
1991 | |
1992 | #if unused |
1993 | static int |
1994 | arc_wait_ne(struct arc_softc *sc, bus_size_t r, uint32_t mask, |
1995 | uint32_t target) |
1996 | { |
1997 | int i; |
1998 | |
1999 | DNPRINTF(ARC_D_RW, "%s: arc_wait_ne 0x%lx 0x%08x 0x%08x\n" , |
2000 | device_xname(sc->sc_dev), r, mask, target); |
2001 | |
2002 | for (i = 0; i < 10000; i++) { |
2003 | if ((arc_read(sc, r) & mask) != target) |
2004 | return 0; |
2005 | delay(1000); |
2006 | } |
2007 | |
2008 | return 1; |
2009 | } |
2010 | #endif |
2011 | |
2012 | static int |
2013 | arc_msg0(struct arc_softc *sc, uint32_t m) |
2014 | { |
2015 | /* post message */ |
2016 | arc_write(sc, ARC_REG_INB_MSG0, m); |
2017 | /* wait for the fw to do it */ |
2018 | if (arc_wait_eq(sc, ARC_REG_INTRSTAT, ARC_REG_INTRSTAT_MSG0, |
2019 | ARC_REG_INTRSTAT_MSG0) != 0) |
2020 | return 1; |
2021 | |
2022 | /* ack it */ |
2023 | arc_write(sc, ARC_REG_INTRSTAT, ARC_REG_INTRSTAT_MSG0); |
2024 | |
2025 | return 0; |
2026 | } |
2027 | |
2028 | static struct arc_dmamem * |
2029 | arc_dmamem_alloc(struct arc_softc *sc, size_t size) |
2030 | { |
2031 | struct arc_dmamem *adm; |
2032 | int nsegs; |
2033 | |
2034 | adm = kmem_zalloc(sizeof(*adm), KM_NOSLEEP); |
2035 | if (adm == NULL) |
2036 | return NULL; |
2037 | |
2038 | adm->adm_size = size; |
2039 | |
2040 | if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, |
2041 | BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &adm->adm_map) != 0) |
2042 | goto admfree; |
2043 | |
2044 | if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &adm->adm_seg, |
2045 | 1, &nsegs, BUS_DMA_NOWAIT) != 0) |
2046 | goto destroy; |
2047 | |
2048 | if (bus_dmamem_map(sc->sc_dmat, &adm->adm_seg, nsegs, size, |
2049 | &adm->adm_kva, BUS_DMA_NOWAIT|BUS_DMA_COHERENT) != 0) |
2050 | goto free; |
2051 | |
2052 | if (bus_dmamap_load(sc->sc_dmat, adm->adm_map, adm->adm_kva, size, |
2053 | NULL, BUS_DMA_NOWAIT) != 0) |
2054 | goto unmap; |
2055 | |
2056 | memset(adm->adm_kva, 0, size); |
2057 | |
2058 | return adm; |
2059 | |
2060 | unmap: |
2061 | bus_dmamem_unmap(sc->sc_dmat, adm->adm_kva, size); |
2062 | free: |
2063 | bus_dmamem_free(sc->sc_dmat, &adm->adm_seg, 1); |
2064 | destroy: |
2065 | bus_dmamap_destroy(sc->sc_dmat, adm->adm_map); |
2066 | admfree: |
2067 | kmem_free(adm, sizeof(*adm)); |
2068 | |
2069 | return NULL; |
2070 | } |
2071 | |
2072 | static void |
2073 | arc_dmamem_free(struct arc_softc *sc, struct arc_dmamem *adm) |
2074 | { |
2075 | bus_dmamap_unload(sc->sc_dmat, adm->adm_map); |
2076 | bus_dmamem_unmap(sc->sc_dmat, adm->adm_kva, adm->adm_size); |
2077 | bus_dmamem_free(sc->sc_dmat, &adm->adm_seg, 1); |
2078 | bus_dmamap_destroy(sc->sc_dmat, adm->adm_map); |
2079 | kmem_free(adm, sizeof(*adm)); |
2080 | } |
2081 | |
2082 | static int |
2083 | arc_alloc_ccbs(device_t self) |
2084 | { |
2085 | struct arc_softc *sc = device_private(self); |
2086 | struct arc_ccb *ccb; |
2087 | uint8_t *cmd; |
2088 | int i; |
2089 | size_t ccbslen; |
2090 | |
2091 | TAILQ_INIT(&sc->sc_ccb_free); |
2092 | |
2093 | ccbslen = sizeof(struct arc_ccb) * sc->sc_req_count; |
2094 | sc->sc_ccbs = kmem_zalloc(ccbslen, KM_SLEEP); |
2095 | |
2096 | sc->sc_requests = arc_dmamem_alloc(sc, |
2097 | ARC_MAX_IOCMDLEN * sc->sc_req_count); |
2098 | if (sc->sc_requests == NULL) { |
2099 | aprint_error_dev(self, "unable to allocate ccb dmamem\n" ); |
2100 | goto free_ccbs; |
2101 | } |
2102 | cmd = ARC_DMA_KVA(sc->sc_requests); |
2103 | |
2104 | for (i = 0; i < sc->sc_req_count; i++) { |
2105 | ccb = &sc->sc_ccbs[i]; |
2106 | |
2107 | if (bus_dmamap_create(sc->sc_dmat, MAXPHYS, ARC_SGL_MAXLEN, |
2108 | MAXPHYS, 0, 0, &ccb->ccb_dmamap) != 0) { |
2109 | aprint_error_dev(self, |
2110 | "unable to create dmamap for ccb %d\n" , i); |
2111 | goto free_maps; |
2112 | } |
2113 | |
2114 | ccb->ccb_sc = sc; |
2115 | ccb->ccb_id = i; |
2116 | ccb->ccb_offset = ARC_MAX_IOCMDLEN * i; |
2117 | |
2118 | ccb->ccb_cmd = (struct arc_io_cmd *)&cmd[ccb->ccb_offset]; |
2119 | ccb->ccb_cmd_post = (ARC_DMA_DVA(sc->sc_requests) + |
2120 | ccb->ccb_offset) >> ARC_REG_POST_QUEUE_ADDR_SHIFT; |
2121 | |
2122 | arc_put_ccb(sc, ccb); |
2123 | } |
2124 | |
2125 | return 0; |
2126 | |
2127 | free_maps: |
2128 | while ((ccb = arc_get_ccb(sc)) != NULL) |
2129 | bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap); |
2130 | arc_dmamem_free(sc, sc->sc_requests); |
2131 | |
2132 | free_ccbs: |
2133 | kmem_free(sc->sc_ccbs, ccbslen); |
2134 | |
2135 | return 1; |
2136 | } |
2137 | |
2138 | static struct arc_ccb * |
2139 | arc_get_ccb(struct arc_softc *sc) |
2140 | { |
2141 | struct arc_ccb *ccb; |
2142 | |
2143 | ccb = TAILQ_FIRST(&sc->sc_ccb_free); |
2144 | if (ccb != NULL) |
2145 | TAILQ_REMOVE(&sc->sc_ccb_free, ccb, ccb_link); |
2146 | |
2147 | return ccb; |
2148 | } |
2149 | |
2150 | static void |
2151 | arc_put_ccb(struct arc_softc *sc, struct arc_ccb *ccb) |
2152 | { |
2153 | ccb->ccb_xs = NULL; |
2154 | memset(ccb->ccb_cmd, 0, ARC_MAX_IOCMDLEN); |
2155 | TAILQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_link); |
2156 | } |
2157 | |