1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * 1394 mass storage SBP-2 bus routines 29 */ 30 31 #include <sys/param.h> 32 #include <sys/errno.h> 33 #include <sys/cred.h> 34 #include <sys/conf.h> 35 #include <sys/modctl.h> 36 #include <sys/stat.h> 37 #include <sys/ddi.h> 38 #include <sys/sunddi.h> 39 40 #include <sys/sbp2/bus.h> 41 #include <sys/1394/targets/scsa1394/impl.h> 42 43 static ddi_iblock_cookie_t scsa1394_bus_get_iblock_cookie(void *); 44 static uint_t scsa1394_bus_get_node_id(void *); 45 static int scsa1394_bus_alloc_cmd(void *, void **, int); 46 static void scsa1394_bus_free_cmd(void *, void *); 47 static int scsa1394_bus_rq(void *, void *, uint64_t, uint32_t *, int *); 48 static int scsa1394_bus_rb(void *, void *, uint64_t, mblk_t **, int, 49 int *); 50 static int scsa1394_bus_wq(void *, void *, uint64_t, uint32_t, int *); 51 static int scsa1394_bus_wb(void *, void *, uint64_t, mblk_t *, int, 52 int *); 53 static int scsa1394_bus_alloc_buf(void *, sbp2_bus_buf_t *); 54 static int scsa1394_bus_alloc_buf_phys(void *, sbp2_bus_buf_t *); 55 static void scsa1394_bus_free_buf_phys(void *, sbp2_bus_buf_t *); 56 static int scsa1394_bus_alloc_buf_normal(void *, sbp2_bus_buf_t *, 57 boolean_t); 58 static void scsa1394_bus_free_buf_normal(void *, sbp2_bus_buf_t *); 59 static void scsa1394_bus_free_buf(void *, sbp2_bus_buf_t *); 60 static int scsa1394_bus_sync_buf(void *, sbp2_bus_buf_t *, off_t, size_t, 61 int); 62 static void scsa1394_bus_buf_rw_done(void *, sbp2_bus_buf_t *, void *, int); 63 64 /* callbacks */ 65 static void scsa1394_bus_recv_read_request(cmd1394_cmd_t *); 66 static void scsa1394_bus_recv_write_request(cmd1394_cmd_t *); 67 68 sbp2_bus_t scsa1394_sbp2_bus = { 69 SBP2_BUS_REV, /* rev */ 70 0xFFFFF0000000LL, /* csr_base */ 71 IEEE1394_CONFIG_ROM_ADDR, /* cfgrom_addr */ 72 scsa1394_bus_get_iblock_cookie, /* get_iblock_cookie */ 73 scsa1394_bus_get_node_id, /* get_node_id */ 74 scsa1394_bus_alloc_buf, /* alloc_buf */ 75 scsa1394_bus_free_buf, /* free_buf */ 76 scsa1394_bus_sync_buf, /* sync_buf */ 77 scsa1394_bus_buf_rw_done, /* buf_rd_done */ 78 scsa1394_bus_buf_rw_done, /* buf_wr_done */ 79 scsa1394_bus_alloc_cmd, /* alloc_cmd */ 80 scsa1394_bus_free_cmd, /* free_cmd */ 81 scsa1394_bus_rq, /* rq */ 82 scsa1394_bus_rb, /* rb */ 83 scsa1394_bus_wq, /* wq */ 84 scsa1394_bus_wb /* wb */ 85 }; 86 87 /* 88 * fault injector 89 * 90 * global on/off switch 91 */ 92 int scsa1394_bus_fi_on = 0; 93 94 /* fault probabilities per operation, in tenths of percent, i.e. 10 is 1% */ 95 int scsa1394_bus_fi_prob_alloc_buf = 10; 96 int scsa1394_bus_fi_prob_alloc_cmd = 10; 97 int scsa1394_bus_fi_prob_rq = 10; 98 int scsa1394_bus_fi_prob_rb = 10; 99 int scsa1394_bus_fi_prob_wq = 10; 100 int scsa1394_bus_fi_prob_wb = 10; 101 102 #define SCSA1394_BUS_FI_POSITIVE(p) (scsa1394_bus_fi_on && \ 103 ((p) > 0) && ((gethrtime() % (p)) == 0)) 104 105 /* 106 * translate command result to SBP2 error code 107 */ 108 static int 109 scsa1394_bus_rw_result2code(int result) 110 { 111 int code; 112 113 switch (result) { 114 case CMD1394_EDEVICE_BUSY: 115 code = SBP2_EBUSY; 116 break; 117 case CMD1394_EADDRESS_ERROR: 118 code = SBP2_EADDR; 119 break; 120 case CMD1394_ETIMEOUT: 121 case CMD1394_ERETRIES_EXCEEDED: 122 code = SBP2_ETIMEOUT; 123 break; 124 case CMD1394_EDEVICE_REMOVED: 125 code = SBP2_ENODEV; 126 break; 127 default: 128 code = SBP2_EIO; 129 break; 130 } 131 return (code); 132 } 133 134 static ddi_iblock_cookie_t 135 scsa1394_bus_get_iblock_cookie(void *hdl) 136 { 137 scsa1394_state_t *sp = hdl; 138 139 return (sp->s_attachinfo.iblock_cookie); 140 } 141 142 static uint_t 143 scsa1394_bus_get_node_id(void *hdl) 144 { 145 scsa1394_state_t *sp = hdl; 146 147 return (sp->s_attachinfo.localinfo.local_nodeID); 148 } 149 150 151 /*ARGSUSED*/ 152 static int 153 scsa1394_bus_alloc_cmd(void *hdl, void **cmdp, int flags) 154 { 155 scsa1394_state_t *sp = hdl; 156 cmd1394_cmd_t *cmd; 157 158 if (SCSA1394_BUS_FI_POSITIVE(scsa1394_bus_fi_prob_alloc_cmd)) { 159 return (SBP2_ENOMEM); 160 } 161 162 if (t1394_alloc_cmd(sp->s_t1394_hdl, 0, &cmd) != DDI_SUCCESS) { 163 return (SBP2_ENOMEM); 164 } 165 *cmdp = cmd; 166 return (SBP2_SUCCESS); 167 } 168 169 170 static void 171 scsa1394_bus_free_cmd(void *hdl, void *argcmd) 172 { 173 scsa1394_state_t *sp = hdl; 174 cmd1394_cmd_t *cmd = argcmd; 175 176 (void) t1394_free_cmd(sp->s_t1394_hdl, 0, &cmd); 177 } 178 179 180 /*ARGSUSED*/ 181 static int 182 scsa1394_bus_rq(void *hdl, void *argcmd, uint64_t addr, uint32_t *q, int *berr) 183 { 184 scsa1394_state_t *sp = hdl; 185 cmd1394_cmd_t *cmd = argcmd; 186 187 if (SCSA1394_BUS_FI_POSITIVE(scsa1394_bus_fi_prob_rq)) { 188 return (SBP2_EIO); 189 } 190 191 cmd->cmd_addr = addr; 192 cmd->cmd_type = CMD1394_ASYNCH_RD_QUAD; 193 cmd->cmd_options = CMD1394_BLOCKING; 194 195 if ((t1394_read(sp->s_t1394_hdl, cmd) != DDI_SUCCESS) || 196 (cmd->cmd_result != CMD1394_CMDSUCCESS)) { 197 *berr = cmd->cmd_result; 198 return (scsa1394_bus_rw_result2code(cmd->cmd_result)); 199 } 200 201 *q = cmd->cmd_u.q.quadlet_data; 202 return (SBP2_SUCCESS); 203 } 204 205 206 /*ARGSUSED*/ 207 static int 208 scsa1394_bus_rb(void *hdl, void *argcmd, uint64_t addr, mblk_t **bpp, int len, 209 int *berr) 210 { 211 scsa1394_state_t *sp = hdl; 212 cmd1394_cmd_t *cmd = argcmd; 213 mblk_t *bp = *bpp; 214 215 /* caller wants us to allocate memory */ 216 if ((bp == NULL) && ((bp = allocb(len, BPRI_HI)) == NULL)) { 217 return (SBP2_ENOMEM); 218 } 219 220 cmd->cmd_addr = addr; 221 cmd->cmd_type = CMD1394_ASYNCH_RD_BLOCK; 222 cmd->cmd_u.b.data_block = bp; 223 cmd->cmd_u.b.blk_length = len; 224 cmd->cmd_options = CMD1394_BLOCKING; 225 226 if ((t1394_read(sp->s_t1394_hdl, cmd) != DDI_SUCCESS) || 227 (cmd->cmd_result != CMD1394_CMDSUCCESS)) { 228 freeb(bp); 229 *berr = cmd->cmd_result; 230 return (scsa1394_bus_rw_result2code(cmd->cmd_result)); 231 } 232 233 *bpp = bp; 234 return (SBP2_SUCCESS); 235 } 236 237 238 /*ARGSUSED*/ 239 static int 240 scsa1394_bus_wq(void *hdl, void *argcmd, uint64_t addr, uint32_t q, int *berr) 241 { 242 scsa1394_state_t *sp = hdl; 243 cmd1394_cmd_t *cmd = argcmd; 244 245 cmd->cmd_addr = addr; 246 cmd->cmd_type = CMD1394_ASYNCH_WR_QUAD; 247 cmd->cmd_u.q.quadlet_data = q; 248 cmd->cmd_options = CMD1394_BLOCKING; 249 250 if ((t1394_write(sp->s_t1394_hdl, cmd) != DDI_SUCCESS) || 251 (cmd->cmd_result != CMD1394_CMDSUCCESS)) { 252 *berr = cmd->cmd_result; 253 return (scsa1394_bus_rw_result2code(cmd->cmd_result)); 254 } 255 256 return (SBP2_SUCCESS); 257 } 258 259 260 /*ARGSUSED*/ 261 static int 262 scsa1394_bus_wb(void *hdl, void *argcmd, uint64_t addr, mblk_t *bp, int len, 263 int *berr) 264 { 265 scsa1394_state_t *sp = hdl; 266 cmd1394_cmd_t *cmd = argcmd; 267 268 cmd->cmd_addr = addr; 269 cmd->cmd_type = CMD1394_ASYNCH_WR_BLOCK; 270 cmd->cmd_u.b.data_block = bp; 271 cmd->cmd_u.b.blk_length = len; 272 cmd->cmd_options = CMD1394_BLOCKING; 273 274 if ((t1394_write(sp->s_t1394_hdl, cmd) != DDI_SUCCESS) || 275 (cmd->cmd_result != CMD1394_CMDSUCCESS)) { 276 *berr = cmd->cmd_result; 277 return (scsa1394_bus_rw_result2code(cmd->cmd_result)); 278 } 279 280 return (SBP2_SUCCESS); 281 } 282 283 284 /*ARGSUSED*/ 285 static int 286 scsa1394_bus_alloc_buf(void *hdl, sbp2_bus_buf_t *buf) 287 { 288 if (SCSA1394_BUS_FI_POSITIVE(scsa1394_bus_fi_prob_alloc_buf)) { 289 return (SBP2_ENOMEM); 290 } 291 292 if (buf->bb_flags & SBP2_BUS_BUF_DMA) { 293 return (scsa1394_bus_alloc_buf_phys(hdl, buf)); 294 } else { 295 return (scsa1394_bus_alloc_buf_normal(hdl, buf, 296 ((buf->bb_flags & SBP2_BUS_BUF_POSTED) != 0))); 297 } 298 } 299 300 301 static void 302 scsa1394_bus_free_buf(void *hdl, sbp2_bus_buf_t *buf) 303 { 304 if (buf->bb_flags & SBP2_BUS_BUF_DMA) { 305 scsa1394_bus_free_buf_phys(hdl, buf); 306 } else { 307 scsa1394_bus_free_buf_normal(hdl, buf); 308 } 309 } 310 311 312 static int 313 scsa1394_bus_alloc_buf_phys(void *hdl, sbp2_bus_buf_t *buf) 314 { 315 scsa1394_state_t *sp = hdl; 316 scsa1394_bus_buf_t *sbb; /* bus private structure */ 317 size_t real_length; /* real allocated length */ 318 ddi_dma_cookie_t cookie; /* cookies */ 319 uint_t ccount; /* cookie count */ 320 t1394_alloc_addr_t aa; 321 int result; 322 323 /* allocate bus private structure */ 324 sbb = kmem_zalloc(sizeof (scsa1394_bus_buf_t), KM_SLEEP); 325 sbb->sbb_state = sp; 326 327 /* allocate DMA resources */ 328 if (ddi_dma_alloc_handle(sp->s_dip, &sp->s_attachinfo.dma_attr, 329 DDI_DMA_SLEEP, NULL, &sbb->sbb_dma_hdl) != DDI_SUCCESS) { 330 kmem_free(sbb, sizeof (scsa1394_bus_buf_t)); 331 return (SBP2_ENOMEM); 332 } 333 334 if (ddi_dma_mem_alloc(sbb->sbb_dma_hdl, buf->bb_len, 335 &sp->s_attachinfo.acc_attr, 336 buf->bb_flags & (DDI_DMA_STREAMING | DDI_DMA_CONSISTENT), 337 DDI_DMA_SLEEP, NULL, &buf->bb_kaddr, &real_length, 338 &sbb->sbb_acc_hdl) != DDI_SUCCESS) { 339 ddi_dma_free_handle(&sbb->sbb_dma_hdl); 340 kmem_free(sbb, sizeof (scsa1394_bus_buf_t)); 341 return (SBP2_ENOMEM); 342 } 343 344 buf->bb_flags &= ~DDI_DMA_PARTIAL; 345 if (ddi_dma_addr_bind_handle(sbb->sbb_dma_hdl, NULL, buf->bb_kaddr, 346 buf->bb_len, buf->bb_flags, DDI_DMA_SLEEP, NULL, 347 &cookie, &ccount) != DDI_DMA_MAPPED) { 348 ddi_dma_mem_free(&sbb->sbb_acc_hdl); 349 ddi_dma_free_handle(&sbb->sbb_dma_hdl); 350 kmem_free(sbb, sizeof (scsa1394_bus_buf_t)); 351 return (SBP2_ENOMEM); 352 } 353 ASSERT(ccount == 1); 354 buf->bb_paddr = cookie.dmac_address; /* 32-bit address */ 355 356 /* allocate 1394 resources */ 357 bzero(&aa, sizeof (aa)); 358 aa.aa_type = T1394_ADDR_FIXED; 359 aa.aa_length = buf->bb_len; 360 if (buf->bb_flags & SBP2_BUS_BUF_RD) { 361 aa.aa_enable |= T1394_ADDR_RDENBL; 362 } 363 if (buf->bb_flags & SBP2_BUS_BUF_WR) { 364 aa.aa_enable |= T1394_ADDR_WRENBL; 365 } 366 aa.aa_address = buf->bb_paddr; /* PCI-1394 mapping is 1-1 */ 367 368 if (t1394_alloc_addr(sp->s_t1394_hdl, &aa, 0, &result) != DDI_SUCCESS) { 369 (void) ddi_dma_unbind_handle(sbb->sbb_dma_hdl); 370 ddi_dma_mem_free(&sbb->sbb_acc_hdl); 371 ddi_dma_free_handle(&sbb->sbb_dma_hdl); 372 kmem_free(sbb, sizeof (scsa1394_bus_buf_t)); 373 return (SBP2_ENOMEM); 374 } 375 sbb->sbb_addr_hdl = aa.aa_hdl; 376 buf->bb_baddr = aa.aa_address; 377 378 buf->bb_hdl = sbb; 379 return (SBP2_SUCCESS); 380 } 381 382 383 static void 384 scsa1394_bus_free_buf_phys(void *hdl, sbp2_bus_buf_t *buf) 385 { 386 scsa1394_state_t *sp = hdl; 387 scsa1394_bus_buf_t *sbb = buf->bb_hdl; 388 389 (void) t1394_free_addr(sp->s_t1394_hdl, &sbb->sbb_addr_hdl, 0); 390 (void) ddi_dma_unbind_handle(sbb->sbb_dma_hdl); 391 ddi_dma_mem_free(&sbb->sbb_acc_hdl); 392 ddi_dma_free_handle(&sbb->sbb_dma_hdl); 393 kmem_free(sbb, sizeof (scsa1394_bus_buf_t)); 394 buf->bb_hdl = NULL; 395 } 396 397 398 static int 399 scsa1394_bus_alloc_buf_normal(void *hdl, sbp2_bus_buf_t *buf, boolean_t posted) 400 { 401 scsa1394_state_t *sp = hdl; 402 scsa1394_bus_buf_t *sbb; /* bus private structure */ 403 t1394_alloc_addr_t aa; 404 int result; 405 406 /* allocate bus private structure */ 407 sbb = kmem_zalloc(sizeof (scsa1394_bus_buf_t), KM_SLEEP); 408 sbb->sbb_state = sp; 409 410 /* allocate 1394 resources */ 411 bzero(&aa, sizeof (aa)); 412 aa.aa_type = posted ? T1394_ADDR_POSTED_WRITE : T1394_ADDR_NORMAL; 413 aa.aa_length = buf->bb_len; 414 if (buf->bb_flags & SBP2_BUS_BUF_RD) { 415 aa.aa_enable |= T1394_ADDR_RDENBL; 416 aa.aa_evts.recv_read_request = scsa1394_bus_recv_read_request; 417 } 418 if (buf->bb_flags & SBP2_BUS_BUF_WR) { 419 aa.aa_enable |= T1394_ADDR_WRENBL; 420 aa.aa_evts.recv_write_request = scsa1394_bus_recv_write_request; 421 } 422 aa.aa_arg = buf; 423 424 if (t1394_alloc_addr(sp->s_t1394_hdl, &aa, 0, &result) != DDI_SUCCESS) { 425 kmem_free(sbb, sizeof (scsa1394_bus_buf_t)); 426 return (SBP2_ENOMEM); 427 } 428 sbb->sbb_addr_hdl = aa.aa_hdl; 429 buf->bb_baddr = aa.aa_address; 430 431 buf->bb_hdl = sbb; 432 return (SBP2_SUCCESS); 433 } 434 435 static void 436 scsa1394_bus_free_buf_normal(void *hdl, sbp2_bus_buf_t *buf) 437 { 438 scsa1394_state_t *sp = hdl; 439 scsa1394_bus_buf_t *sbb = buf->bb_hdl; 440 441 (void) t1394_free_addr(sp->s_t1394_hdl, &sbb->sbb_addr_hdl, 0); 442 kmem_free(sbb, sizeof (scsa1394_bus_buf_t)); 443 buf->bb_hdl = NULL; 444 } 445 446 /*ARGSUSED*/ 447 static int 448 scsa1394_bus_sync_buf(void *hdl, sbp2_bus_buf_t *buf, off_t offset, 449 size_t length, int type) 450 { 451 scsa1394_bus_buf_t *sbb = buf->bb_hdl; 452 453 if (buf->bb_flags & SBP2_BUS_BUF_DMA) { 454 return (ddi_dma_sync(sbb->sbb_dma_hdl, offset, length, type)); 455 } else { 456 return (SBP2_SUCCESS); 457 } 458 } 459 460 /*ARGSUSED*/ 461 static void 462 scsa1394_bus_buf_rw_done(void *hdl, sbp2_bus_buf_t *buf, void *reqh, int error) 463 { 464 scsa1394_state_t *sp = hdl; 465 cmd1394_cmd_t *req = reqh; 466 467 /* complete request */ 468 switch (error) { 469 case SBP2_BUS_BUF_SUCCESS: 470 req->cmd_result = IEEE1394_RESP_COMPLETE; 471 break; 472 case SBP2_BUS_BUF_ELENGTH: 473 req->cmd_result = IEEE1394_RESP_DATA_ERROR; 474 break; 475 case SBP2_BUS_BUF_EBUSY: 476 req->cmd_result = IEEE1394_RESP_CONFLICT_ERROR; 477 break; 478 default: 479 req->cmd_result = IEEE1394_RESP_TYPE_ERROR; 480 } 481 (void) t1394_recv_request_done(sp->s_t1394_hdl, req, 0); 482 } 483 484 485 /* 486 * 487 * --- callbacks 488 * 489 */ 490 static void 491 scsa1394_bus_recv_read_request(cmd1394_cmd_t *req) 492 { 493 sbp2_bus_buf_t *buf = req->cmd_callback_arg; 494 scsa1394_bus_buf_t *sbb = buf->bb_hdl; 495 scsa1394_state_t *sp = sbb->sbb_state; 496 497 /* XXX sanity checks: addr, etc */ 498 if (req->cmd_type == CMD1394_ASYNCH_RD_QUAD) { 499 if (buf->bb_rq_cb) { 500 buf->bb_rq_cb(buf, req, &req->cmd_u.q.quadlet_data); 501 return; 502 } 503 } else { 504 if (buf->bb_rb_cb) { 505 buf->bb_rb_cb(buf, req, &req->cmd_u.b.data_block, 506 req->cmd_u.b.blk_length); 507 return; 508 } 509 } 510 scsa1394_bus_buf_rw_done(sp, buf, req, SBP2_BUS_BUF_FAILURE); 511 } 512 513 514 static void 515 scsa1394_bus_recv_write_request(cmd1394_cmd_t *req) 516 { 517 sbp2_bus_buf_t *buf = req->cmd_callback_arg; 518 scsa1394_bus_buf_t *sbb = buf->bb_hdl; 519 scsa1394_state_t *sp = sbb->sbb_state; 520 521 /* XXX sanity checks: addr, etc */ 522 if (req->cmd_type == CMD1394_ASYNCH_WR_QUAD) { 523 if (buf->bb_wq_cb) { 524 buf->bb_wq_cb(buf, req, req->cmd_u.q.quadlet_data); 525 return; 526 } 527 } else { 528 if (buf->bb_wb_cb) { 529 buf->bb_wb_cb(buf, req, &req->cmd_u.b.data_block); 530 return; 531 } 532 } 533 scsa1394_bus_buf_rw_done(sp, buf, req, SBP2_BUS_BUF_FAILURE); 534 } 535