SMREmulator 1.0
ShingledMagneticRecordingEmulator
|
00001 00012 #include <fcntl.h> 00013 #include <errno.h> 00014 #include <unistd.h> 00015 #include <string.h> 00016 00017 #include <ediversion.h> 00018 00019 00020 00021 /* -- Macro Definitions -- */ 00022 #define EDIVERSION 0 00023 00024 #define HEADER ediv0_header 00025 00026 #define OFF_META OFF_HEADER + sizeof(ediv0_header_t) 00027 #define OFF_DATA OFF_META + sizeof(ediv0_metadata_t) * HEADER.band_count 00028 00029 00030 /* -- Type Definitions -- */ 00031 00044 typedef struct { 00045 uint32_t blk_size; 00046 band_t band_count; 00047 rba_t band_size; 00048 } ediv0_header_t; 00049 00050 00061 typedef struct { 00062 rba_t write_ptr; 00063 } ediv0_metadata_t; 00064 00065 00066 00067 /* -- Static Variables -- */ 00068 static edi_vops_t ediv0_ops; 00069 static ediv0_header_t ediv0_header; 00070 00071 00072 00073 /* -- Function Prototypes -- */ 00074 static int is_valid_band(band_t); 00075 static int get_meta_rec(int, band_t, ediv0_metadata_t*); 00076 static int set_meta_rec(int, band_t, ediv0_metadata_t*); 00077 00078 00079 /* -- Function Implementations -- */ 00080 00089 static int ediv0_create(int fd, va_list args) { 00090 ediv0_header_t header; 00091 ediv0_metadata_t metadata; 00092 size_t size; 00093 uint32_t blk_size; 00094 band_t band_count; 00095 rba_t band_size; 00096 int i; 00097 00098 00099 /* Verify if all the required arguments are present and valid */ 00100 blk_size = va_arg(args, uint32_t); 00101 band_count = va_arg(args, band_t); 00102 band_size = va_arg(args, rba_t); 00103 dbg("Arguments received: blk_size: %d, band_count: %d, band_size: %d\n", 00104 blk_size, band_count, band_size); 00105 00106 if ((blk_size & (blk_size - 1))) /* Block size must be a power of 2 */ 00107 return -1; 00108 00109 if (band_count <= 0) /* Band count must be greater than 0 */ 00110 return -1; 00111 00112 if (band_size <= 0) /* Band size must be greater than 0 */ 00113 return -1; 00114 00115 00116 /* Write out the EDI header */ 00117 header.blk_size = blk_size; 00118 header.band_count = band_count; 00119 header.band_size = band_size; 00120 00121 size = sizeof(ediv0_header_t); 00122 if (pwrite(fd, &header, size, OFF_HEADER) != size) 00123 return -1; 00124 dbg("Header written out!\n"); 00125 00126 00127 /* Write out the metadata */ 00128 metadata.write_ptr = 0; 00129 size = sizeof(ediv0_metadata_t); 00130 00131 if (lseek(fd, 0, SEEK_END) < 0) { 00132 dbg("Unable to see to end of file!\n"); 00133 return -1; 00134 } 00135 00136 for(i=0; i<band_count; i++) { 00137 if (write(fd, &metadata, size) != size) { 00138 dbg("Metadata record %d failed to be written out!\n", i); 00139 return -1; 00140 } 00141 dbg("Wrote metadata record for band %d\n", i); 00142 } 00143 00144 return 0; 00145 } 00146 00147 00148 00157 static int ediv0_dump(int fd) { 00158 ediv0_metadata_t metadata; 00159 int i; 00160 int cols = 4; 00161 00162 00163 /* Display the EDI Version and basics */ 00164 fprintf(stdout, "EDI INFORMATION\n===============\n"); 00165 fprintf(stdout, "EDI Version: 0\n"); 00166 fprintf(stdout, "Block Size: %d bytes\n", ediv0_header.blk_size); 00167 fprintf(stdout, "No. of bands: %d\n", ediv0_header.band_count); 00168 fprintf(stdout, "Write Pointers for bands:"); 00169 00170 00171 /* Display the write pointers for each band */ 00172 for (i=0; i<ediv0_header.band_count; i++) { 00173 /* Display the row header */ 00174 if (!(i % cols)) 00175 fprintf(stdout, "\nBand %4d:", i); 00176 00177 /* Read the band meta data for the current band */ 00178 if (get_meta_rec(fd, i, &metadata) < 0) { 00179 dbg("Error reading metadata for band %d: %s\n", i, strerror(errno)); 00180 return -1; 00181 } 00182 fprintf(stdout, " %8d", metadata.write_ptr); 00183 } 00184 fprintf(stdout, "\n\n"); 00185 00186 return 0; 00187 } 00188 00189 00190 00198 static int ediv0_open(int fd) { 00199 int size; 00200 00201 00202 /* Read the header data from disk */ 00203 size = sizeof(ediv0_header_t); 00204 if (pread(fd, &ediv0_header, size, OFF_HEADER) < size) { 00205 dbg("Cannot read v0 header!\n"); 00206 errno = EFAIL; 00207 return -1; 00208 } 00209 dbg("Loaded header into memory!\n"); 00210 00211 return 0; 00212 } 00213 00214 00215 00233 static int ediv0_modesense(int fd, inq_t inq, void* data) { 00234 /* Check the operation requested */ 00235 switch(inq) { 00236 case INQ_BLKSIZE: /* Block Size */ 00237 *((uint32_t *)data) = ediv0_header.blk_size; 00238 dbg("Returning block size as %d.\n", *((uint32_t *)data)); 00239 return 0; 00240 00241 case INQ_BNDCOUNT: /* Band Count */ 00242 *((band_t *)data) = ediv0_header.band_count; 00243 dbg("Returning band count as %d.\n", *((band_t *)data)); 00244 return 0; 00245 00246 default: /* Unsupported Operation */ 00247 errno = EUNSUPPORTED; 00248 return -1; 00249 } 00250 } 00251 00252 00253 00268 static int ediv0_managebands(int fd, svc_act_t action, band_t* band, rba_t* rba, 00269 int len) { 00270 ediv0_metadata_t metadata; 00271 int i, rba_zero = 0, retval = 0; 00272 00273 00274 /* Check the action requested */ 00275 switch (action) { 00276 case SVC_GETPTR: /* Get Write Pointer for band */ 00277 /* Read the metadata for the band */ 00278 if (get_meta_rec(fd, *band, &metadata) < 0) 00279 return -1; 00280 00281 /* Return the Write Pointer */ 00282 *rba = metadata.write_ptr; 00283 dbg("Write pointer for band %d returned as %d\n", *band, *rba); 00284 return 0; 00285 00286 00287 case SVC_SETPTR: /* Set Write Pointer for band */ 00288 /* Verify that the rba is valid */ 00289 if ((*rba < 0) || (*rba >= ediv0_header.band_size)) { 00290 dbg("Invalid RBA (%d) specified!", *rba); 00291 errno = ERBA; 00292 return -1; 00293 } 00294 00295 /* Read the metadata for the band */ 00296 if (get_meta_rec(fd, *band, &metadata) < 0) 00297 return -1; 00298 00299 /* Update the Write Pointer */ 00300 metadata.write_ptr = *rba; 00301 00302 /* Write the metadata for the band */ 00303 if (set_meta_rec(fd, *band, &metadata) < 0) 00304 return -1; 00305 00306 dbg("Write pointer for band %d set as %d\n", *band, *rba); 00307 return 0; 00308 00309 00310 case SVC_GETMULTIPLE: /* Get Write Pointer for bands */ 00311 /* Loop over all the bands passed */ 00312 for(i=0; i<len; i++) { 00313 /* Retrieve the Write Pointer for the current band */ 00314 if (ediv0_managebands(fd, SVC_GETPTR, &band[i], &rba[i], 0) < 0) { 00315 rba[i] = -1; 00316 retval = -1; 00317 dbg("Unable to retrieve Write Pointer for band %d\n", band[i]); 00318 } 00319 dbg("Write pointer for band %d returned as %d\n", band[i], rba[i]); 00320 } 00321 00322 return retval; 00323 00324 00325 case SVC_RESETALL: /* Set Write Pointers for all bands */ 00326 /* Loop over all the bands */ 00327 for(i=0; i<ediv0_header.band_count; i++) { 00328 /* Retrieve the Write Pointer for the current band */ 00329 if (ediv0_managebands(fd, SVC_SETPTR, &band[i], &rba_zero, 0) < 0) { 00330 rba[i] = -1; 00331 retval = -1; 00332 dbg("Unable to retrieve Write Pointer for band %d\n", band[i]); 00333 } 00334 dbg("Write pointer for band %d set as %d\n", band[i], rba_zero); 00335 } 00336 00337 return 0; 00338 00339 00340 case SVC_GETBANDCONFIG: /* Returns the size of a band */ 00341 /* Validate the band */ 00342 if (!is_valid_band(*band)) { 00343 dbg("Band %d is not valid!\n", *band); 00344 errno = EBAND; 00345 return -1; 00346 } 00347 00348 /* Return the size of the band */ 00349 *rba = ediv0_header.band_size; 00350 dbg("Band size returned as %d.\n", *rba); 00351 return 0; 00352 00353 00354 default: /* Unsupported Operation */ 00355 dbg("Unsupported operation %x requested for band %d\n", action, *rba); 00356 errno = EUNSUPPORTED; 00357 return -1; 00358 } 00359 } 00360 00361 00362 00382 static int ediv0_read(int fd, band_t band, rba_t rba, char* buf, rba_t count) { 00383 ediv0_metadata_t metadata; 00384 off_t offset; 00385 size_t size = count * HEADER.blk_size; 00386 00387 00388 dbg("Reading data in band %d from block %d to %d\n", band, rba, rba+count); 00389 00390 /* Read the metadata for the band */ 00391 if (get_meta_rec(fd, band, &metadata) < 0) { 00392 return -1; 00393 } 00394 00395 /* Verify that the rba is valid */ 00396 if ((rba < 0) || (rba >= HEADER.band_size)) { 00397 errno = ERBA; 00398 return -1; 00399 } 00400 00401 if (rba >= metadata.write_ptr) { 00402 errno = EOOB; 00403 return -1; 00404 } 00405 00406 /* Check the validity of the read length */ 00407 if (rba + count > metadata.write_ptr) { 00408 errno = EOOB; 00409 return -1; 00410 } 00411 00412 00413 /* Read the data into the buffer */ 00414 offset = OFF_DATA + ((off_t)band * HEADER.band_size * HEADER.blk_size); 00415 dbg("Data for band begins at %lld bytes. ", (long long)offset); 00416 offset += ((off_t)rba * HEADER.blk_size); 00417 dbg("Data for block begins at %lld bytes. ", (long long)offset); 00418 if (pread(fd, buf, size, offset) != size) 00419 return -1; 00420 00421 return 0; 00422 } 00423 00424 00425 00447 static int ediv0_write(int fd, band_t band, rba_t rba, char* buf, rba_t count) { 00448 ediv0_metadata_t metadata; 00449 off_t offset; 00450 off_t size = count * HEADER.blk_size; 00451 00452 00453 dbg("Writing data to band %d from block %d to %d\n", band, rba, rba+count); 00454 00455 /* Check the validity of the write length */ 00456 if ((rba + count > rba) && (rba + count > ediv0_header.band_size)) { 00457 dbg("rba+count (%d) exceed band size (%d)!\n", 00458 rba+count, ediv0_header.band_size); 00459 errno = EOOB; 00460 return -1; 00461 } 00462 00463 /* Read the metadata for the band */ 00464 if (get_meta_rec(fd, band, &metadata) < 0) { 00465 dbg("Cannot fetch metadata record for band %d\n", band); 00466 return -1; 00467 } 00468 00469 /* Verify that the rba is valid */ 00470 if (rba != metadata.write_ptr) { 00471 dbg("rba passed (%d) does not match write pointer (%d)\n", 00472 rba, metadata.write_ptr); 00473 errno = ERBA; 00474 return -1; 00475 } 00476 00477 /* Write the data from the buffer */ 00478 offset = OFF_DATA + ((off_t)band * HEADER.band_size * HEADER.blk_size); 00479 dbg("Data for band begins at %lld bytes. ", (long long)offset); 00480 offset += ((off_t)rba * HEADER.blk_size); 00481 dbg("Data for block begins at %lld bytes. ", (long long)offset); 00482 if (pwrite(fd, buf, size, offset) != size) { 00483 dbg("pwrite() failed to writedata: %s\n", strerror(errno)); 00484 return -1; 00485 } 00486 00487 /* Update the write pointer for the band */ 00488 metadata.write_ptr += count; 00489 if (set_meta_rec(fd, band, &metadata) < 0) { 00490 dbg("Failed to update write pointer (%d)\n", metadata.write_ptr); 00491 errno = EUPDATE; 00492 return -1; 00493 } 00494 00495 return 0; 00496 } 00497 00498 00499 00505 edi_vops_t* ediv0_init() { 00506 /* Initialize all data structures */ 00507 memset(&ediv0_header, 0, sizeof(ediv0_header_t)); 00508 00509 00510 /* Initialize the Call-back Functions object and return it to the caller */ 00511 ediv0_ops.create = ediv0_create; 00512 ediv0_ops.dump = ediv0_dump; 00513 ediv0_ops.open = ediv0_open; 00514 ediv0_ops.modesense = ediv0_modesense; 00515 ediv0_ops.managebands = ediv0_managebands; 00516 ediv0_ops.read = ediv0_read; 00517 ediv0_ops.write = ediv0_write; 00518 00519 return &ediv0_ops; 00520 } 00521 00522 00523 00531 static int is_valid_band(band_t band) { 00532 /* Ensure that the band number is less than the band count for the EDI */ 00533 return ((band >= 0) && (band < ediv0_header.band_count)); 00534 } 00535 00536 00537 00554 static int get_meta_rec(int fd, band_t band, ediv0_metadata_t* metadata) { 00555 int len; 00556 size_t offset; 00557 00558 00559 /* Validate the band */ 00560 if (!is_valid_band(band)) { 00561 errno = EBAND; 00562 return -1; 00563 } 00564 00565 /* Read the metadata record */ 00566 offset = OFF_META + sizeof(ediv0_metadata_t) * band; 00567 len = pread(fd, metadata, sizeof(ediv0_metadata_t), offset); 00568 if (len < sizeof(ediv0_metadata_t)) 00569 return -1; 00570 00571 return 0; 00572 } 00573 00574 00575 00592 static int set_meta_rec(int fd, band_t band, ediv0_metadata_t* metadata) { 00593 int len; 00594 size_t offset; 00595 00596 00597 /* Validate the band */ 00598 if (!is_valid_band(band)) { 00599 errno = EBAND; 00600 return -1; 00601 } 00602 00603 /* Read the metadata record */ 00604 offset = OFF_META + sizeof(ediv0_metadata_t) * band; 00605 len = pwrite(fd, metadata, sizeof(ediv0_metadata_t), offset); 00606 if (len < sizeof(ediv0_metadata_t)) 00607 return -1; 00608 00609 return 0; 00610 }