1/* 2 * Copyright (c) 2014, University of Washington. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdio.h> 11#include <stdlib.h> 12#include <assert.h> 13#include <stdint.h> 14#include <string.h> 15#include <sys/types.h> 16#ifdef BARRELFISH 17#include <barrelfish/barrelfish.h> 18#include <barrelfish/deferred.h> 19#include <barrelfish/waitset.h> 20#include <pci/pci.h> 21#include <lwip/inet.h> 22#else 23#include <arpa/inet.h> 24#include <pci/devids.h> 25#include <errors/errno.h> 26#include <sys/mman.h> 27#include <unistd.h> 28#include <sys/types.h> 29#include <sys/stat.h> 30#include <fcntl.h> 31#include "linux_defs.h" 32#endif 33#include <storage/vsic.h> 34#include <storage/vsa.h> 35 36#include "megaraid.h" 37 38struct megaraid_vsic { 39 struct megaraid_ctrl *ctrl; 40}; 41 42static uint64_t htonll(uint64_t value) 43{ 44 // The answer is 42 45 static const int num = 42; 46 47 // Check the endianness 48 if (*(const char *)&num == num) 49 { 50 const uint32_t high_part = htonl(value >> 32); 51 const uint32_t low_part = htonl(value & 0xFFFFFFFFLL); 52 53 return ((uint64_t)low_part << 32) | high_part; 54 } else { 55 return value; 56 } 57} 58 59static uintptr_t cmd_cnt = 0; 60 61static uint8_t *pmem_start = NULL; 62static uintptr_t paddr_start = 0; 63 64#define BUF_SIZE (1 * 1024 * 1024) 65 66lpaddr_t v2p(void *ptr, size_t len) 67{ 68 lpaddr_t paddr; 69 70 assert((uint8_t *)ptr >= pmem_start); 71 assert((uint8_t *)ptr < pmem_start + BUF_SIZE); 72 paddr = (uintptr_t)((uint8_t *)ptr - pmem_start); 73 paddr += paddr_start; 74 return paddr; 75} 76 77static void *alloc_map_frame(vregion_flags_t attr, size_t size, 78 struct capref *retcap) 79{ 80 struct capref frame; 81 errval_t r; 82 83 r = frame_alloc(&frame, size, NULL); 84 assert(err_is_ok(r)); 85 void *va; 86 r = vspace_map_one_frame_attr(&va, size, frame, attr, 87 NULL, NULL); 88 if (err_is_fail(r)) { 89 DEBUG_ERR(r, "vspace_map_one_frame failed"); 90 return NULL; 91 } 92 93 if (retcap != NULL) { 94 *retcap = frame; 95 } 96 97 return va; 98} 99 100void *user_alloc(size_t size, uintptr_t *paddr); 101void *user_alloc(size_t size, uintptr_t *paddr) 102{ 103 struct capref cap = NULL_CAP; 104 void * va = alloc_map_frame(VREGION_FLAGS_READ_WRITE_NOCACHE, 105 size, &cap); 106 assert(va != NULL); 107 struct frame_identity id; 108 errval_t err = frame_identify(cap, &id); 109 assert(err_is_ok(err)); 110 *paddr = id.base; 111 return va; 112} 113 114static errval_t vsic_write(struct storage_vsic *vsic, struct storage_vsa *vsa, 115 off_t offset, size_t size, void *buffer) 116{ 117 assert(vsic != NULL); 118 assert(vsa != NULL); 119 assert(buffer != NULL); 120 /* struct megaraid_vsic *mydata = vsic->data; */ 121 122 struct write16 { 123 uint8_t opcode; 124 uint8_t flags; 125 uint64_t lba; 126 uint32_t length; 127 uint8_t group; 128 uint8_t control; 129 } __attribute__ ((packed)); 130 131 assert(offset % BLOCK_SIZE == 0); 132 133 memcpy(pmem_start, buffer, size); 134 buffer = pmem_start; 135 136 size = STORAGE_VSIC_ROUND(vsic, size); 137 /* assert(size % BLOCK_SIZE == 0); */ 138 139 struct write16 write16_cmd = { 140 .opcode = 0x8a, 141 .flags = 0, 142 .lba = htonll(offset / BLOCK_SIZE), 143 .length = htonl(size / BLOCK_SIZE), 144 .group = 0, 145 .control = 0, 146 }; 147 148 struct mrsas_mpt_cmd *cmd; 149 MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc; 150 151 cmd = mrsas_get_mpt_cmd(); 152 assert(cmd != NULL); 153 154 // Need virtual data addresses 155 cmd->flags = MRSAS_DIR_OUT; 156 cmd->length = size; 157 cmd->data = buffer; 158 cmd->ccb_ptr = (void *)cmd_cnt; // Data pointer we can use 159 160 cmd_cnt++; 161 162 req_desc = mrsas_get_request_desc((cmd->index)-1); 163 assert(req_desc != NULL); 164 memset(req_desc, 0, sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION)); 165 cmd->request_desc = req_desc; 166 167 // command data block 168 memcpy(cmd->io_request->CDB.CDB32, &write16_cmd, 16); 169 170 // Build LDIO command 171 MRSAS_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request; 172 io_request->RaidContext.VirtualDiskTgtId = TARGET_DEVICE_ID; 173 io_request->RaidContext.status = 0; 174 io_request->RaidContext.exStatus = 0; 175 io_request->IoFlags = 16; // CDB length in bytes 176 io_request->RaidContext.regLockFlags = 0; 177 io_request->RaidContext.timeoutValue = 0; 178 cmd->request_desc->SCSIIO.RequestFlags = 179 (MRSAS_REQ_DESCRIPT_FLAGS_LD_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 180 if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) 181 cmd->request_desc->SCSIIO.RequestFlags = (MRSAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 182 io_request->RaidContext.Type = MPI2_TYPE_CUDA; 183 io_request->RaidContext.regLockFlags |= (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 | MR_RL_FLAGS_SEQ_NUM_ENABLE); 184 io_request->RaidContext.nseg = 0x1; 185 io_request->Function = MRSAS_MPI2_FUNCTION_LD_IO_REQUEST; 186 io_request->DevHandle = TARGET_DEVICE_ID; 187 io_request->DataLength = cmd->length; 188 189 pMpi25IeeeSgeChain64_t sgl_ptr; 190 sgl_ptr = (pMpi25IeeeSgeChain64_t)&io_request->SGL; 191 pMpi25IeeeSgeChain64_t sgl_ptr_end = sgl_ptr; 192 sgl_ptr_end += sc->max_sge_in_main_msg - 1; 193 sgl_ptr_end->Flags = 0; 194 sgl_ptr->Address = v2p(buffer, size); 195 sgl_ptr->Length = size; 196 sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST; 197 sgl_ptr++; 198 cmd->sge_count = 1; 199 io_request->RaidContext.numSGE = cmd->sge_count; 200 201 cmd->io_request->Control |= MPI2_SCSIIO_CONTROL_READ; 202 cmd->io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING; 203 cmd->io_request->SGLOffset0 = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL)/4; 204 cmd->io_request->SenseBufferLowAddress = cmd->sense_phys_addr; 205 cmd->io_request->SenseBufferLength = MRSAS_SCSI_SENSE_BUFFERSIZE; 206 207 req_desc->SCSIIO.SMID = cmd->index; 208 209 if (cmd->io_request->ChainOffset != 0 && 210 cmd->io_request->ChainOffset != 0xF) { 211 DEBUG("megasas: The chain offset value is not " 212 "correct : %x\n", cmd->io_request->ChainOffset); 213 } 214 215 DEBUG("Firing write cmd (outstanding %u)...\n", sc->fw_outstanding.val); 216 217 sc->fw_outstanding.val++; 218 mrsas_fire_cmd(req_desc->addr.u.low, req_desc->addr.u.high); 219 220 return SYS_ERR_OK; 221} 222 223static errval_t vsic_read(struct storage_vsic *vsic, struct storage_vsa *vsa, 224 off_t offset, size_t size, void *buffer) 225{ 226 assert(vsic != NULL); 227 assert(vsa != NULL); 228 assert(buffer != NULL); 229 /* struct megaraid_vsic *mydata = vsic->data; */ 230 231 struct read16 { 232 uint8_t opcode; 233 uint8_t flags; 234 uint64_t lba; 235 uint32_t length; 236 uint8_t group; 237 uint8_t control; 238 } __attribute__ ((packed)); 239 240 buffer = pmem_start; 241 assert(offset % BLOCK_SIZE == 0); 242 size = STORAGE_VSIC_ROUND(vsic, size); 243 /* assert(size % BLOCK_SIZE == 0); */ 244 245 struct read16 read16_cmd = { 246 .opcode = 0x88, 247 .flags = 0, 248 .lba = htonll(offset / BLOCK_SIZE), 249 .length = htonl(size / BLOCK_SIZE), 250 .group = 0, 251 .control = 0, 252 }; 253 254 struct mrsas_mpt_cmd *cmd; 255 MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc; 256 257 cmd = mrsas_get_mpt_cmd(); 258 assert(cmd != NULL); 259 cmd->flags = MRSAS_DIR_IN; 260 261 // Need virtual data addresses 262 cmd->length = size; 263 cmd->data = buffer; 264 cmd->ccb_ptr = NULL; // Data pointer we can use 265 266 req_desc = mrsas_get_request_desc((cmd->index)-1); 267 assert(req_desc != NULL); 268 memset(req_desc, 0, sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION)); 269 cmd->request_desc = req_desc; 270 271 // command data block 272 memcpy(cmd->io_request->CDB.CDB32, &read16_cmd, 16); 273 274 // Build LDIO command 275 MRSAS_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request; 276 io_request->RaidContext.VirtualDiskTgtId = TARGET_DEVICE_ID; 277 io_request->RaidContext.status = 0; 278 io_request->RaidContext.exStatus = 0; 279 io_request->IoFlags = 16; // CDB length in bytes 280 io_request->RaidContext.regLockFlags = 0; 281 io_request->RaidContext.timeoutValue = 0; 282 cmd->request_desc->SCSIIO.RequestFlags = 283 (MRSAS_REQ_DESCRIPT_FLAGS_LD_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 284 if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) 285 cmd->request_desc->SCSIIO.RequestFlags = (MRSAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 286 io_request->RaidContext.Type = MPI2_TYPE_CUDA; 287 io_request->RaidContext.regLockFlags |= (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 | MR_RL_FLAGS_SEQ_NUM_ENABLE); 288 io_request->RaidContext.nseg = 0x1; 289 io_request->Function = MRSAS_MPI2_FUNCTION_LD_IO_REQUEST; 290 io_request->DevHandle = TARGET_DEVICE_ID; 291 io_request->DataLength = cmd->length; 292 293 pMpi25IeeeSgeChain64_t sgl_ptr; 294 sgl_ptr = (pMpi25IeeeSgeChain64_t)&io_request->SGL; 295 pMpi25IeeeSgeChain64_t sgl_ptr_end = sgl_ptr; 296 sgl_ptr_end += sc->max_sge_in_main_msg - 1; 297 sgl_ptr_end->Flags = 0; 298 sgl_ptr->Address = v2p(buffer, size); 299 sgl_ptr->Length = size; 300 sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST; 301 sgl_ptr++; 302 cmd->sge_count = 1; 303 io_request->RaidContext.numSGE = cmd->sge_count; 304 305 cmd->io_request->Control |= MPI2_SCSIIO_CONTROL_READ; 306 cmd->io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING; 307 cmd->io_request->SGLOffset0 = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL)/4; 308 cmd->io_request->SenseBufferLowAddress = cmd->sense_phys_addr; 309 cmd->io_request->SenseBufferLength = MRSAS_SCSI_SENSE_BUFFERSIZE; 310 311 req_desc->SCSIIO.SMID = cmd->index; 312 313 if (cmd->io_request->ChainOffset != 0 && 314 cmd->io_request->ChainOffset != 0xF) { 315 DEBUG("megasas: The chain offset value is not " 316 "correct : %x\n", cmd->io_request->ChainOffset); 317 } 318 319 DEBUG("Firing read cmd...\n"); 320 321 sc->fw_outstanding.val++; 322 mrsas_fire_cmd(req_desc->addr.u.low, req_desc->addr.u.high); 323 324 return SYS_ERR_OK; 325} 326 327static errval_t vsic_flush(struct storage_vsic *vsic, struct storage_vsa *vsa) 328{ 329 assert(vsic != NULL); 330 assert(vsa != NULL); 331 /* struct megaraid_vsic *mydata = vsic->data; */ 332 333 return SYS_ERR_OK; 334} 335 336static errval_t vsic_flush2(struct storage_vsic *vsic, struct storage_vsa *vsa, 337 void *handle) 338{ 339 assert(vsic != NULL); 340 assert(vsa != NULL); 341 /* struct megaraid_vsic *mydata = vsic->data; */ 342 343 return SYS_ERR_OK; 344} 345 346static errval_t vsic_wait(struct storage_vsic *vsic) 347{ 348 assert(vsic != NULL); 349 /* struct megaraid_vsic *mydata = vsic->data; */ 350 351 poll_mode = false; 352 353 while(sc->fw_outstanding.val > 0) { 354 /* DEBUG("Outstanding cmds = %u\n", sc->fw_outstanding.val); */ 355 mrsas_complete_cmd(); 356 } 357 358 return SYS_ERR_OK; 359} 360 361static errval_t vsic_poll(struct storage_vsic *vsic, void **handle) 362{ 363 assert(vsic != NULL); 364 /* struct megaraid_vsic *mydata = vsic->data; */ 365 366 if(sc->fw_outstanding.val > 0) { 367 DEBUG("polling: Outstanding cmds = %u\n", sc->fw_outstanding.val); 368 poll_mode = true; 369 mrsas_complete_cmd(); 370 *handle = (void *)1234; 371 } else { 372 return FLOUNDER_ERR_TX_BUSY; 373 } 374 375 return SYS_ERR_OK; 376} 377 378static struct storage_vsic_ops megaraid_ops = { 379 .write = vsic_write, 380 .read = vsic_read, 381 .flush = vsic_flush, 382 .wait = vsic_wait, 383 .flush2 = vsic_flush2, 384 .poll = vsic_poll, 385}; 386 387errval_t storage_vsic_driver_init(int argc, const char **argv, 388 struct storage_vsic *vsic) 389{ 390 assert(vsic != NULL); 391 struct megaraid_vsic *mydata = malloc(sizeof(struct megaraid_vsic)); 392 assert(mydata != NULL); 393 memset(mydata, 0, sizeof(struct megaraid_vsic)); 394 395 // Init VSIC data structures 396 vsic->ops = megaraid_ops; 397 vsic->data = mydata; 398 vsic->blocksize = BLOCK_SIZE; // XXX: Determine from drive? 399 400 megaraid_driver_init(argc, argv); 401 402 pmem_start = user_alloc(BUF_SIZE, &paddr_start); 403 assert(pmem_start != NULL); 404 405 return SYS_ERR_OK; 406} 407 408errval_t storage_vsa_acquire(struct storage_vsa *vsa, const char *name, 409 size_t size) 410{ 411 // XXX: Always return empty VSA of fixed size 412 return SYS_ERR_OK; 413} 414 415errval_t storage_vsa_resize(struct storage_vsa *vsa, size_t size) 416{ 417 assert("NYI"); 418 return SYS_ERR_OK; 419} 420