1 /* $wasabi: ld_twa.c,v 1.9 2006/02/14 18:44:37 jordanr Exp $ */ 2 /* $NetBSD: ld_twa.c,v 1.19 2016/09/27 03:33:32 pgoyette Exp $ */ 3 4 /*- 5 * Copyright (c) 2000, 2001, 2002, 2003, 2004 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Andrew Doran, and by Jason R. Thorpe and Jordan Rhody of Wasabi 10 * Systems, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * 3ware "Apache" RAID controller front-end for ld(4) driver. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: ld_twa.c,v 1.19 2016/09/27 03:33:32 pgoyette Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/device.h> 45 #include <sys/buf.h> 46 #include <sys/bufq.h> 47 #include <sys/endian.h> 48 #include <sys/dkio.h> 49 #include <sys/disk.h> 50 #include <sys/proc.h> 51 #include <sys/module.h> 52 #include <sys/bus.h> 53 54 #include <dev/ldvar.h> 55 56 #include <dev/scsipi/scsipi_all.h> 57 #include <dev/scsipi/scsipi_disk.h> 58 #include <dev/scsipi/scsipiconf.h> 59 #include <dev/scsipi/scsi_disk.h> 60 61 62 #include <dev/pci/pcireg.h> 63 #include <dev/pci/pcivar.h> 64 #include <dev/pci/twareg.h> 65 #include <dev/pci/twavar.h> 66 67 #include "ioconf.h" 68 69 struct ld_twa_softc { 70 struct ld_softc sc_ld; 71 int sc_hwunit; 72 }; 73 74 static void ld_twa_attach(device_t, device_t, void *); 75 static int ld_twa_detach(device_t, int); 76 static int ld_twa_dobio(struct ld_twa_softc *, void *, size_t, daddr_t, 77 struct buf *); 78 static int ld_twa_dump(struct ld_softc *, void *, int, int); 79 static int ld_twa_flush(struct ld_softc *, int); 80 static void ld_twa_handler(struct twa_request *); 81 static int ld_twa_match(device_t, cfdata_t, void *); 82 static int ld_twa_start(struct ld_softc *, struct buf *); 83 84 static void ld_twa_adjqparam(device_t, int); 85 86 static int ld_twa_scsicmd(struct ld_twa_softc *, 87 struct twa_request *, struct buf *); 88 89 CFATTACH_DECL_NEW(ld_twa, sizeof(struct ld_twa_softc), 90 ld_twa_match, ld_twa_attach, ld_twa_detach, NULL); 91 92 static const struct twa_callbacks ld_twa_callbacks = { 93 ld_twa_adjqparam, 94 }; 95 96 static int 97 ld_twa_match(device_t parent, cfdata_t match, void *aux) 98 { 99 100 return (1); 101 } 102 103 static void 104 ld_twa_attach(device_t parent, device_t self, void *aux) 105 { 106 struct twa_attach_args *twa_args = aux; 107 struct ld_twa_softc *sc = device_private(self); 108 struct ld_softc *ld = &sc->sc_ld; 109 struct twa_softc *twa = device_private(parent); 110 111 ld->sc_dv = self; 112 113 twa_register_callbacks(twa, twa_args->twaa_unit, &ld_twa_callbacks); 114 115 sc->sc_hwunit = twa_args->twaa_unit; 116 ld->sc_maxxfer = twa_get_maxxfer(twa_get_maxsegs()); 117 ld->sc_secperunit = twa->sc_units[sc->sc_hwunit].td_size; 118 ld->sc_flags = LDF_ENABLED; 119 ld->sc_secsize = TWA_SECTOR_SIZE; 120 ld->sc_maxqueuecnt = twa->sc_units[sc->sc_hwunit].td_openings; 121 ld->sc_start = ld_twa_start; 122 ld->sc_dump = ld_twa_dump; 123 ld->sc_flush = ld_twa_flush; 124 ldattach(ld, BUFQ_DISK_DEFAULT_STRAT); 125 } 126 127 static int 128 ld_twa_detach(device_t self, int flags) 129 { 130 struct ld_twa_softc *sc = device_private(self); 131 struct ld_softc *ld = &sc->sc_ld; 132 int error; 133 134 if ((error = ldbegindetach(ld, flags)) != 0) 135 return (error); 136 ldenddetach(ld); 137 138 return (0); 139 } 140 141 static int 142 ld_twa_dobio(struct ld_twa_softc *sc, void *data, size_t datasize, 143 daddr_t blkno, struct buf *bp) 144 { 145 int rv; 146 struct twa_request *tr; 147 struct twa_softc *twa; 148 149 twa = device_private(device_parent(sc->sc_ld.sc_dv)); 150 151 if ((tr = twa_get_request(twa, 0)) == NULL) { 152 return (EAGAIN); 153 } 154 if (bp->b_flags & B_READ) { 155 tr->tr_flags = TWA_CMD_DATA_OUT; 156 } else { 157 tr->tr_flags = TWA_CMD_DATA_IN; 158 } 159 160 tr->tr_data = data; 161 tr->tr_length = datasize; 162 tr->tr_cmd_pkt_type = 163 (TWA_CMD_PKT_TYPE_9K | TWA_CMD_PKT_TYPE_EXTERNAL); 164 165 tr->tr_command->cmd_hdr.header_desc.size_header = 128; 166 167 tr->tr_command->command.cmd_pkt_9k.command.opcode = 168 TWA_OP_EXECUTE_SCSI_COMMAND; 169 tr->tr_command->command.cmd_pkt_9k.unit = 170 sc->sc_hwunit; 171 tr->tr_command->command.cmd_pkt_9k.request_id = 172 tr->tr_request_id; 173 tr->tr_command->command.cmd_pkt_9k.status = 0; 174 tr->tr_command->command.cmd_pkt_9k.sgl_entries = 1; 175 tr->tr_command->command.cmd_pkt_9k.sgl_offset = 16; 176 177 /* offset from end of hdr = max cdb len */ 178 ld_twa_scsicmd(sc, tr, bp); 179 180 tr->tr_callback = ld_twa_handler; 181 tr->tr_ld_sc = sc; 182 183 tr->bp = bp; 184 185 rv = twa_map_request(tr); 186 187 return (rv); 188 } 189 190 static int 191 ld_twa_start(struct ld_softc *ld, struct buf *bp) 192 { 193 194 return (ld_twa_dobio((struct ld_twa_softc *)ld, bp->b_data, 195 bp->b_bcount, bp->b_rawblkno, bp)); 196 } 197 198 static void 199 ld_twa_handler(struct twa_request *tr) 200 { 201 uint8_t status; 202 struct buf *bp; 203 struct ld_twa_softc *sc; 204 205 bp = tr->bp; 206 sc = (struct ld_twa_softc *)tr->tr_ld_sc; 207 208 status = tr->tr_command->command.cmd_pkt_9k.status; 209 210 if (status != 0) { 211 bp->b_error = EIO; 212 bp->b_resid = bp->b_bcount; 213 } else { 214 bp->b_resid = 0; 215 bp->b_error = 0; 216 } 217 twa_release_request(tr); 218 219 lddone(&sc->sc_ld, bp); 220 } 221 222 static int 223 ld_twa_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt) 224 { 225 226 #if 0 227 /* XXX Unsafe right now. */ 228 return (ld_twa_dobio((struct ld_twa_softc *)ld, data, 229 blkcnt * ld->sc_secsize, blkno, NULL)); 230 #else 231 return EIO; 232 #endif 233 234 } 235 236 237 static int 238 ld_twa_flush(struct ld_softc *ld, int flags) 239 { 240 int s, rv = 0; 241 struct twa_request *tr; 242 struct twa_softc *twa = device_private(device_parent(ld->sc_dv)); 243 struct ld_twa_softc *sc = (void *)ld; 244 struct twa_command_generic *generic_cmd; 245 246 /* Get a request packet. */ 247 tr = twa_get_request_wait(twa, 0); 248 KASSERT(tr != NULL); 249 250 tr->tr_cmd_pkt_type = 251 (TWA_CMD_PKT_TYPE_9K | TWA_CMD_PKT_TYPE_EXTERNAL); 252 253 tr->tr_callback = twa_request_wait_handler; 254 tr->tr_ld_sc = sc; 255 256 tr->tr_command->cmd_hdr.header_desc.size_header = 128; 257 258 generic_cmd = &(tr->tr_command->command.cmd_pkt_7k.generic); 259 generic_cmd->opcode = TWA_OP_FLUSH; 260 generic_cmd->size = 2; 261 generic_cmd->unit = sc->sc_hwunit; 262 generic_cmd->request_id = tr->tr_request_id; 263 generic_cmd->sgl_offset = 0; 264 generic_cmd->host_id = 0; 265 generic_cmd->status = 0; 266 generic_cmd->flags = 0; 267 generic_cmd->count = 0; 268 rv = twa_map_request(tr); 269 s = splbio(); 270 while (tr->tr_status != TWA_CMD_COMPLETE) 271 if ((rv = tsleep(tr, PRIBIO, "twaflush", 60 * hz)) != 0) 272 break; 273 twa_release_request(tr); 274 splx(s); 275 276 return (rv); 277 } 278 279 static void 280 ld_twa_adjqparam(device_t self, int openings) 281 { 282 struct ld_twa_softc *sc = device_private(self); 283 struct ld_softc *ld = &sc->sc_ld; 284 285 ldadjqparam(ld, openings); 286 } 287 288 289 static int 290 ld_twa_scsicmd(struct ld_twa_softc *sc, 291 struct twa_request *tr, struct buf *bp) 292 { 293 if (tr->tr_flags == TWA_CMD_DATA_IN) { 294 tr->tr_command->command.cmd_pkt_9k.cdb[0] = WRITE_16; 295 } else { 296 tr->tr_command->command.cmd_pkt_9k.cdb[0] = READ_16; 297 } 298 tr->tr_command->command.cmd_pkt_9k.cdb[1] = 299 (sc->sc_hwunit << 5); /* lun for CDB */ 300 301 _lto8b(htole64(bp->b_rawblkno), 302 &tr->tr_command->command.cmd_pkt_9k.cdb[2]); 303 _lto4b(htole32((bp->b_bcount / TWA_SECTOR_SIZE)), 304 &tr->tr_command->command.cmd_pkt_9k.cdb[10]); 305 306 tr->tr_command->command.cmd_pkt_9k.cdb[14] = 0; 307 tr->tr_command->command.cmd_pkt_9k.cdb[15] = 0; 308 309 return (0); 310 } 311 312 MODULE(MODULE_CLASS_DRIVER, ld_twa, "ld,twa"); 313 314 #ifdef _MODULE 315 /* 316 * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd" 317 * XXX it will be defined in the common-code module 318 */ 319 #undef CFDRIVER_DECL 320 #define CFDRIVER_DECL(name, class, attr) 321 #include "ioconf.c" 322 #endif 323 324 static int 325 ld_twa_modcmd(modcmd_t cmd, void *opaque) 326 { 327 #ifdef _MODULE 328 /* 329 * We ignore the cfdriver_vec[] that ioconf provides, since 330 * the cfdrivers are attached already. 331 */ 332 static struct cfdriver * const no_cfdriver_vec[] = { NULL }; 333 #endif 334 int error = 0; 335 336 #ifdef _MODULE 337 switch (cmd) { 338 case MODULE_CMD_INIT: 339 error = config_init_component(no_cfdriver_vec, 340 cfattach_ioconf_ld_twa, cfdata_ioconf_ld_twa); 341 break; 342 case MODULE_CMD_FINI: 343 error = config_fini_component(no_cfdriver_vec, 344 cfattach_ioconf_ld_twa, cfdata_ioconf_ld_twa); 345 break; 346 default: 347 error = ENOTTY; 348 break; 349 } 350 #endif 351 352 return error; 353 } 354