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