|
|
1.1 ! root 1: /* ! 2: * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator ! 3: * ! 4: * PAPR Virtual SCSI, aka ibmvscsi ! 5: * ! 6: * Copyright (c) 2010,2011 Benjamin Herrenschmidt, IBM Corporation. ! 7: * ! 8: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 9: * of this software and associated documentation files (the "Software"), to deal ! 10: * in the Software without restriction, including without limitation the rights ! 11: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 12: * copies of the Software, and to permit persons to whom the Software is ! 13: * furnished to do so, subject to the following conditions: ! 14: * ! 15: * The above copyright notice and this permission notice shall be included in ! 16: * all copies or substantial portions of the Software. ! 17: * ! 18: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 19: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 20: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 21: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 22: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 23: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 24: * THE SOFTWARE. ! 25: * ! 26: * TODO: ! 27: * ! 28: * - Cleanups :-) ! 29: * - Sort out better how to assign devices to VSCSI instances ! 30: * - Fix residual counts ! 31: * - Add indirect descriptors support ! 32: * - Maybe do autosense (PAPR seems to mandate it, linux doesn't care) ! 33: */ ! 34: #include "hw.h" ! 35: #include "scsi.h" ! 36: #include "scsi-defs.h" ! 37: #include "net.h" /* Remove that when we can */ ! 38: #include "srp.h" ! 39: #include "hw/qdev.h" ! 40: #include "hw/spapr.h" ! 41: #include "hw/spapr_vio.h" ! 42: #include "hw/ppc-viosrp.h" ! 43: ! 44: #include <libfdt.h> ! 45: ! 46: /*#define DEBUG_VSCSI*/ ! 47: ! 48: #ifdef DEBUG_VSCSI ! 49: #define dprintf(fmt, ...) \ ! 50: do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) ! 51: #else ! 52: #define dprintf(fmt, ...) \ ! 53: do { } while (0) ! 54: #endif ! 55: ! 56: /* ! 57: * Virtual SCSI device ! 58: */ ! 59: ! 60: /* Random numbers */ ! 61: #define VSCSI_MAX_SECTORS 4096 ! 62: #define VSCSI_REQ_LIMIT 24 ! 63: ! 64: #define SCSI_SENSE_BUF_SIZE 96 ! 65: #define SRP_RSP_SENSE_DATA_LEN 18 ! 66: ! 67: typedef union vscsi_crq { ! 68: struct viosrp_crq s; ! 69: uint8_t raw[16]; ! 70: } vscsi_crq; ! 71: ! 72: typedef struct vscsi_req { ! 73: vscsi_crq crq; ! 74: union viosrp_iu iu; ! 75: ! 76: /* SCSI request tracking */ ! 77: SCSIRequest *sreq; ! 78: uint32_t qtag; /* qemu tag != srp tag */ ! 79: int lun; ! 80: int active; ! 81: long data_len; ! 82: int writing; ! 83: int sensing; ! 84: int senselen; ! 85: uint8_t sense[SCSI_SENSE_BUF_SIZE]; ! 86: ! 87: /* RDMA related bits */ ! 88: uint8_t dma_fmt; ! 89: struct srp_direct_buf ext_desc; ! 90: struct srp_direct_buf *cur_desc; ! 91: struct srp_indirect_buf *ind_desc; ! 92: int local_desc; ! 93: int total_desc; ! 94: } vscsi_req; ! 95: ! 96: ! 97: typedef struct { ! 98: VIOsPAPRDevice vdev; ! 99: SCSIBus bus; ! 100: vscsi_req reqs[VSCSI_REQ_LIMIT]; ! 101: } VSCSIState; ! 102: ! 103: /* XXX Debug only */ ! 104: static VSCSIState *dbg_vscsi_state; ! 105: ! 106: ! 107: static struct vscsi_req *vscsi_get_req(VSCSIState *s) ! 108: { ! 109: vscsi_req *req; ! 110: int i; ! 111: ! 112: for (i = 0; i < VSCSI_REQ_LIMIT; i++) { ! 113: req = &s->reqs[i]; ! 114: if (!req->active) { ! 115: memset(req, 0, sizeof(*req)); ! 116: req->qtag = i; ! 117: req->active = 1; ! 118: return req; ! 119: } ! 120: } ! 121: return NULL; ! 122: } ! 123: ! 124: static void vscsi_put_req(vscsi_req *req) ! 125: { ! 126: if (req->sreq != NULL) { ! 127: scsi_req_unref(req->sreq); ! 128: } ! 129: req->sreq = NULL; ! 130: req->active = 0; ! 131: } ! 132: ! 133: static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun) ! 134: { ! 135: /* XXX Figure that one out properly ! This is crackpot */ ! 136: *id = (srp_lun >> 56) & 0x7f; ! 137: *lun = (srp_lun >> 48) & 0xff; ! 138: } ! 139: ! 140: static int vscsi_send_iu(VSCSIState *s, vscsi_req *req, ! 141: uint64_t length, uint8_t format) ! 142: { ! 143: long rc, rc1; ! 144: ! 145: /* First copy the SRP */ ! 146: rc = spapr_tce_dma_write(&s->vdev, req->crq.s.IU_data_ptr, ! 147: &req->iu, length); ! 148: if (rc) { ! 149: fprintf(stderr, "vscsi_send_iu: DMA write failure !\n"); ! 150: } ! 151: ! 152: req->crq.s.valid = 0x80; ! 153: req->crq.s.format = format; ! 154: req->crq.s.reserved = 0x00; ! 155: req->crq.s.timeout = cpu_to_be16(0x0000); ! 156: req->crq.s.IU_length = cpu_to_be16(length); ! 157: req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */ ! 158: ! 159: if (rc == 0) { ! 160: req->crq.s.status = 0x99; /* Just needs to be non-zero */ ! 161: } else { ! 162: req->crq.s.status = 0x00; ! 163: } ! 164: ! 165: rc1 = spapr_vio_send_crq(&s->vdev, req->crq.raw); ! 166: if (rc1) { ! 167: fprintf(stderr, "vscsi_send_iu: Error sending response\n"); ! 168: return rc1; ! 169: } ! 170: ! 171: return rc; ! 172: } ! 173: ! 174: static void vscsi_makeup_sense(VSCSIState *s, vscsi_req *req, ! 175: uint8_t key, uint8_t asc, uint8_t ascq) ! 176: { ! 177: req->senselen = SRP_RSP_SENSE_DATA_LEN; ! 178: ! 179: /* Valid bit and 'current errors' */ ! 180: req->sense[0] = (0x1 << 7 | 0x70); ! 181: /* Sense key */ ! 182: req->sense[2] = key; ! 183: /* Additional sense length */ ! 184: req->sense[7] = 0xa; /* 10 bytes */ ! 185: /* Additional sense code */ ! 186: req->sense[12] = asc; ! 187: req->sense[13] = ascq; ! 188: } ! 189: ! 190: static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req, ! 191: uint8_t status, int32_t res_in, int32_t res_out) ! 192: { ! 193: union viosrp_iu *iu = &req->iu; ! 194: uint64_t tag = iu->srp.rsp.tag; ! 195: int total_len = sizeof(iu->srp.rsp); ! 196: ! 197: dprintf("VSCSI: Sending resp status: 0x%x, " ! 198: "res_in: %d, res_out: %d\n", status, res_in, res_out); ! 199: ! 200: memset(iu, 0, sizeof(struct srp_rsp)); ! 201: iu->srp.rsp.opcode = SRP_RSP; ! 202: iu->srp.rsp.req_lim_delta = cpu_to_be32(1); ! 203: iu->srp.rsp.tag = tag; ! 204: ! 205: /* Handle residuals */ ! 206: if (res_in < 0) { ! 207: iu->srp.rsp.flags |= SRP_RSP_FLAG_DIUNDER; ! 208: res_in = -res_in; ! 209: } else if (res_in) { ! 210: iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER; ! 211: } ! 212: if (res_out < 0) { ! 213: iu->srp.rsp.flags |= SRP_RSP_FLAG_DOUNDER; ! 214: res_out = -res_out; ! 215: } else if (res_out) { ! 216: iu->srp.rsp.flags |= SRP_RSP_FLAG_DOOVER; ! 217: } ! 218: iu->srp.rsp.data_in_res_cnt = cpu_to_be32(res_in); ! 219: iu->srp.rsp.data_out_res_cnt = cpu_to_be32(res_out); ! 220: ! 221: /* We don't do response data */ ! 222: /* iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID; */ ! 223: iu->srp.rsp.resp_data_len = cpu_to_be32(0); ! 224: ! 225: /* Handle success vs. failure */ ! 226: iu->srp.rsp.status = status; ! 227: if (status) { ! 228: iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x04) >> 2; ! 229: if (req->senselen) { ! 230: req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; ! 231: req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen); ! 232: memcpy(req->iu.srp.rsp.data, req->sense, req->senselen); ! 233: total_len += req->senselen; ! 234: } ! 235: } else { ! 236: iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x02) >> 1; ! 237: } ! 238: ! 239: vscsi_send_iu(s, req, total_len, VIOSRP_SRP_FORMAT); ! 240: return 0; ! 241: } ! 242: ! 243: static inline void vscsi_swap_desc(struct srp_direct_buf *desc) ! 244: { ! 245: desc->va = be64_to_cpu(desc->va); ! 246: desc->len = be32_to_cpu(desc->len); ! 247: } ! 248: ! 249: static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req, ! 250: uint8_t *buf, uint32_t len) ! 251: { ! 252: struct srp_direct_buf *md = req->cur_desc; ! 253: uint32_t llen; ! 254: int rc = 0; ! 255: ! 256: dprintf("VSCSI: direct segment 0x%x bytes, va=0x%llx desc len=0x%x\n", ! 257: len, (unsigned long long)md->va, md->len); ! 258: ! 259: llen = MIN(len, md->len); ! 260: if (llen) { ! 261: if (req->writing) { /* writing = to device = reading from memory */ ! 262: rc = spapr_tce_dma_read(&s->vdev, md->va, buf, llen); ! 263: } else { ! 264: rc = spapr_tce_dma_write(&s->vdev, md->va, buf, llen); ! 265: } ! 266: } ! 267: md->len -= llen; ! 268: md->va += llen; ! 269: ! 270: if (rc) { ! 271: return -1; ! 272: } ! 273: return llen; ! 274: } ! 275: ! 276: static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req, ! 277: uint8_t *buf, uint32_t len) ! 278: { ! 279: struct srp_direct_buf *td = &req->ind_desc->table_desc; ! 280: struct srp_direct_buf *md = req->cur_desc; ! 281: int rc = 0; ! 282: uint32_t llen, total = 0; ! 283: ! 284: dprintf("VSCSI: indirect segment 0x%x bytes, td va=0x%llx len=0x%x\n", ! 285: len, (unsigned long long)td->va, td->len); ! 286: ! 287: /* While we have data ... */ ! 288: while (len) { ! 289: /* If we have a descriptor but it's empty, go fetch a new one */ ! 290: if (md && md->len == 0) { ! 291: /* More local available, use one */ ! 292: if (req->local_desc) { ! 293: md = ++req->cur_desc; ! 294: --req->local_desc; ! 295: --req->total_desc; ! 296: td->va += sizeof(struct srp_direct_buf); ! 297: } else { ! 298: md = req->cur_desc = NULL; ! 299: } ! 300: } ! 301: /* No descriptor at hand, fetch one */ ! 302: if (!md) { ! 303: if (!req->total_desc) { ! 304: dprintf("VSCSI: Out of descriptors !\n"); ! 305: break; ! 306: } ! 307: md = req->cur_desc = &req->ext_desc; ! 308: dprintf("VSCSI: Reading desc from 0x%llx\n", ! 309: (unsigned long long)td->va); ! 310: rc = spapr_tce_dma_read(&s->vdev, td->va, md, ! 311: sizeof(struct srp_direct_buf)); ! 312: if (rc) { ! 313: dprintf("VSCSI: tce_dma_read -> %d reading ext_desc\n", rc); ! 314: break; ! 315: } ! 316: vscsi_swap_desc(md); ! 317: td->va += sizeof(struct srp_direct_buf); ! 318: --req->total_desc; ! 319: } ! 320: dprintf("VSCSI: [desc va=0x%llx,len=0x%x] remaining=0x%x\n", ! 321: (unsigned long long)md->va, md->len, len); ! 322: ! 323: /* Perform transfer */ ! 324: llen = MIN(len, md->len); ! 325: if (req->writing) { /* writing = to device = reading from memory */ ! 326: rc = spapr_tce_dma_read(&s->vdev, md->va, buf, llen); ! 327: } else { ! 328: rc = spapr_tce_dma_write(&s->vdev, md->va, buf, llen); ! 329: } ! 330: if (rc) { ! 331: dprintf("VSCSI: tce_dma_r/w(%d) -> %d\n", req->writing, rc); ! 332: break; ! 333: } ! 334: dprintf("VSCSI: data: %02x %02x %02x %02x...\n", ! 335: buf[0], buf[1], buf[2], buf[3]); ! 336: ! 337: len -= llen; ! 338: buf += llen; ! 339: total += llen; ! 340: md->va += llen; ! 341: md->len -= llen; ! 342: } ! 343: return rc ? -1 : total; ! 344: } ! 345: ! 346: static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req, ! 347: int writing, uint8_t *buf, uint32_t len) ! 348: { ! 349: int err = 0; ! 350: ! 351: switch (req->dma_fmt) { ! 352: case SRP_NO_DATA_DESC: ! 353: dprintf("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len); ! 354: break; ! 355: case SRP_DATA_DESC_DIRECT: ! 356: err = vscsi_srp_direct_data(s, req, buf, len); ! 357: break; ! 358: case SRP_DATA_DESC_INDIRECT: ! 359: err = vscsi_srp_indirect_data(s, req, buf, len); ! 360: break; ! 361: } ! 362: return err; ! 363: } ! 364: ! 365: /* Bits from linux srp */ ! 366: static int data_out_desc_size(struct srp_cmd *cmd) ! 367: { ! 368: int size = 0; ! 369: uint8_t fmt = cmd->buf_fmt >> 4; ! 370: ! 371: switch (fmt) { ! 372: case SRP_NO_DATA_DESC: ! 373: break; ! 374: case SRP_DATA_DESC_DIRECT: ! 375: size = sizeof(struct srp_direct_buf); ! 376: break; ! 377: case SRP_DATA_DESC_INDIRECT: ! 378: size = sizeof(struct srp_indirect_buf) + ! 379: sizeof(struct srp_direct_buf)*cmd->data_out_desc_cnt; ! 380: break; ! 381: default: ! 382: break; ! 383: } ! 384: return size; ! 385: } ! 386: ! 387: static int vscsi_preprocess_desc(vscsi_req *req) ! 388: { ! 389: struct srp_cmd *cmd = &req->iu.srp.cmd; ! 390: int offset, i; ! 391: ! 392: offset = cmd->add_cdb_len & ~3; ! 393: ! 394: if (req->writing) { ! 395: req->dma_fmt = cmd->buf_fmt >> 4; ! 396: } else { ! 397: offset += data_out_desc_size(cmd); ! 398: req->dma_fmt = cmd->buf_fmt & ((1U << 4) - 1); ! 399: } ! 400: ! 401: switch (req->dma_fmt) { ! 402: case SRP_NO_DATA_DESC: ! 403: break; ! 404: case SRP_DATA_DESC_DIRECT: ! 405: req->cur_desc = (struct srp_direct_buf *)(cmd->add_data + offset); ! 406: req->total_desc = req->local_desc = 1; ! 407: vscsi_swap_desc(req->cur_desc); ! 408: dprintf("VSCSI: using direct RDMA %s, 0x%x bytes MD: 0x%llx\n", ! 409: req->writing ? "write" : "read", ! 410: req->cur_desc->len, (unsigned long long)req->cur_desc->va); ! 411: break; ! 412: case SRP_DATA_DESC_INDIRECT: ! 413: req->ind_desc = (struct srp_indirect_buf *)(cmd->add_data + offset); ! 414: vscsi_swap_desc(&req->ind_desc->table_desc); ! 415: req->total_desc = req->ind_desc->table_desc.len / ! 416: sizeof(struct srp_direct_buf); ! 417: req->local_desc = req->writing ? cmd->data_out_desc_cnt : ! 418: cmd->data_in_desc_cnt; ! 419: for (i = 0; i < req->local_desc; i++) { ! 420: vscsi_swap_desc(&req->ind_desc->desc_list[i]); ! 421: } ! 422: req->cur_desc = req->local_desc ? &req->ind_desc->desc_list[0] : NULL; ! 423: dprintf("VSCSI: using indirect RDMA %s, 0x%x bytes %d descs " ! 424: "(%d local) VA: 0x%llx\n", ! 425: req->writing ? "read" : "write", ! 426: be32_to_cpu(req->ind_desc->len), ! 427: req->total_desc, req->local_desc, ! 428: (unsigned long long)req->ind_desc->table_desc.va); ! 429: break; ! 430: default: ! 431: fprintf(stderr, ! 432: "vscsi_preprocess_desc: Unknown format %x\n", req->dma_fmt); ! 433: return -1; ! 434: } ! 435: ! 436: return 0; ! 437: } ! 438: ! 439: static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) ! 440: { ! 441: uint8_t *cdb = req->iu.srp.cmd.cdb; ! 442: int n; ! 443: ! 444: n = scsi_req_get_sense(req->sreq, req->sense, sizeof(req->sense)); ! 445: if (n) { ! 446: req->senselen = n; ! 447: vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); ! 448: vscsi_put_req(req); ! 449: return; ! 450: } ! 451: ! 452: dprintf("VSCSI: Got CHECK_CONDITION, requesting sense...\n"); ! 453: cdb[0] = 3; ! 454: cdb[1] = 0; ! 455: cdb[2] = 0; ! 456: cdb[3] = 0; ! 457: cdb[4] = 96; ! 458: cdb[5] = 0; ! 459: req->sensing = 1; ! 460: n = scsi_req_enqueue(req->sreq, cdb); ! 461: dprintf("VSCSI: Queued request sense tag 0x%x\n", req->qtag); ! 462: if (n < 0) { ! 463: fprintf(stderr, "VSCSI: REQUEST_SENSE wants write data !?!?!?\n"); ! 464: vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); ! 465: scsi_req_abort(req->sreq, CHECK_CONDITION); ! 466: return; ! 467: } else if (n == 0) { ! 468: return; ! 469: } ! 470: scsi_req_continue(req->sreq); ! 471: } ! 472: ! 473: /* Callback to indicate that the SCSI layer has completed a transfer. */ ! 474: static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) ! 475: { ! 476: VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); ! 477: vscsi_req *req = sreq->hba_private; ! 478: uint8_t *buf; ! 479: int rc = 0; ! 480: ! 481: dprintf("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n", ! 482: sreq->tag, len, req); ! 483: if (req == NULL) { ! 484: fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); ! 485: return; ! 486: } ! 487: ! 488: if (req->sensing) { ! 489: uint8_t *buf = scsi_req_get_buf(sreq); ! 490: ! 491: len = MIN(len, SCSI_SENSE_BUF_SIZE); ! 492: dprintf("VSCSI: Sense data, %d bytes:\n", len); ! 493: dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", ! 494: buf[0], buf[1], buf[2], buf[3], ! 495: buf[4], buf[5], buf[6], buf[7]); ! 496: dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", ! 497: buf[8], buf[9], buf[10], buf[11], ! 498: buf[12], buf[13], buf[14], buf[15]); ! 499: memcpy(req->sense, buf, len); ! 500: req->senselen = len; ! 501: scsi_req_continue(req->sreq); ! 502: return; ! 503: } ! 504: ! 505: if (len) { ! 506: buf = scsi_req_get_buf(sreq); ! 507: rc = vscsi_srp_transfer_data(s, req, req->writing, buf, len); ! 508: } ! 509: if (rc < 0) { ! 510: fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc); ! 511: vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); ! 512: scsi_req_abort(req->sreq, CHECK_CONDITION); ! 513: return; ! 514: } ! 515: ! 516: /* Start next chunk */ ! 517: req->data_len -= rc; ! 518: scsi_req_continue(sreq); ! 519: } ! 520: ! 521: /* Callback to indicate that the SCSI layer has completed a transfer. */ ! 522: static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status) ! 523: { ! 524: VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); ! 525: vscsi_req *req = sreq->hba_private; ! 526: int32_t res_in = 0, res_out = 0; ! 527: ! 528: dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n", ! 529: reason, sreq->tag, status, req); ! 530: if (req == NULL) { ! 531: fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); ! 532: return; ! 533: } ! 534: ! 535: if (!req->sensing && status == CHECK_CONDITION) { ! 536: vscsi_send_request_sense(s, req); ! 537: return; ! 538: } ! 539: ! 540: if (req->sensing) { ! 541: dprintf("VSCSI: Sense done !\n"); ! 542: status = CHECK_CONDITION; ! 543: } else { ! 544: dprintf("VSCSI: Command complete err=%d\n", status); ! 545: if (status == 0) { ! 546: /* We handle overflows, not underflows for normal commands, ! 547: * but hopefully nobody cares ! 548: */ ! 549: if (req->writing) { ! 550: res_out = req->data_len; ! 551: } else { ! 552: res_in = req->data_len; ! 553: } ! 554: } ! 555: } ! 556: vscsi_send_rsp(s, req, 0, res_in, res_out); ! 557: vscsi_put_req(req); ! 558: } ! 559: ! 560: static void vscsi_request_cancelled(SCSIRequest *sreq) ! 561: { ! 562: vscsi_req *req = sreq->hba_private; ! 563: ! 564: vscsi_put_req(req); ! 565: } ! 566: ! 567: static void vscsi_process_login(VSCSIState *s, vscsi_req *req) ! 568: { ! 569: union viosrp_iu *iu = &req->iu; ! 570: struct srp_login_rsp *rsp = &iu->srp.login_rsp; ! 571: uint64_t tag = iu->srp.rsp.tag; ! 572: ! 573: dprintf("VSCSI: Got login, sendin response !\n"); ! 574: ! 575: /* TODO handle case that requested size is wrong and ! 576: * buffer format is wrong ! 577: */ ! 578: memset(iu, 0, sizeof(struct srp_login_rsp)); ! 579: rsp->opcode = SRP_LOGIN_RSP; ! 580: /* Don't advertise quite as many request as we support to ! 581: * keep room for management stuff etc... ! 582: */ ! 583: rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2); ! 584: rsp->tag = tag; ! 585: rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu)); ! 586: rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu)); ! 587: /* direct and indirect */ ! 588: rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT); ! 589: ! 590: vscsi_send_iu(s, req, sizeof(*rsp), VIOSRP_SRP_FORMAT); ! 591: } ! 592: ! 593: static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req) ! 594: { ! 595: uint8_t *cdb = req->iu.srp.cmd.cdb; ! 596: uint8_t resp_data[36]; ! 597: int rc, len, alen; ! 598: ! 599: /* We dont do EVPD. Also check that page_code is 0 */ ! 600: if ((cdb[1] & 0x01) || (cdb[1] & 0x01) || cdb[2] != 0) { ! 601: /* Send INVALID FIELD IN CDB */ ! 602: vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0); ! 603: vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); ! 604: return; ! 605: } ! 606: alen = cdb[3]; ! 607: alen = (alen << 8) | cdb[4]; ! 608: len = MIN(alen, 36); ! 609: ! 610: /* Fake up inquiry using PQ=3 */ ! 611: memset(resp_data, 0, 36); ! 612: resp_data[0] = 0x7f; /* Not capable of supporting a device here */ ! 613: resp_data[2] = 0x06; /* SPS-4 */ ! 614: resp_data[3] = 0x02; /* Resp data format */ ! 615: resp_data[4] = 36 - 5; /* Additional length */ ! 616: resp_data[7] = 0x10; /* Sync transfers */ ! 617: memcpy(&resp_data[16], "QEMU EMPTY ", 16); ! 618: memcpy(&resp_data[8], "QEMU ", 8); ! 619: ! 620: req->writing = 0; ! 621: vscsi_preprocess_desc(req); ! 622: rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len); ! 623: if (rc < 0) { ! 624: vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); ! 625: vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); ! 626: } else { ! 627: vscsi_send_rsp(s, req, 0, 36 - rc, 0); ! 628: } ! 629: } ! 630: ! 631: static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) ! 632: { ! 633: union srp_iu *srp = &req->iu.srp; ! 634: SCSIDevice *sdev; ! 635: int n, id, lun; ! 636: ! 637: vscsi_decode_id_lun(be64_to_cpu(srp->cmd.lun), &id, &lun); ! 638: ! 639: /* Qemu vs. linux issue with LUNs to be sorted out ... */ ! 640: sdev = (id < 8 && lun < 16) ? s->bus.devs[id] : NULL; ! 641: if (!sdev) { ! 642: dprintf("VSCSI: Command for id %d with no drive\n", id); ! 643: if (srp->cmd.cdb[0] == INQUIRY) { ! 644: vscsi_inquiry_no_target(s, req); ! 645: } else { ! 646: vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0x00); ! 647: vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); ! 648: } return 1; ! 649: } ! 650: ! 651: req->lun = lun; ! 652: req->sreq = scsi_req_new(sdev, req->qtag, lun, req); ! 653: n = scsi_req_enqueue(req->sreq, srp->cmd.cdb); ! 654: ! 655: dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n", ! 656: req->qtag, srp->cmd.cdb[0], id, lun, n); ! 657: ! 658: if (n) { ! 659: /* Transfer direction must be set before preprocessing the ! 660: * descriptors ! 661: */ ! 662: req->writing = (n < 1); ! 663: ! 664: /* Preprocess RDMA descriptors */ ! 665: vscsi_preprocess_desc(req); ! 666: ! 667: /* Get transfer direction and initiate transfer */ ! 668: if (n > 0) { ! 669: req->data_len = n; ! 670: } else if (n < 0) { ! 671: req->data_len = -n; ! 672: } ! 673: scsi_req_continue(req->sreq); ! 674: } ! 675: /* Don't touch req here, it may have been recycled already */ ! 676: ! 677: return 0; ! 678: } ! 679: ! 680: static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req) ! 681: { ! 682: union viosrp_iu *iu = &req->iu; ! 683: int fn; ! 684: ! 685: fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n", ! 686: iu->srp.tsk_mgmt.tsk_mgmt_func); ! 687: ! 688: switch (iu->srp.tsk_mgmt.tsk_mgmt_func) { ! 689: #if 0 /* We really don't deal with these for now */ ! 690: case SRP_TSK_ABORT_TASK: ! 691: fn = ABORT_TASK; ! 692: break; ! 693: case SRP_TSK_ABORT_TASK_SET: ! 694: fn = ABORT_TASK_SET; ! 695: break; ! 696: case SRP_TSK_CLEAR_TASK_SET: ! 697: fn = CLEAR_TASK_SET; ! 698: break; ! 699: case SRP_TSK_LUN_RESET: ! 700: fn = LOGICAL_UNIT_RESET; ! 701: break; ! 702: case SRP_TSK_CLEAR_ACA: ! 703: fn = CLEAR_ACA; ! 704: break; ! 705: #endif ! 706: default: ! 707: fn = 0; ! 708: } ! 709: if (fn) { ! 710: /* XXX Send/Handle target task management */ ! 711: ; ! 712: } else { ! 713: vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x20, 0); ! 714: vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); ! 715: } ! 716: return !fn; ! 717: } ! 718: ! 719: static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req) ! 720: { ! 721: union srp_iu *srp = &req->iu.srp; ! 722: int done = 1; ! 723: uint8_t opcode = srp->rsp.opcode; ! 724: ! 725: switch (opcode) { ! 726: case SRP_LOGIN_REQ: ! 727: vscsi_process_login(s, req); ! 728: break; ! 729: case SRP_TSK_MGMT: ! 730: done = vscsi_process_tsk_mgmt(s, req); ! 731: break; ! 732: case SRP_CMD: ! 733: done = vscsi_queue_cmd(s, req); ! 734: break; ! 735: case SRP_LOGIN_RSP: ! 736: case SRP_I_LOGOUT: ! 737: case SRP_T_LOGOUT: ! 738: case SRP_RSP: ! 739: case SRP_CRED_REQ: ! 740: case SRP_CRED_RSP: ! 741: case SRP_AER_REQ: ! 742: case SRP_AER_RSP: ! 743: fprintf(stderr, "VSCSI: Unsupported opcode %02x\n", opcode); ! 744: break; ! 745: default: ! 746: fprintf(stderr, "VSCSI: Unknown type %02x\n", opcode); ! 747: } ! 748: ! 749: return done; ! 750: } ! 751: ! 752: static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req) ! 753: { ! 754: struct viosrp_adapter_info *sinfo; ! 755: struct mad_adapter_info_data info; ! 756: int rc; ! 757: ! 758: sinfo = &req->iu.mad.adapter_info; ! 759: ! 760: #if 0 /* What for ? */ ! 761: rc = spapr_tce_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer), ! 762: &info, be16_to_cpu(sinfo->common.length)); ! 763: if (rc) { ! 764: fprintf(stderr, "vscsi_send_adapter_info: DMA read failure !\n"); ! 765: } ! 766: #endif ! 767: memset(&info, 0, sizeof(info)); ! 768: strcpy(info.srp_version, SRP_VERSION); ! 769: strncpy(info.partition_name, "qemu", sizeof("qemu")); ! 770: info.partition_number = cpu_to_be32(0); ! 771: info.mad_version = cpu_to_be32(1); ! 772: info.os_type = cpu_to_be32(2); ! 773: info.port_max_txu[0] = cpu_to_be32(VSCSI_MAX_SECTORS << 9); ! 774: ! 775: rc = spapr_tce_dma_write(&s->vdev, be64_to_cpu(sinfo->buffer), ! 776: &info, be16_to_cpu(sinfo->common.length)); ! 777: if (rc) { ! 778: fprintf(stderr, "vscsi_send_adapter_info: DMA write failure !\n"); ! 779: } ! 780: ! 781: sinfo->common.status = rc ? cpu_to_be32(1) : 0; ! 782: ! 783: return vscsi_send_iu(s, req, sizeof(*sinfo), VIOSRP_MAD_FORMAT); ! 784: } ! 785: ! 786: static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req) ! 787: { ! 788: union mad_iu *mad = &req->iu.mad; ! 789: ! 790: switch (be32_to_cpu(mad->empty_iu.common.type)) { ! 791: case VIOSRP_EMPTY_IU_TYPE: ! 792: fprintf(stderr, "Unsupported EMPTY MAD IU\n"); ! 793: break; ! 794: case VIOSRP_ERROR_LOG_TYPE: ! 795: fprintf(stderr, "Unsupported ERROR LOG MAD IU\n"); ! 796: mad->error_log.common.status = cpu_to_be16(1); ! 797: vscsi_send_iu(s, req, sizeof(mad->error_log), VIOSRP_MAD_FORMAT); ! 798: break; ! 799: case VIOSRP_ADAPTER_INFO_TYPE: ! 800: vscsi_send_adapter_info(s, req); ! 801: break; ! 802: case VIOSRP_HOST_CONFIG_TYPE: ! 803: mad->host_config.common.status = cpu_to_be16(1); ! 804: vscsi_send_iu(s, req, sizeof(mad->host_config), VIOSRP_MAD_FORMAT); ! 805: break; ! 806: default: ! 807: fprintf(stderr, "VSCSI: Unknown MAD type %02x\n", ! 808: be32_to_cpu(mad->empty_iu.common.type)); ! 809: } ! 810: ! 811: return 1; ! 812: } ! 813: ! 814: static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq) ! 815: { ! 816: vscsi_req *req; ! 817: int done; ! 818: ! 819: req = vscsi_get_req(s); ! 820: if (req == NULL) { ! 821: fprintf(stderr, "VSCSI: Failed to get a request !\n"); ! 822: return; ! 823: } ! 824: ! 825: /* We only support a limited number of descriptors, we know ! 826: * the ibmvscsi driver uses up to 10 max, so it should fit ! 827: * in our 256 bytes IUs. If not we'll have to increase the size ! 828: * of the structure. ! 829: */ ! 830: if (crq->s.IU_length > sizeof(union viosrp_iu)) { ! 831: fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n", ! 832: crq->s.IU_length); ! 833: return; ! 834: } ! 835: ! 836: /* XXX Handle failure differently ? */ ! 837: if (spapr_tce_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu, ! 838: crq->s.IU_length)) { ! 839: fprintf(stderr, "vscsi_got_payload: DMA read failure !\n"); ! 840: qemu_free(req); ! 841: } ! 842: memcpy(&req->crq, crq, sizeof(vscsi_crq)); ! 843: ! 844: if (crq->s.format == VIOSRP_MAD_FORMAT) { ! 845: done = vscsi_handle_mad_req(s, req); ! 846: } else { ! 847: done = vscsi_handle_srp_req(s, req); ! 848: } ! 849: ! 850: if (done) { ! 851: vscsi_put_req(req); ! 852: } ! 853: } ! 854: ! 855: ! 856: static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data) ! 857: { ! 858: VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); ! 859: vscsi_crq crq; ! 860: ! 861: memcpy(crq.raw, crq_data, 16); ! 862: crq.s.timeout = be16_to_cpu(crq.s.timeout); ! 863: crq.s.IU_length = be16_to_cpu(crq.s.IU_length); ! 864: crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr); ! 865: ! 866: dprintf("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]); ! 867: ! 868: switch (crq.s.valid) { ! 869: case 0xc0: /* Init command/response */ ! 870: ! 871: /* Respond to initialization request */ ! 872: if (crq.s.format == 0x01) { ! 873: memset(crq.raw, 0, 16); ! 874: crq.s.valid = 0xc0; ! 875: crq.s.format = 0x02; ! 876: spapr_vio_send_crq(dev, crq.raw); ! 877: } ! 878: ! 879: /* Note that in hotplug cases, we might get a 0x02 ! 880: * as a result of us emitting the init request ! 881: */ ! 882: ! 883: break; ! 884: case 0xff: /* Link event */ ! 885: ! 886: /* Not handled for now */ ! 887: ! 888: break; ! 889: case 0x80: /* Payloads */ ! 890: switch (crq.s.format) { ! 891: case VIOSRP_SRP_FORMAT: /* AKA VSCSI request */ ! 892: case VIOSRP_MAD_FORMAT: /* AKA VSCSI response */ ! 893: vscsi_got_payload(s, &crq); ! 894: break; ! 895: case VIOSRP_OS400_FORMAT: ! 896: case VIOSRP_AIX_FORMAT: ! 897: case VIOSRP_LINUX_FORMAT: ! 898: case VIOSRP_INLINE_FORMAT: ! 899: fprintf(stderr, "vscsi_do_srq: Unsupported payload format %02x\n", ! 900: crq.s.format); ! 901: break; ! 902: default: ! 903: fprintf(stderr, "vscsi_do_srq: Unknown payload format %02x\n", ! 904: crq.s.format); ! 905: } ! 906: break; ! 907: default: ! 908: fprintf(stderr, "vscsi_do_crq: unknown CRQ %02x %02x ...\n", ! 909: crq.raw[0], crq.raw[1]); ! 910: }; ! 911: ! 912: return 0; ! 913: } ! 914: ! 915: static const struct SCSIBusOps vscsi_scsi_ops = { ! 916: .transfer_data = vscsi_transfer_data, ! 917: .complete = vscsi_command_complete, ! 918: .cancel = vscsi_request_cancelled ! 919: }; ! 920: ! 921: static int spapr_vscsi_init(VIOsPAPRDevice *dev) ! 922: { ! 923: VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); ! 924: int i; ! 925: ! 926: dbg_vscsi_state = s; ! 927: ! 928: /* Initialize qemu request tags */ ! 929: memset(s->reqs, 0, sizeof(s->reqs)); ! 930: for (i = 0; i < VSCSI_REQ_LIMIT; i++) { ! 931: s->reqs[i].qtag = i; ! 932: } ! 933: ! 934: dev->crq.SendFunc = vscsi_do_crq; ! 935: ! 936: scsi_bus_new(&s->bus, &dev->qdev, 1, VSCSI_REQ_LIMIT, ! 937: &vscsi_scsi_ops); ! 938: if (!dev->qdev.hotplugged) { ! 939: scsi_bus_legacy_handle_cmdline(&s->bus); ! 940: } ! 941: ! 942: return 0; ! 943: } ! 944: ! 945: void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg, ! 946: qemu_irq qirq, uint32_t vio_irq_num) ! 947: { ! 948: DeviceState *dev; ! 949: VIOsPAPRDevice *sdev; ! 950: ! 951: dev = qdev_create(&bus->bus, "spapr-vscsi"); ! 952: qdev_prop_set_uint32(dev, "reg", reg); ! 953: ! 954: qdev_init_nofail(dev); ! 955: ! 956: sdev = (VIOsPAPRDevice *)dev; ! 957: sdev->qirq = qirq; ! 958: sdev->vio_irq_num = vio_irq_num; ! 959: } ! 960: ! 961: static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) ! 962: { ! 963: int ret; ! 964: ! 965: ret = fdt_setprop_cell(fdt, node_off, "#address-cells", 2); ! 966: if (ret < 0) { ! 967: return ret; ! 968: } ! 969: ! 970: ret = fdt_setprop_cell(fdt, node_off, "#size-cells", 0); ! 971: if (ret < 0) { ! 972: return ret; ! 973: } ! 974: ! 975: return 0; ! 976: } ! 977: ! 978: static VIOsPAPRDeviceInfo spapr_vscsi = { ! 979: .init = spapr_vscsi_init, ! 980: .devnode = spapr_vscsi_devnode, ! 981: .dt_name = "v-scsi", ! 982: .dt_type = "vscsi", ! 983: .dt_compatible = "IBM,v-scsi", ! 984: .signal_mask = 0x00000001, ! 985: .qdev.name = "spapr-vscsi", ! 986: .qdev.size = sizeof(VSCSIState), ! 987: .qdev.props = (Property[]) { ! 988: DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x2000), ! 989: DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice, ! 990: rtce_window_size, 0x10000000), ! 991: DEFINE_PROP_END_OF_LIST(), ! 992: }, ! 993: }; ! 994: ! 995: static void spapr_vscsi_register(void) ! 996: { ! 997: spapr_vio_bus_register_withprop(&spapr_vscsi); ! 998: } ! 999: device_init(spapr_vscsi_register);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.