1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2000 Michael Smith 5 * Copyright (c) 2000 BSDi 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32#define TWE_DRIVER_VERSION_STRING "1.50.01.002" 33 34#ifdef TWE_DEBUG 35#define debug(level, fmt, args...) \ 36 do { \ 37 if (level <= TWE_DEBUG) printf("%s: " fmt "\n", __func__ , ##args); \ 38 } while(0) 39#define debug_called(level) \ 40 do { \ 41 if (level <= TWE_DEBUG) printf("%s: called\n", __func__); \ 42 } while(0) 43#else 44#define debug(level, fmt, args...) 45#define debug_called(level) 46#endif 47 48/* 49 * Structure describing a logical unit as attached to the controller 50 */ 51struct twe_drive 52{ 53 /* unit properties */ 54 u_int32_t td_size; 55 int td_cylinders; 56 int td_heads; 57 int td_sectors; 58 int td_sys_unit; /* device unit number */ 59 int td_twe_unit; /* index into sc->twe_drive[] */ 60 61 /* unit state and type */ 62 u_int8_t td_state; 63 u_int8_t td_type; 64 u_int8_t td_stripe; 65 66 /* handle for attached driver */ 67 device_t td_disk; 68}; 69 70/* 71 * Per-command control structure. 72 * 73 * Note that due to alignment constraints on the tc_command field, this *must* be 64-byte aligned. 74 * We achieve this by placing the command at the beginning of the structure, and using malloc() 75 * to allocate each structure. 76 */ 77struct twe_request 78{ 79 int tr_tag; 80 /* command payload */ 81 void *tr_data; /* data buffer */ 82 void *tr_realdata; /* copy of real data buffer pointer for alignment fixup */ 83 size_t tr_length; 84 85 TAILQ_ENTRY(twe_request) tr_link; /* list linkage */ 86 struct twe_softc *tr_sc; /* controller that owns us */ 87 int tr_status; /* command status */ 88#define TWE_CMD_SETUP 0 /* being assembled */ 89#define TWE_CMD_BUSY 1 /* submitted to controller */ 90#define TWE_CMD_COMPLETE 2 /* completed by controller (maybe with error) */ 91#define TWE_CMD_ERROR 3 /* encountered error, even before submission to controller */ 92 int tr_flags; 93#define TWE_CMD_DATAIN (1<<0) 94#define TWE_CMD_DATAOUT (1<<1) 95#define TWE_CMD_ALIGNBUF (1<<2) /* data in bio is misaligned, have to copy to/from private buffer */ 96#define TWE_CMD_SLEEPER (1<<3) /* owner is sleeping on this command */ 97#define TWE_CMD_IMMEDIATE (1<<4) /* immediate request */ 98#define TWE_CMD_MAPPED (1<<5) 99#define TWE_CMD_IN_PROGRESS (1<<6) /* bus_dmamap_load returned EINPROGRESS */ 100 void (* tr_complete)(struct twe_request *tr); /* completion handler */ 101 void *tr_private; /* submitter-private data or wait channel */ 102 103 TWE_PLATFORM_REQUEST /* platform-specific request elements */ 104}; 105 106#define TWE_FIND_COMMAND(tr) \ 107 (TWE_Command *)((u_int8_t *)(tr)->tr_sc->twe_cmd + \ 108 ((tr)->tr_tag * sizeof(TWE_Command))) 109#define TWE_FIND_COMMANDPHYS(tr) ((tr)->tr_sc->twe_cmdphys + \ 110 ((tr)->tr_tag * sizeof(TWE_Command))) 111 112/* 113 * Per-controller state. 114 */ 115struct twe_softc 116{ 117 /* controller queues and arrays */ 118 TAILQ_HEAD(, twe_request) twe_free; /* command structures available for reuse */ 119 struct bio_queue_head twe_bioq; /* outstanding I/O operations */ 120 TAILQ_HEAD(, twe_request) twe_ready; /* requests ready for the controller */ 121 TAILQ_HEAD(, twe_request) twe_busy; /* requests busy in the controller */ 122 TAILQ_HEAD(, twe_request) twe_complete; /* active commands (busy or waiting for completion) */ 123 struct twe_request *twe_lookup[TWE_Q_LENGTH]; /* commands indexed by request ID */ 124 struct twe_drive twe_drive[TWE_MAX_UNITS]; /* attached drives */ 125 126 /* asynchronous event handling */ 127 u_int16_t twe_aen_queue[TWE_Q_LENGTH]; /* AENs queued for userland tool(s) */ 128 int twe_aen_head, twe_aen_tail; /* ringbuffer pointers for AEN queue */ 129 int twe_wait_aen; /* wait-for-aen notification */ 130 char twe_aen_buf[80]; /* AEN format buffer */ 131 132 /* controller status */ 133 int twe_state; 134#define TWE_STATE_INTEN (1<<0) /* interrupts have been enabled */ 135#define TWE_STATE_SHUTDOWN (1<<1) /* controller is shut down */ 136#define TWE_STATE_OPEN (1<<2) /* control device is open */ 137#define TWE_STATE_SUSPEND (1<<3) /* controller is suspended */ 138#define TWE_STATE_FRZN (1<<4) /* got EINPROGRESS */ 139#define TWE_STATE_CTLR_BUSY (1<<5) /* controller cmd queue full */ 140#define TWE_STATE_DETACHING (1<<6) /* controller is being shut down */ 141 int twe_host_id; 142 struct twe_qstat twe_qstat[TWEQ_COUNT]; /* queue statistics */ 143 144 TWE_PLATFORM_SOFTC /* platform-specific softc elements */ 145}; 146 147/* 148 * Interface between driver core and platform-dependant code. 149 */ 150extern int twe_setup(struct twe_softc *sc); /* do early driver/controller setup */ 151extern void twe_init(struct twe_softc *sc); /* init controller */ 152extern void twe_deinit(struct twe_softc *sc); /* stop controller */ 153extern void twe_intr(struct twe_softc *sc); /* hardware interrupt signalled */ 154extern void twe_startio(struct twe_softc *sc); 155extern int twe_start(struct twe_request *tr); 156extern int twe_dump_blocks(struct twe_softc *sc, int unit, /* crashdump block write */ 157 u_int32_t lba, void *data, int nblks); 158extern int twe_ioctl(struct twe_softc *sc, u_long cmd, 159 void *addr); /* handle user request */ 160extern void twe_describe_controller(struct twe_softc *sc); /* print controller info */ 161extern void twe_print_controller(struct twe_softc *sc); 162extern void twe_enable_interrupts(struct twe_softc *sc); /* enable controller interrupts */ 163extern void twe_disable_interrupts(struct twe_softc *sc); /* disable controller interrupts */ 164 165extern int twe_attach_drive(struct twe_softc *sc, 166 struct twe_drive *dr); /* attach drive when found in twe_init */ 167extern int twe_detach_drive(struct twe_softc *sc, 168 int unit); /* detach drive */ 169extern void twe_clear_pci_parity_error(struct twe_softc *sc); 170extern void twe_clear_pci_abort(struct twe_softc *sc); 171extern void twed_intr(struct bio *bp); /* return bio from core */ 172extern struct twe_request *twe_allocate_request(struct twe_softc *sc, int tag); /* allocate request structure */ 173extern void twe_free_request(struct twe_request *tr); /* free request structure */ 174extern int twe_map_request(struct twe_request *tr); /* make request visible to controller, do s/g */ 175extern void twe_unmap_request(struct twe_request *tr); /* cleanup after transfer, unmap */ 176 177/******************************************************************************** 178 * Queue primitives 179 */ 180#define TWEQ_ADD(sc, qname) \ 181 do { \ 182 struct twe_qstat *qs = &(sc)->twe_qstat[qname]; \ 183 \ 184 qs->q_length++; \ 185 if (qs->q_length > qs->q_max) \ 186 qs->q_max = qs->q_length; \ 187 } while(0) 188 189#define TWEQ_REMOVE(sc, qname) \ 190 do { \ 191 struct twe_qstat *qs = &(sc)->twe_qstat[qname]; \ 192 \ 193 qs->q_length--; \ 194 if (qs->q_length < qs->q_min) \ 195 qs->q_min = qs->q_length; \ 196 } while(0); 197 198#define TWEQ_INIT(sc, qname) \ 199 do { \ 200 sc->twe_qstat[qname].q_length = 0; \ 201 sc->twe_qstat[qname].q_max = 0; \ 202 sc->twe_qstat[qname].q_min = 0xFFFFFFFF; \ 203 } while(0) 204 205 206#define TWEQ_REQUEST_QUEUE(name, index) \ 207static __inline void \ 208twe_initq_ ## name (struct twe_softc *sc) \ 209{ \ 210 TAILQ_INIT(&sc->twe_ ## name); \ 211 TWEQ_INIT(sc, index); \ 212} \ 213static __inline void \ 214twe_enqueue_ ## name (struct twe_request *tr) \ 215{ \ 216 TAILQ_INSERT_TAIL(&tr->tr_sc->twe_ ## name, tr, tr_link); \ 217 TWEQ_ADD(tr->tr_sc, index); \ 218} \ 219static __inline void \ 220twe_requeue_ ## name (struct twe_request *tr) \ 221{ \ 222 TAILQ_INSERT_HEAD(&tr->tr_sc->twe_ ## name, tr, tr_link); \ 223 TWEQ_ADD(tr->tr_sc, index); \ 224} \ 225static __inline struct twe_request * \ 226twe_dequeue_ ## name (struct twe_softc *sc) \ 227{ \ 228 struct twe_request *tr; \ 229 \ 230 if ((tr = TAILQ_FIRST(&sc->twe_ ## name)) != NULL) { \ 231 TAILQ_REMOVE(&sc->twe_ ## name, tr, tr_link); \ 232 TWEQ_REMOVE(sc, index); \ 233 } \ 234 return(tr); \ 235} \ 236static __inline void \ 237twe_remove_ ## name (struct twe_request *tr) \ 238{ \ 239 TAILQ_REMOVE(&tr->tr_sc->twe_ ## name, tr, tr_link); \ 240 TWEQ_REMOVE(tr->tr_sc, index); \ 241} 242 243TWEQ_REQUEST_QUEUE(free, TWEQ_FREE) 244TWEQ_REQUEST_QUEUE(ready, TWEQ_READY) 245TWEQ_REQUEST_QUEUE(busy, TWEQ_BUSY) 246TWEQ_REQUEST_QUEUE(complete, TWEQ_COMPLETE) 247 248/* 249 * outstanding bio queue 250 */ 251static __inline void 252twe_initq_bio(struct twe_softc *sc) 253{ 254 bioq_init(&sc->twe_bioq); 255 TWEQ_INIT(sc, TWEQ_BIO); 256} 257 258static __inline void 259twe_enqueue_bio(struct twe_softc *sc, struct bio *bp) 260{ 261 bioq_insert_tail(&sc->twe_bioq, bp); 262 TWEQ_ADD(sc, TWEQ_BIO); 263} 264 265static __inline struct bio * 266twe_dequeue_bio(struct twe_softc *sc) 267{ 268 struct bio *bp; 269 270 if ((bp = bioq_first(&sc->twe_bioq)) != NULL) { 271 bioq_remove(&sc->twe_bioq, bp); 272 TWEQ_REMOVE(sc, TWEQ_BIO); 273 } 274 return(bp); 275} 276