Annotation of sys/dev/pci/ips.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ips.c,v 1.29 2007/06/06 20:51:13 grange Exp $ */
2:
3: /*
4: * Copyright (c) 2006, 2007 Alexander Yurchenko <grange@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: /*
20: * IBM (Adaptec) ServeRAID controller driver.
21: */
22:
23: #include <sys/param.h>
24: #include <sys/systm.h>
25: #include <sys/buf.h>
26: #include <sys/device.h>
27: #include <sys/kernel.h>
28: #include <sys/malloc.h>
29: #include <sys/timeout.h>
30: #include <sys/queue.h>
31:
32: #include <machine/bus.h>
33:
34: #include <scsi/scsi_all.h>
35: #include <scsi/scsi_disk.h>
36: #include <scsi/scsiconf.h>
37:
38: #include <dev/pci/pcidevs.h>
39: #include <dev/pci/pcireg.h>
40: #include <dev/pci/pcivar.h>
41:
42: #define IPS_DEBUG /* XXX: remove when driver becomes stable */
43:
44: /* Debug levels */
45: #define IPS_D_ERR 0x0001 /* errors */
46: #define IPS_D_INFO 0x0002 /* information */
47: #define IPS_D_XFER 0x0004 /* transfers */
48:
49: #ifdef IPS_DEBUG
50: #define DPRINTF(a, b) do { if (ips_debug & (a)) printf b; } while (0)
51: int ips_debug = IPS_D_ERR;
52: #else
53: #define DPRINTF(a, b)
54: #endif
55:
56: #define IPS_MAXDRIVES 8
57: #define IPS_MAXCHANS 4
58: #define IPS_MAXTARGETS 15
59: #define IPS_MAXCMDS 128
60:
61: #define IPS_MAXFER (64 * 1024)
62: #define IPS_MAXSGS 16
63: #define IPS_MAXCMDSZ (IPS_CMDSZ + IPS_MAXSGS * IPS_SGSZ)
64:
65: #define IPS_CMDSZ sizeof(struct ips_cmd)
66: #define IPS_SGSZ sizeof(struct ips_sg)
67: #define IPS_SECSZ 512
68:
69: /* Command codes */
70: #define IPS_CMD_READ 0x02
71: #define IPS_CMD_WRITE 0x03
72: #define IPS_CMD_DCDB 0x04
73: #define IPS_CMD_GETADAPTERINFO 0x05
74: #define IPS_CMD_FLUSH 0x0a
75: #define IPS_CMD_ERRORTABLE 0x17
76: #define IPS_CMD_GETDRIVEINFO 0x19
77: #define IPS_CMD_RESETCHAN 0x1a
78: #define IPS_CMD_DOWNLOAD 0x20
79: #define IPS_CMD_RWBIOSFW 0x22
80: #define IPS_CMD_READCONF 0x38
81: #define IPS_CMD_GETSUBSYS 0x40
82: #define IPS_CMD_CONFIGSYNC 0x58
83: #define IPS_CMD_READ_SG 0x82
84: #define IPS_CMD_WRITE_SG 0x83
85: #define IPS_CMD_DCDB_SG 0x84
86: #define IPS_CMD_EXT_DCDB 0x95
87: #define IPS_CMD_EXT_DCDB_SG 0x96
88: #define IPS_CMD_RWNVRAMPAGE 0xbc
89: #define IPS_CMD_GETVERINFO 0xc6
90: #define IPS_CMD_FFDC 0xd7
91: #define IPS_CMD_SG 0x80
92:
93: /* Register definitions */
94: #define IPS_REG_HIS 0x08 /* host interrupt status */
95: #define IPS_REG_HIS_SCE 0x01 /* status channel enqueue */
96: #define IPS_REG_HIS_EN 0x80 /* enable interrupts */
97: #define IPS_REG_CCSA 0x10 /* command channel system address */
98: #define IPS_REG_CCC 0x14 /* command channel control */
99: #define IPS_REG_CCC_SEM 0x0008 /* semaphore */
100: #define IPS_REG_CCC_START 0x101a /* start command */
101: #define IPS_REG_OIS 0x30 /* outbound interrupt status */
102: #define IPS_REG_OIS_PEND 0x0008 /* interrupt is pending */
103: #define IPS_REG_OIM 0x34 /* outbound interrupt mask */
104: #define IPS_REG_OIM_DS 0x0008 /* disable interrupts */
105: #define IPS_REG_IQP 0x40 /* inbound queue port */
106: #define IPS_REG_OQP 0x44 /* outbound queue port */
107:
108: #define IPS_REG_STAT_ID(x) (((x) >> 8) & 0xff)
109: #define IPS_REG_STAT_BASIC(x) (((x) >> 16) & 0xff)
110: #define IPS_REG_STAT_GSC(x) (((x) >> 16) & 0x0f)
111: #define IPS_REG_STAT_EXT(x) (((x) >> 24) & 0xff)
112:
113: /* Command frame */
114: struct ips_cmd {
115: u_int8_t code;
116: u_int8_t id;
117: u_int8_t drive;
118: u_int8_t sgcnt;
119: u_int32_t lba;
120: u_int32_t sgaddr;
121: u_int16_t seccnt;
122: u_int8_t seg4g;
123: u_int8_t esg;
124: u_int32_t ccsar;
125: u_int32_t cccr;
126: };
127:
128: /* Scatter-gather array element */
129: struct ips_sg {
130: u_int32_t addr;
131: u_int32_t size;
132: };
133:
134: /* Data frames */
135: struct ips_adapterinfo {
136: u_int8_t drivecnt;
137: u_int8_t miscflag;
138: u_int8_t sltflag;
139: u_int8_t bstflag;
140: u_int8_t pwrchgcnt;
141: u_int8_t wrongaddrcnt;
142: u_int8_t unidentcnt;
143: u_int8_t nvramdevchgcnt;
144: u_int8_t codeblkver[8];
145: u_int8_t bootblkver[8];
146: u_int32_t drivesize[IPS_MAXDRIVES];
147: u_int8_t cmdcnt;
148: u_int8_t maxphysdevs;
149: u_int16_t flashrepgmcnt;
150: u_int8_t defunctdiskcnt;
151: u_int8_t rebuildflag;
152: u_int8_t offdrivecnt;
153: u_int8_t critdrivecnt;
154: u_int16_t confupdcnt;
155: u_int8_t blkflag;
156: u_int8_t __reserved;
157: u_int16_t deaddisk[IPS_MAXCHANS * (IPS_MAXTARGETS + 1)];
158: };
159:
160: struct ips_driveinfo {
161: u_int8_t drivecnt;
162: u_int8_t __reserved[3];
163: struct ips_drive {
164: u_int8_t id;
165: u_int8_t __reserved;
166: u_int8_t raid;
167: u_int8_t state;
168: u_int32_t seccnt;
169: } drive[IPS_MAXDRIVES];
170: };
171:
172: /* Command control block */
173: struct ips_ccb {
174: int c_id; /* command id */
175: int c_flags; /* flags */
176: #define IPS_CCB_READ 0x0001
177: #define IPS_CCB_WRITE 0x0002
178: #define IPS_CCB_POLL 0x0004
179: #define IPS_CCB_RUN 0x0008
180:
181: void * c_cmdva; /* command frame virt addr */
182: paddr_t c_cmdpa; /* command frame phys addr */
183: bus_dmamap_t c_dmam; /* data buffer DMA map */
184: struct scsi_xfer * c_xfer; /* corresponding SCSI xfer */
185: int c_stat; /* status word copy */
186: int c_estat; /* ext status word copy */
187:
188: TAILQ_ENTRY(ips_ccb) c_link; /* queue link */
189: };
190:
191: /* CCB queue */
192: TAILQ_HEAD(ips_ccbq, ips_ccb);
193:
194: /* DMA-able chunk of memory */
195: struct dmamem {
196: bus_dma_tag_t dm_tag;
197: bus_dmamap_t dm_map;
198: bus_dma_segment_t dm_seg;
199: bus_size_t dm_size;
200: void * dm_vaddr;
201: #define dm_paddr dm_seg.ds_addr
202: };
203:
204: struct ips_softc {
205: struct device sc_dev;
206:
207: struct scsi_link sc_scsi_link;
208:
209: bus_space_tag_t sc_iot;
210: bus_space_handle_t sc_ioh;
211: bus_dma_tag_t sc_dmat;
212:
213: const struct ips_chipset *sc_chip;
214:
215: struct ips_driveinfo sc_di;
216: int sc_nunits;
217:
218: struct dmamem sc_cmdm;
219:
220: struct ips_ccb * sc_ccb;
221: int sc_nccbs;
222: struct ips_ccbq sc_ccbq_free;
223: struct ips_ccbq sc_ccbq_run;
224: };
225:
226: int ips_match(struct device *, void *, void *);
227: void ips_attach(struct device *, struct device *, void *);
228:
229: int ips_scsi_cmd(struct scsi_xfer *);
230:
231: int ips_cmd(struct ips_softc *, int, int, u_int32_t, void *, size_t, int,
232: struct scsi_xfer *);
233: int ips_poll(struct ips_softc *, struct ips_ccb *);
234: void ips_done(struct ips_softc *, struct ips_ccb *);
235: int ips_intr(void *);
236:
237: int ips_getadapterinfo(struct ips_softc *, struct ips_adapterinfo *);
238: int ips_getdriveinfo(struct ips_softc *, struct ips_driveinfo *);
239: int ips_flush(struct ips_softc *);
240:
241: void ips_copperhead_exec(struct ips_softc *, struct ips_ccb *);
242: void ips_copperhead_init(struct ips_softc *);
243: void ips_copperhead_intren(struct ips_softc *);
244: int ips_copperhead_isintr(struct ips_softc *);
245: int ips_copperhead_reset(struct ips_softc *);
246: u_int32_t ips_copperhead_status(struct ips_softc *);
247:
248: void ips_morpheus_exec(struct ips_softc *, struct ips_ccb *);
249: void ips_morpheus_init(struct ips_softc *);
250: void ips_morpheus_intren(struct ips_softc *);
251: int ips_morpheus_isintr(struct ips_softc *);
252: int ips_morpheus_reset(struct ips_softc *);
253: u_int32_t ips_morpheus_status(struct ips_softc *);
254:
255: struct ips_ccb *ips_ccb_alloc(struct ips_softc *, int);
256: void ips_ccb_free(struct ips_softc *, struct ips_ccb *, int);
257: struct ips_ccb *ips_ccb_get(struct ips_softc *);
258: void ips_ccb_put(struct ips_softc *, struct ips_ccb *);
259:
260: int ips_dmamem_alloc(struct dmamem *, bus_dma_tag_t, bus_size_t);
261: void ips_dmamem_free(struct dmamem *);
262:
263: struct cfattach ips_ca = {
264: sizeof(struct ips_softc),
265: ips_match,
266: ips_attach
267: };
268:
269: struct cfdriver ips_cd = {
270: NULL, "ips", DV_DULL
271: };
272:
273: static struct scsi_adapter ips_scsi_adapter = {
274: ips_scsi_cmd,
275: minphys,
276: NULL,
277: NULL,
278: NULL
279: };
280:
281: static struct scsi_device ips_scsi_device = {
282: NULL,
283: NULL,
284: NULL,
285: NULL
286: };
287:
288: static const struct pci_matchid ips_ids[] = {
289: { PCI_VENDOR_IBM, PCI_PRODUCT_IBM_SERVERAID },
290: { PCI_VENDOR_IBM, PCI_PRODUCT_IBM_SERVERAID2 },
291: { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_SERVERAID }
292: };
293:
294: static const struct ips_chipset {
295: const char * ic_name;
296: int ic_bar;
297:
298: void (*ic_exec)(struct ips_softc *, struct ips_ccb *);
299: void (*ic_init)(struct ips_softc *);
300: void (*ic_intren)(struct ips_softc *);
301: int (*ic_isintr)(struct ips_softc *);
302: int (*ic_reset)(struct ips_softc *);
303: u_int32_t (*ic_status)(struct ips_softc *);
304: } ips_chips[] = {
305: {
306: "Copperhead",
307: 0x14,
308: ips_copperhead_exec,
309: ips_copperhead_init,
310: ips_copperhead_intren,
311: ips_copperhead_isintr,
312: ips_copperhead_reset,
313: ips_copperhead_status
314: },
315: {
316: "Morpheus",
317: 0x10,
318: ips_morpheus_exec,
319: ips_morpheus_init,
320: ips_morpheus_intren,
321: ips_morpheus_isintr,
322: ips_morpheus_reset,
323: ips_morpheus_status
324: }
325: };
326:
327: enum {
328: IPS_CHIP_COPPERHEAD = 0,
329: IPS_CHIP_MORPHEUS
330: };
331:
332: #define ips_exec(s, c) (s)->sc_chip->ic_exec((s), (c))
333: #define ips_init(s) (s)->sc_chip->ic_init((s))
334: #define ips_intren(s) (s)->sc_chip->ic_intren((s))
335: #define ips_isintr(s) (s)->sc_chip->ic_isintr((s))
336: #define ips_reset(s) (s)->sc_chip->ic_reset((s))
337: #define ips_status(s) (s)->sc_chip->ic_status((s))
338:
339: int
340: ips_match(struct device *parent, void *match, void *aux)
341: {
342: return (pci_matchbyid(aux, ips_ids,
343: sizeof(ips_ids) / sizeof(ips_ids[0])));
344: }
345:
346: void
347: ips_attach(struct device *parent, struct device *self, void *aux)
348: {
349: struct ips_softc *sc = (struct ips_softc *)self;
350: struct pci_attach_args *pa = aux;
351: struct ips_ccb ccb0;
352: struct scsibus_attach_args saa;
353: struct ips_adapterinfo ai;
354: pcireg_t maptype;
355: bus_size_t iosize;
356: pci_intr_handle_t ih;
357: const char *intrstr;
358: int i;
359:
360: sc->sc_dmat = pa->pa_dmat;
361:
362: /* Identify chipset */
363: switch (PCI_PRODUCT(pa->pa_id)) {
364: case PCI_PRODUCT_IBM_SERVERAID:
365: sc->sc_chip = &ips_chips[IPS_CHIP_COPPERHEAD];
366: break;
367: case PCI_PRODUCT_IBM_SERVERAID2:
368: case PCI_PRODUCT_ADP2_SERVERAID:
369: sc->sc_chip = &ips_chips[IPS_CHIP_MORPHEUS];
370: break;
371: default:
372: printf(": unsupported chipset\n");
373: return;
374: }
375:
376: /* Map registers */
377: maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, sc->sc_chip->ic_bar);
378: if (pci_mapreg_map(pa, sc->sc_chip->ic_bar, maptype, 0, &sc->sc_iot,
379: &sc->sc_ioh, NULL, &iosize, 0)) {
380: printf(": can't map registers\n");
381: return;
382: }
383:
384: /* Initialize hardware */
385: ips_init(sc);
386:
387: /* Allocate command buffer */
388: if (ips_dmamem_alloc(&sc->sc_cmdm, sc->sc_dmat,
389: IPS_MAXCMDS * IPS_MAXCMDSZ)) {
390: printf(": can't allocate command buffer\n");
391: goto fail1;
392: }
393:
394: /* Bootstrap CCB queue */
395: sc->sc_nccbs = 1;
396: sc->sc_ccb = &ccb0;
397: bzero(&ccb0, sizeof(ccb0));
398: ccb0.c_cmdva = sc->sc_cmdm.dm_vaddr;
399: ccb0.c_cmdpa = sc->sc_cmdm.dm_paddr;
400: if (bus_dmamap_create(sc->sc_dmat, IPS_MAXFER, IPS_MAXSGS,
401: IPS_MAXFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
402: &ccb0.c_dmam)) {
403: printf(": can't bootstrap CCB queue\n");
404: goto fail2;
405: }
406: TAILQ_INIT(&sc->sc_ccbq_free);
407: TAILQ_INIT(&sc->sc_ccbq_run);
408: TAILQ_INSERT_TAIL(&sc->sc_ccbq_free, &ccb0, c_link);
409:
410: /* Get adapter info */
411: if (ips_getadapterinfo(sc, &ai)) {
412: printf(": can't get adapter info\n");
413: bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
414: goto fail2;
415: }
416:
417: /* Get logical drives info */
418: if (ips_getdriveinfo(sc, &sc->sc_di)) {
419: printf(": can't get logical drives info\n");
420: bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
421: goto fail2;
422: }
423: sc->sc_nunits = sc->sc_di.drivecnt;
424:
425: bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
426:
427: /* Initialize CCB queue */
428: sc->sc_nccbs = ai.cmdcnt;
429: if ((sc->sc_ccb = ips_ccb_alloc(sc, sc->sc_nccbs)) == NULL) {
430: printf(": can't allocate CCB queue\n");
431: goto fail2;
432: }
433: TAILQ_INIT(&sc->sc_ccbq_free);
434: TAILQ_INIT(&sc->sc_ccbq_run);
435: for (i = 0; i < sc->sc_nccbs; i++)
436: TAILQ_INSERT_TAIL(&sc->sc_ccbq_free,
437: &sc->sc_ccb[i], c_link);
438:
439: /* Install interrupt handler */
440: if (pci_intr_map(pa, &ih)) {
441: printf(": can't map interrupt\n");
442: goto fail3;
443: }
444: intrstr = pci_intr_string(pa->pa_pc, ih);
445: if (pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ips_intr, sc,
446: sc->sc_dev.dv_xname) == NULL) {
447: printf(": can't establish interrupt");
448: if (intrstr != NULL)
449: printf(" at %s", intrstr);
450: printf("\n");
451: goto fail3;
452: }
453: printf(": %s\n", intrstr);
454:
455: /* Display adapter info */
456: printf("%s", sc->sc_dev.dv_xname);
457: printf(": %s", sc->sc_chip->ic_name);
458: printf(", firmware %c%c%c%c%c%c%c",
459: ai.codeblkver[0], ai.codeblkver[1], ai.codeblkver[2],
460: ai.codeblkver[3], ai.codeblkver[4], ai.codeblkver[5],
461: ai.codeblkver[6]);
462: printf(", bootblock %c%c%c%c%c%c%c",
463: ai.bootblkver[0], ai.bootblkver[1], ai.bootblkver[2],
464: ai.bootblkver[3], ai.bootblkver[4], ai.bootblkver[5],
465: ai.bootblkver[6]);
466: printf(", %d CCBs, %d units", sc->sc_nccbs, sc->sc_nunits);
467: printf("\n");
468:
469: /* Attach SCSI bus */
470: if (sc->sc_nunits > 0)
471: sc->sc_scsi_link.openings = sc->sc_nccbs / sc->sc_nunits;
472: sc->sc_scsi_link.adapter_target = sc->sc_nunits;
473: sc->sc_scsi_link.adapter_buswidth = sc->sc_nunits;
474: sc->sc_scsi_link.device = &ips_scsi_device;
475: sc->sc_scsi_link.adapter = &ips_scsi_adapter;
476: sc->sc_scsi_link.adapter_softc = sc;
477:
478: bzero(&saa, sizeof(saa));
479: saa.saa_sc_link = &sc->sc_scsi_link;
480: config_found(self, &saa, scsiprint);
481:
482: /* Enable interrupts */
483: ips_intren(sc);
484:
485: return;
486: fail3:
487: ips_ccb_free(sc, sc->sc_ccb, sc->sc_nccbs);
488: fail2:
489: ips_dmamem_free(&sc->sc_cmdm);
490: fail1:
491: bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
492: }
493:
494: int
495: ips_scsi_cmd(struct scsi_xfer *xs)
496: {
497: struct scsi_link *link = xs->sc_link;
498: struct ips_softc *sc = link->adapter_softc;
499: struct ips_drive *drive;
500: struct scsi_inquiry_data *id;
501: struct scsi_read_cap_data *rcd;
502: struct scsi_sense_data *sd;
503: struct scsi_rw *rw;
504: struct scsi_rw_big *rwb;
505: int target = link->target;
506: u_int32_t blkno, blkcnt;
507: int cmd, error, flags, s;
508:
509: if (target >= sc->sc_nunits || link->lun != 0) {
510: DPRINTF(IPS_D_INFO, ("%s: invalid scsi command, "
511: "target %d, lun %d\n", sc->sc_dev.dv_xname,
512: target, link->lun));
513: xs->error = XS_DRIVER_STUFFUP;
514: s = splbio();
515: scsi_done(xs);
516: splx(s);
517: return (COMPLETE);
518: }
519:
520: s = splbio();
521: drive = &sc->sc_di.drive[target];
522: xs->error = XS_NOERROR;
523:
524: /* Fake SCSI commands */
525: switch (xs->cmd->opcode) {
526: case READ_BIG:
527: case READ_COMMAND:
528: case WRITE_BIG:
529: case WRITE_COMMAND:
530: if (xs->cmdlen == sizeof(struct scsi_rw)) {
531: rw = (void *)xs->cmd;
532: blkno = _3btol(rw->addr) &
533: (SRW_TOPADDR << 16 | 0xffff);
534: blkcnt = rw->length ? rw->length : 0x100;
535: } else {
536: rwb = (void *)xs->cmd;
537: blkno = _4btol(rwb->addr);
538: blkcnt = _2btol(rwb->length);
539: }
540:
541: if (blkno >= letoh32(drive->seccnt) || blkno + blkcnt >
542: letoh32(drive->seccnt)) {
543: DPRINTF(IPS_D_ERR, ("%s: invalid scsi command, "
544: "blkno %u, blkcnt %u\n", sc->sc_dev.dv_xname,
545: blkno, blkcnt));
546: xs->error = XS_DRIVER_STUFFUP;
547: scsi_done(xs);
548: break;
549: }
550:
551: if (xs->flags & SCSI_DATA_IN) {
552: cmd = IPS_CMD_READ;
553: flags = IPS_CCB_READ;
554: } else {
555: cmd = IPS_CMD_WRITE;
556: flags = IPS_CCB_WRITE;
557: }
558: if (xs->flags & SCSI_POLL)
559: flags |= IPS_CCB_POLL;
560:
561: if ((error = ips_cmd(sc, cmd, target, blkno, xs->data,
562: blkcnt * IPS_SECSZ, flags, xs))) {
563: if (error == ENOMEM) {
564: splx(s);
565: return (NO_CCB);
566: } else if (flags & IPS_CCB_POLL) {
567: splx(s);
568: return (TRY_AGAIN_LATER);
569: } else {
570: xs->error = XS_DRIVER_STUFFUP;
571: scsi_done(xs);
572: break;
573: }
574: }
575:
576: splx(s);
577: if (flags & IPS_CCB_POLL)
578: return (COMPLETE);
579: else
580: return (SUCCESSFULLY_QUEUED);
581: case INQUIRY:
582: id = (void *)xs->data;
583: bzero(id, sizeof(*id));
584: id->device = T_DIRECT;
585: id->version = 2;
586: id->response_format = 2;
587: id->additional_length = 32;
588: strlcpy(id->vendor, "IBM ", sizeof(id->vendor));
589: snprintf(id->product, sizeof(id->product),
590: "ServeRAID RAID%d #%02d", drive->raid, target);
591: strlcpy(id->revision, " ", sizeof(id->revision));
592: break;
593: case READ_CAPACITY:
594: rcd = (void *)xs->data;
595: bzero(rcd, sizeof(*rcd));
596: _lto4b(letoh32(drive->seccnt) - 1, rcd->addr);
597: _lto4b(IPS_SECSZ, rcd->length);
598: break;
599: case REQUEST_SENSE:
600: sd = (void *)xs->data;
601: bzero(sd, sizeof(*sd));
602: sd->error_code = SSD_ERRCODE_CURRENT;
603: sd->flags = SKEY_NO_SENSE;
604: break;
605: case SYNCHRONIZE_CACHE:
606: if (ips_flush(sc))
607: xs->error = XS_DRIVER_STUFFUP;
608: break;
609: case PREVENT_ALLOW:
610: case START_STOP:
611: case TEST_UNIT_READY:
612: break;
613: default:
614: DPRINTF(IPS_D_INFO, ("%s: unsupported scsi command 0x%02x\n",
615: sc->sc_dev.dv_xname, xs->cmd->opcode));
616: xs->error = XS_DRIVER_STUFFUP;
617: }
618: scsi_done(xs);
619: splx(s);
620:
621: return (COMPLETE);
622: }
623:
624: int
625: ips_cmd(struct ips_softc *sc, int code, int drive, u_int32_t lba, void *data,
626: size_t size, int flags, struct scsi_xfer *xs)
627: {
628: struct ips_cmd *cmd;
629: struct ips_sg *sg;
630: struct ips_ccb *ccb;
631: int nsegs, i, error = 0;
632:
633: DPRINTF(IPS_D_XFER, ("%s: cmd code 0x%02x, drive %d, lba %u, "
634: "size %lu, flags 0x%02x\n", sc->sc_dev.dv_xname, code, drive, lba,
635: (u_long)size, flags));
636:
637: /* Grab free CCB */
638: if ((ccb = ips_ccb_get(sc)) == NULL) {
639: DPRINTF(IPS_D_ERR, ("%s: no free CCB\n", sc->sc_dev.dv_xname));
640: return (ENOMEM);
641: }
642:
643: ccb->c_flags = flags;
644: ccb->c_xfer = xs;
645:
646: /* Fill in command frame */
647: cmd = ccb->c_cmdva;
648: cmd->code = code;
649: cmd->id = ccb->c_id;
650: cmd->drive = drive;
651: cmd->lba = htole32(lba);
652: cmd->seccnt = htole16(howmany(size, IPS_SECSZ));
653:
654: if (size > 0) {
655: /* Map data buffer into DMA segments */
656: if (bus_dmamap_load(sc->sc_dmat, ccb->c_dmam, data, size,
657: NULL, BUS_DMA_NOWAIT)) {
658: printf("%s: can't load DMA map\n",
659: sc->sc_dev.dv_xname);
660: return (1); /* XXX: return code */
661: }
662: bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,
663: ccb->c_dmam->dm_mapsize,
664: flags & IPS_CCB_READ ? BUS_DMASYNC_PREREAD :
665: BUS_DMASYNC_PREWRITE);
666:
667: if ((nsegs = ccb->c_dmam->dm_nsegs) > IPS_MAXSGS) {
668: printf("%s: too many DMA segments\n",
669: sc->sc_dev.dv_xname);
670: return (1); /* XXX: return code */
671: }
672:
673: if (nsegs > 1) {
674: cmd->code |= IPS_CMD_SG;
675: cmd->sgcnt = nsegs;
676: cmd->sgaddr = htole32(ccb->c_cmdpa + IPS_CMDSZ);
677:
678: /* Fill in scatter-gather array */
679: sg = (void *)(cmd + 1);
680: for (i = 0; i < nsegs; i++) {
681: sg[i].addr =
682: htole32(ccb->c_dmam->dm_segs[i].ds_addr);
683: sg[i].size =
684: htole32(ccb->c_dmam->dm_segs[i].ds_len);
685: }
686: } else {
687: cmd->sgcnt = 0;
688: cmd->sgaddr = htole32(ccb->c_dmam->dm_segs[0].ds_addr);
689: }
690: }
691:
692: /* Pass command to hardware */
693: DPRINTF(IPS_D_XFER, ("%s: run command 0x%02x\n", sc->sc_dev.dv_xname,
694: ccb->c_id));
695: ccb->c_flags |= IPS_CCB_RUN;
696: TAILQ_INSERT_TAIL(&sc->sc_ccbq_run, ccb, c_link);
697: ips_exec(sc, ccb);
698:
699: if (flags & IPS_CCB_POLL)
700: /* Wait for command to complete */
701: error = ips_poll(sc, ccb);
702:
703: return (error);
704: }
705:
706: int
707: ips_poll(struct ips_softc *sc, struct ips_ccb *c)
708: {
709: struct ips_ccb *ccb = NULL;
710: u_int32_t status;
711: int id, timeout;
712:
713: while (ccb != c) {
714: for (timeout = 100; timeout-- > 0; delay(100)) {
715: if ((status = ips_status(sc)) == 0xffffffff)
716: continue;
717: id = IPS_REG_STAT_ID(status);
718: if (id >= sc->sc_nccbs) {
719: DPRINTF(IPS_D_ERR, ("%s: invalid command "
720: "0x%02x\n", sc->sc_dev.dv_xname, id));
721: continue;
722: }
723: break;
724: }
725: if (timeout < 0) {
726: printf("%s: poll timeout\n", sc->sc_dev.dv_xname);
727: return (EBUSY);
728: }
729: ccb = &sc->sc_ccb[id];
730: ccb->c_stat = IPS_REG_STAT_GSC(status);
731: ccb->c_estat = IPS_REG_STAT_EXT(status);
732: ips_done(sc, ccb);
733: }
734:
735: return (0);
736: }
737:
738: void
739: ips_done(struct ips_softc *sc, struct ips_ccb *ccb)
740: {
741: struct scsi_xfer *xs = ccb->c_xfer;
742: int flags = ccb->c_flags;
743: int error = 0;
744:
745: if ((flags & IPS_CCB_RUN) == 0) {
746: printf("%s: command 0x%02x not run\n", sc->sc_dev.dv_xname,
747: ccb->c_id);
748: if (xs != NULL) {
749: xs->error = XS_DRIVER_STUFFUP;
750: scsi_done(xs);
751: }
752: return;
753: }
754:
755: if (flags & (IPS_CCB_READ | IPS_CCB_WRITE)) {
756: bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,
757: ccb->c_dmam->dm_mapsize, flags & IPS_CCB_READ ?
758: BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
759: bus_dmamap_unload(sc->sc_dmat, ccb->c_dmam);
760: }
761:
762: if (ccb->c_stat) {
763: printf("%s: ", sc->sc_dev.dv_xname);
764: if (ccb->c_stat == 1) {
765: printf("recovered error\n");
766: } else {
767: printf("error\n");
768: error = 1;
769: }
770: }
771:
772: /* Release CCB */
773: TAILQ_REMOVE(&sc->sc_ccbq_run, ccb, c_link);
774: ips_ccb_put(sc, ccb);
775:
776: if (xs != NULL) {
777: if (error)
778: xs->error = XS_DRIVER_STUFFUP;
779: else
780: xs->resid = 0;
781: xs->flags |= ITSDONE;
782: scsi_done(xs);
783: }
784: }
785:
786: int
787: ips_intr(void *arg)
788: {
789: struct ips_softc *sc = arg;
790: struct ips_ccb *ccb;
791: u_int32_t status;
792: int id;
793:
794: if (!ips_isintr(sc))
795: return (0);
796:
797: /* Process completed commands */
798: while ((status = ips_status(sc)) != 0xffffffff) {
799: DPRINTF(IPS_D_XFER, ("%s: intr status 0x%08x\n",
800: sc->sc_dev.dv_xname, status));
801:
802: id = IPS_REG_STAT_ID(status);
803: if (id >= sc->sc_nccbs) {
804: DPRINTF(IPS_D_ERR, ("%s: invalid command %d\n",
805: sc->sc_dev.dv_xname, id));
806: continue;
807: }
808: ccb = &sc->sc_ccb[id];
809: ccb->c_stat = IPS_REG_STAT_GSC(status);
810: ccb->c_estat = IPS_REG_STAT_EXT(status);
811: ips_done(sc, ccb);
812: }
813:
814: return (1);
815: }
816:
817: int
818: ips_getadapterinfo(struct ips_softc *sc, struct ips_adapterinfo *ai)
819: {
820: return (ips_cmd(sc, IPS_CMD_GETADAPTERINFO, 0, 0, ai, sizeof(*ai),
821: IPS_CCB_READ | IPS_CCB_POLL, NULL));
822: }
823:
824: int
825: ips_getdriveinfo(struct ips_softc *sc, struct ips_driveinfo *di)
826: {
827: return (ips_cmd(sc, IPS_CMD_GETDRIVEINFO, 0, 0, di, sizeof(*di),
828: IPS_CCB_READ | IPS_CCB_POLL, NULL));
829: }
830:
831: int
832: ips_flush(struct ips_softc *sc)
833: {
834: return (ips_cmd(sc, IPS_CMD_FLUSH, 0, 0, NULL, 0, IPS_CCB_POLL, NULL));
835: }
836:
837: void
838: ips_copperhead_exec(struct ips_softc *sc, struct ips_ccb *ccb)
839: {
840: u_int32_t reg;
841: int timeout;
842:
843: for (timeout = 100; timeout-- > 0; delay(100)) {
844: reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_CCC);
845: if ((reg & IPS_REG_CCC_SEM) == 0)
846: break;
847: }
848: if (timeout < 0) {
849: printf("%s: semaphore timeout\n", sc->sc_dev.dv_xname);
850: return;
851: }
852:
853: bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_CCSA, ccb->c_cmdpa);
854: bus_space_write_2(sc->sc_iot, sc->sc_ioh, IPS_REG_CCC,
855: IPS_REG_CCC_START);
856: }
857:
858: void
859: ips_copperhead_init(struct ips_softc *sc)
860: {
861: /* XXX: not implemented */
862: }
863:
864: void
865: ips_copperhead_intren(struct ips_softc *sc)
866: {
867: bus_space_write_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS, IPS_REG_HIS_EN);
868: }
869:
870: int
871: ips_copperhead_isintr(struct ips_softc *sc)
872: {
873: u_int8_t reg;
874:
875: reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS);
876: bus_space_write_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS, reg);
877: if (reg != 0xff && (reg & IPS_REG_HIS_SCE))
878: return (1);
879:
880: return (0);
881: }
882:
883: int
884: ips_copperhead_reset(struct ips_softc *sc)
885: {
886: /* XXX: not implemented */
887: return (0);
888: }
889:
890: u_int32_t
891: ips_copperhead_status(struct ips_softc *sc)
892: {
893: /* XXX: not implemented */
894: return (0);
895: }
896:
897: void
898: ips_morpheus_exec(struct ips_softc *sc, struct ips_ccb *ccb)
899: {
900: bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_IQP, ccb->c_cmdpa);
901: }
902:
903: void
904: ips_morpheus_init(struct ips_softc *sc)
905: {
906: /* XXX: not implemented */
907: }
908:
909: void
910: ips_morpheus_intren(struct ips_softc *sc)
911: {
912: u_int32_t reg;
913:
914: reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIM);
915: reg &= ~IPS_REG_OIM_DS;
916: bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIM, reg);
917: }
918:
919: int
920: ips_morpheus_isintr(struct ips_softc *sc)
921: {
922: u_int32_t reg;
923:
924: reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIS);
925: DPRINTF(IPS_D_XFER, ("%s: isintr 0x%08x\n", sc->sc_dev.dv_xname, reg));
926:
927: return (reg & IPS_REG_OIS_PEND);
928: }
929:
930: int
931: ips_morpheus_reset(struct ips_softc *sc)
932: {
933: /* XXX: not implemented */
934: return (0);
935: }
936:
937: u_int32_t
938: ips_morpheus_status(struct ips_softc *sc)
939: {
940: u_int32_t reg;
941:
942: reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OQP);
943: DPRINTF(IPS_D_XFER, ("%s: status 0x%08x\n", sc->sc_dev.dv_xname, reg));
944:
945: return (reg);
946: }
947:
948: struct ips_ccb *
949: ips_ccb_alloc(struct ips_softc *sc, int n)
950: {
951: struct ips_ccb *ccb;
952: int i;
953:
954: if ((ccb = malloc(n * sizeof(*ccb), M_DEVBUF, M_NOWAIT)) == NULL)
955: return (NULL);
956: bzero(ccb, n * sizeof(*ccb));
957:
958: for (i = 0; i < n; i++) {
959: ccb[i].c_id = i;
960: ccb[i].c_cmdva = (char *)sc->sc_cmdm.dm_vaddr +
961: i * IPS_MAXCMDSZ;
962: ccb[i].c_cmdpa = sc->sc_cmdm.dm_paddr + i * IPS_MAXCMDSZ;
963: if (bus_dmamap_create(sc->sc_dmat, IPS_MAXFER, IPS_MAXSGS,
964: IPS_MAXFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
965: &ccb[i].c_dmam))
966: goto fail;
967: }
968:
969: return (ccb);
970: fail:
971: for (; i > 0; i--)
972: bus_dmamap_destroy(sc->sc_dmat, ccb[i - 1].c_dmam);
973: free(ccb, M_DEVBUF);
974: return (NULL);
975: }
976:
977: void
978: ips_ccb_free(struct ips_softc *sc, struct ips_ccb *ccb, int n)
979: {
980: int i;
981:
982: for (i = 0; i < n; i++)
983: bus_dmamap_destroy(sc->sc_dmat, ccb[i - 1].c_dmam);
984: free(ccb, M_DEVBUF);
985: }
986:
987: struct ips_ccb *
988: ips_ccb_get(struct ips_softc *sc)
989: {
990: struct ips_ccb *ccb;
991:
992: if ((ccb = TAILQ_FIRST(&sc->sc_ccbq_free)) != NULL)
993: TAILQ_REMOVE(&sc->sc_ccbq_free, ccb, c_link);
994:
995: return (ccb);
996: }
997:
998: void
999: ips_ccb_put(struct ips_softc *sc, struct ips_ccb *ccb)
1000: {
1001: ccb->c_flags = 0;
1002: ccb->c_xfer = NULL;
1003: TAILQ_INSERT_TAIL(&sc->sc_ccbq_free, ccb, c_link);
1004: }
1005:
1006: int
1007: ips_dmamem_alloc(struct dmamem *dm, bus_dma_tag_t tag, bus_size_t size)
1008: {
1009: int nsegs;
1010:
1011: dm->dm_tag = tag;
1012: dm->dm_size = size;
1013:
1014: if (bus_dmamap_create(tag, size, 1, size, 0,
1015: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &dm->dm_map))
1016: return (1);
1017: if (bus_dmamem_alloc(tag, size, 0, 0, &dm->dm_seg, 1, &nsegs,
1018: BUS_DMA_NOWAIT))
1019: goto fail1;
1020: if (bus_dmamem_map(tag, &dm->dm_seg, 1, size, (caddr_t *)&dm->dm_vaddr,
1021: BUS_DMA_NOWAIT))
1022: goto fail2;
1023: if (bus_dmamap_load(tag, dm->dm_map, dm->dm_vaddr, size, NULL,
1024: BUS_DMA_NOWAIT))
1025: goto fail3;
1026:
1027: return (0);
1028:
1029: fail3:
1030: bus_dmamem_unmap(tag, dm->dm_vaddr, size);
1031: fail2:
1032: bus_dmamem_free(tag, &dm->dm_seg, 1);
1033: fail1:
1034: bus_dmamap_destroy(tag, dm->dm_map);
1035: return (1);
1036: }
1037:
1038: void
1039: ips_dmamem_free(struct dmamem *dm)
1040: {
1041: bus_dmamap_unload(dm->dm_tag, dm->dm_map);
1042: bus_dmamem_unmap(dm->dm_tag, dm->dm_vaddr, dm->dm_size);
1043: bus_dmamem_free(dm->dm_tag, &dm->dm_seg, 1);
1044: bus_dmamap_destroy(dm->dm_tag, dm->dm_map);
1045: }
CVSweb