Print this page
NEX-3705 Need to update libses with LID/USN code from sesctld
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/scsi/libscsi/common/scsi_engine.c
+++ new/usr/src/lib/scsi/libscsi/common/scsi_engine.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 25 */
25 26
26 27 #include <sys/types.h>
27 28 #include <sys/isa_defs.h>
28 29 #include <sys/systeminfo.h>
29 30 #include <sys/scsi/generic/commands.h>
30 31 #include <sys/scsi/impl/commands.h>
31 32 #include <sys/scsi/impl/uscsi.h>
32 33
33 34 #include <stdio.h>
34 35 #include <stdlib.h>
35 36 #include <stddef.h>
36 37 #include <string.h>
37 38 #include <dlfcn.h>
38 39 #include <limits.h>
39 40
40 41 #include <scsi/libscsi.h>
41 42 #include "libscsi_impl.h"
42 43
43 44 static const libscsi_engine_t *
44 45 get_engine(libscsi_hdl_t *hp, const char *name)
45 46 {
46 47 libscsi_engine_impl_t *eip;
47 48 const libscsi_engine_t *ep;
48 49 const char *engine_path, *p, *q;
49 50 char engine_dir[MAXPATHLEN];
50 51 char engine_lib[MAXPATHLEN];
51 52 char init_name[MAXPATHLEN];
52 53 void *dl_hdl;
53 54 libscsi_engine_init_f init;
54 55 boolean_t found_lib = B_FALSE, found_init = B_FALSE;
55 56 int dirs_tried = 0;
56 57 char isa[257];
57 58
58 59 for (eip = hp->lsh_engines; eip != NULL; eip = eip->lsei_next) {
59 60 if (strcmp(eip->lsei_engine->lse_name, name) == 0)
60 61 return (eip->lsei_engine);
61 62 }
62 63
63 64 if ((engine_path = getenv("LIBSCSI_ENGINE_PATH")) == NULL)
64 65 engine_path = LIBSCSI_DEFAULT_ENGINE_PATH;
65 66
66 67 #if defined(_LP64)
67 68 if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
68 69 isa[0] = '\0';
69 70 #else
70 71 isa[0] = '\0';
71 72 #endif
72 73
73 74 for (p = engine_path; p != NULL; p = q) {
74 75 if ((q = strchr(p, ':')) != NULL) {
75 76 ptrdiff_t len = q - p;
76 77 (void) strncpy(engine_dir, p, len);
77 78 engine_dir[len] = '\0';
78 79 while (*q == ':')
79 80 ++q;
80 81 if (*q == '\0')
81 82 q = NULL;
82 83 if (len == 0)
83 84 continue;
84 85 } else {
85 86 (void) strcpy(engine_dir, p);
86 87 }
87 88 if (engine_dir[0] != '/')
88 89 continue;
89 90
90 91 ++dirs_tried;
91 92
92 93 (void) snprintf(engine_lib, MAXPATHLEN, "%s/%s/%s%s",
93 94 engine_dir, isa, name, LIBSCSI_ENGINE_EXT);
94 95
95 96 dl_hdl = dlopen(engine_lib,
96 97 RTLD_LOCAL | RTLD_LAZY | RTLD_PARENT);
97 98 if (dl_hdl == NULL) {
98 99 if (!found_lib)
99 100 (void) libscsi_error(hp, ESCSI_NOENGINE,
100 101 "unable to dlopen %s: %s", engine_lib,
101 102 dlerror());
102 103 continue;
103 104 }
104 105 found_lib = B_TRUE;
105 106 (void) snprintf(init_name, MAXPATHLEN, "libscsi_%s_init", name);
106 107 init = (libscsi_engine_init_f)dlsym(dl_hdl, init_name);
107 108 if (init == NULL) {
108 109 if (!found_init)
109 110 (void) libscsi_error(hp, ESCSI_NOENGINE,
110 111 "failed to find %s in %s: %s", init_name,
111 112 engine_lib, dlerror());
112 113 (void) dlclose(dl_hdl);
113 114 continue;
114 115 }
115 116 if ((ep = init(hp)) == NULL) {
116 117 (void) dlclose(dl_hdl);
117 118 /*
118 119 * libscsi errno set by init.
119 120 */
120 121 return (NULL);
121 122 }
122 123 if (ep->lse_libversion != hp->lsh_version) {
123 124 (void) dlclose(dl_hdl);
124 125 (void) libscsi_error(hp, ESCSI_ENGINE_VER, "engine "
125 126 "%s version %u does not match library version %u",
126 127 engine_lib, ep->lse_libversion, hp->lsh_version);
127 128 return (NULL);
128 129 }
129 130
130 131 eip = libscsi_zalloc(hp, sizeof (libscsi_engine_impl_t));
131 132 if (eip == NULL) {
132 133 (void) dlclose(dl_hdl);
133 134 return (NULL);
134 135 }
135 136 eip->lsei_engine = ep;
136 137 eip->lsei_dl_hdl = dl_hdl;
137 138 eip->lsei_next = hp->lsh_engines;
138 139 hp->lsh_engines = eip;
139 140
140 141 return (ep);
141 142 }
142 143
143 144 if (dirs_tried == 0)
144 145 (void) libscsi_error(hp, ESCSI_ENGINE_BADPATH, "no valid "
145 146 "directories found in engine path %s", engine_path);
146 147
147 148 return (NULL);
148 149 }
149 150
150 151 static void
151 152 scsi_parse_mtbf(const char *envvar, uint_t *intp)
152 153 {
153 154 const char *strval;
154 155 int intval;
155 156
156 157 if ((strval = getenv(envvar)) != NULL &&
157 158 (intval = atoi(strval)) > 0) {
158 159 srand48(gethrtime());
159 160 *intp = intval;
160 161 }
161 162 }
162 163
163 164 libscsi_target_t *
164 165 libscsi_open(libscsi_hdl_t *hp, const char *engine, const void *target)
165 166 {
166 167 const libscsi_engine_t *ep;
167 168 libscsi_target_t *tp;
168 169 void *private;
169 170
170 171 if (engine == NULL) {
171 172 if ((engine = getenv("LIBSCSI_DEFAULT_ENGINE")) == NULL)
172 173 engine = LIBSCSI_DEFAULT_ENGINE;
173 174 }
174 175
175 176 if ((ep = get_engine(hp, engine)) == NULL)
176 177 return (NULL);
177 178
178 179 if ((tp = libscsi_zalloc(hp, sizeof (libscsi_target_t))) == NULL)
179 180 return (NULL);
180 181
181 182 if ((private = ep->lse_ops->lseo_open(hp, target)) == NULL) {
182 183 libscsi_free(hp, tp);
183 184 return (NULL);
184 185 }
185 186
186 187 scsi_parse_mtbf("LIBSCSI_MTBF_CDB", &tp->lst_mtbf_cdb);
187 188 scsi_parse_mtbf("LIBSCSI_MTBF_READ", &tp->lst_mtbf_read);
188 189 scsi_parse_mtbf("LIBSCSI_MTBF_WRITE", &tp->lst_mtbf_write);
189 190
190 191 tp->lst_hdl = hp;
|
↓ open down ↓ |
157 lines elided |
↑ open up ↑ |
191 192 tp->lst_engine = ep;
192 193 tp->lst_priv = private;
193 194
194 195 ++hp->lsh_targets;
195 196
196 197 if (libscsi_get_inquiry(hp, tp) != 0) {
197 198 libscsi_close(hp, tp);
198 199 return (NULL);
199 200 }
200 201
202 + if (libscsi_get_inquiry_dev_id(hp, tp) != 0)
203 + tp->lst_lid = NULL;
204 + if (libscsi_get_inquiry_usn(hp, tp) != 0)
205 + tp->lst_usn = NULL;
206 +
201 207 return (tp);
202 208 }
203 209
204 210 libscsi_hdl_t *
205 211 libscsi_get_handle(libscsi_target_t *tp)
206 212 {
207 213 return (tp->lst_hdl);
208 214 }
209 215
210 216 void
211 217 libscsi_close(libscsi_hdl_t *hp, libscsi_target_t *tp)
212 218 {
213 219 tp->lst_engine->lse_ops->lseo_close(hp, tp->lst_priv);
214 220 libscsi_free(hp, tp->lst_vendor);
215 221 libscsi_free(hp, tp->lst_product);
216 222 libscsi_free(hp, tp->lst_revision);
223 + if (tp->lst_lid != NULL)
224 + libscsi_free(hp, tp->lst_lid);
225 + if (tp->lst_usn != NULL)
226 + libscsi_free(hp, tp->lst_usn);
217 227 libscsi_free(hp, tp);
218 228 --hp->lsh_targets;
219 229 }
220 230
221 231 sam4_status_t
222 232 libscsi_action_get_status(const libscsi_action_t *ap)
223 233 {
224 234 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
225 235
226 236 return (aip->lsai_status);
227 237 }
228 238
229 239 /*
230 240 * Set the timeout in seconds for this action. If no timeout is specified
231 241 * or if the timeout is set to 0, an implementation-specific timeout will be
232 242 * used (which may vary based on the target, command or other variables).
233 243 * Not all engines support all timeout values. Setting the timeout to a value
234 244 * not supported by the engine will cause engine-defined behavior when the
235 245 * action is executed.
236 246 */
237 247 void
238 248 libscsi_action_set_timeout(libscsi_action_t *ap, uint32_t timeout)
239 249 {
240 250 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
241 251
242 252 aip->lsai_timeout = timeout;
243 253 }
244 254
245 255 /*
246 256 * Obtain the timeout setting for this action.
247 257 */
248 258 uint32_t
249 259 libscsi_action_get_timeout(const libscsi_action_t *ap)
250 260 {
251 261 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
252 262
253 263 return (aip->lsai_timeout);
254 264 }
255 265
256 266 /*
257 267 * Returns the flags associated with this action. Never fails.
258 268 */
259 269 uint_t
260 270 libscsi_action_get_flags(const libscsi_action_t *ap)
261 271 {
262 272 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
263 273
264 274 return (aip->lsai_flags);
265 275 }
266 276
267 277 /*
268 278 * Returns the address of the action's CDB. The CDB buffer is guaranteed to
269 279 * be large enough to hold the complete CDB for the command specified when the
270 280 * action was allocated. Therefore, changing the command/opcode portion of
271 281 * the CDB has undefined effects. The remainder of the CDB may be modified.
272 282 */
273 283 uint8_t *
274 284 libscsi_action_get_cdb(const libscsi_action_t *ap)
275 285 {
276 286 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
277 287
278 288 return (aip->lsai_cdb);
279 289 }
280 290
281 291 /*
282 292 * Places the address of the action buffer in the location pointed to by bp,
283 293 * if bp is not NULL. If ap is not NULL, it will contain the allocated size
284 294 * of the buffer itself. If vp is not NULL, it will contain the number of
285 295 * bytes of valid data currently stored in the buffer.
286 296 *
287 297 * If the action has LIBSCSI_AF_WRITE set and it has not yet been executed
288 298 * successfully, the entire buffer is assumed to contain valid data.
289 299 *
290 300 * If the action has LIBSCSI_AF_READ set and it has not yet been executed
291 301 * successfully, the amount of valid data is 0.
292 302 *
293 303 * If both LIBSCSI_AF_READ and LIBSCSI_AF_WRITE are clear, this function
294 304 * fails with ESCSI_BADFLAGS to indicate that the action flags are
295 305 * incompatible with the action data buffer.
296 306 */
297 307 int
298 308 libscsi_action_get_buffer(const libscsi_action_t *ap, uint8_t **bp,
299 309 size_t *sp, size_t *vp)
300 310 {
301 311 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
302 312
303 313 if ((aip->lsai_flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE)) == 0)
304 314 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
305 315 "data buffer not supported for actions with both "
306 316 "LIBSCSI_AF_READ and LIBSCSI_AF_WRITE clear"));
307 317
308 318 if ((aip->lsai_flags & LIBSCSI_AF_WRITE) &&
309 319 aip->lsai_status == LIBSCSI_STATUS_INVALID) {
310 320 if (bp != NULL)
311 321 *bp = aip->lsai_data;
312 322 if (sp != NULL)
313 323 *sp = aip->lsai_data_alloc;
314 324 if (vp != NULL)
315 325 *vp = aip->lsai_data_alloc;
316 326
317 327 return (0);
318 328 }
319 329
320 330 if ((aip->lsai_flags & LIBSCSI_AF_READ) &&
321 331 aip->lsai_status != LIBSCSI_STATUS_INVALID) {
322 332 if (bp != NULL)
323 333 *bp = aip->lsai_data;
324 334 if (sp != NULL)
325 335 *sp = aip->lsai_data_alloc;
326 336 if (vp != NULL)
327 337 *vp = aip->lsai_data_len;
328 338
329 339 return (0);
330 340 }
331 341
332 342 if (aip->lsai_flags & LIBSCSI_AF_WRITE) {
333 343 if (bp != NULL)
334 344 *bp = NULL;
335 345 if (sp != NULL)
336 346 *sp = NULL;
337 347 if (vp != NULL)
338 348 *vp = 0;
339 349 } else {
340 350 if (bp != NULL)
341 351 *bp = aip->lsai_data;
342 352 if (sp != NULL)
343 353 *sp = aip->lsai_data_alloc;
344 354 if (vp != NULL)
345 355 *vp = 0;
346 356 }
347 357
348 358 return (0);
349 359 }
350 360
351 361 /*
352 362 * Obtain a pointer to the sense buffer for this action, if any, along with
353 363 * the size of the sense buffer and the amount of valid data it contains.
354 364 */
355 365 int
356 366 libscsi_action_get_sense(const libscsi_action_t *ap, uint8_t **bp,
357 367 size_t *sp, size_t *vp)
358 368 {
359 369 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
360 370
361 371 if (!(aip->lsai_flags & LIBSCSI_AF_RQSENSE))
362 372 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
363 373 "sense data unavailable: LIBSCSI_AF_RQSENSE is clear"));
364 374
365 375 if (vp != NULL) {
366 376 if (aip->lsai_status == LIBSCSI_STATUS_INVALID)
367 377 *vp = 0;
368 378 else
369 379 *vp = aip->lsai_sense_len;
370 380 }
371 381
372 382 if (bp != NULL) {
373 383 ASSERT(aip->lsai_sense_data != NULL);
374 384 *bp = aip->lsai_sense_data;
375 385 }
376 386
377 387 if (sp != NULL)
378 388 *sp = UINT8_MAX;
379 389
380 390 return (0);
381 391 }
382 392
383 393 /*
384 394 * Set the SCSI status of the action.
385 395 *
386 396 * Engines only.
387 397 */
388 398 void
389 399 libscsi_action_set_status(libscsi_action_t *ap, sam4_status_t status)
390 400 {
391 401 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
392 402
393 403 ASSERT(aip->lsai_status == LIBSCSI_STATUS_INVALID);
394 404
395 405 aip->lsai_status = status;
396 406 }
397 407
398 408 /*
399 409 * Set the length of valid data returned by a READ action. If the action is
400 410 * not a READ action, or the length exceeds the size of the buffer, an error
401 411 * results.
402 412 *
403 413 * Engines only.
404 414 */
405 415 int
406 416 libscsi_action_set_datalen(libscsi_action_t *ap, size_t len)
407 417 {
408 418 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
409 419
410 420 if ((aip->lsai_flags & LIBSCSI_AF_READ) == 0)
411 421 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
412 422 "data cannot be returned for actions with LIBSCSI_AF_READ "
413 423 "clear"));
414 424 if (len > aip->lsai_data_alloc)
415 425 return (libscsi_error(aip->lsai_hdl, ESCSI_BADLENGTH,
416 426 "data length %lu exceeds allocated buffer capacity %lu",
417 427 (ulong_t)len, (ulong_t)aip->lsai_data_alloc));
418 428
419 429 ASSERT(aip->lsai_data_len == 0);
420 430 aip->lsai_data_len = len;
421 431
422 432 return (0);
423 433 }
424 434
425 435 /*
426 436 * Set the length of the valid sense data returned following the command, if
427 437 * LIBSCSI_AF_RQSENSE is set for this action. Otherwise, fail.
428 438 *
429 439 * Engines only.
430 440 */
431 441 int
432 442 libscsi_action_set_senselen(libscsi_action_t *ap, size_t len)
433 443 {
434 444 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
435 445
436 446 if (!(aip->lsai_flags & LIBSCSI_AF_RQSENSE))
437 447 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
438 448 "sense data not supported: LIBSCSI_AF_RQSENSE is clear"));
439 449
440 450 if (len > UINT8_MAX)
441 451 return (libscsi_error(aip->lsai_hdl, ESCSI_BADLENGTH,
442 452 "sense length %lu exceeds allocated buffer capacity %lu",
443 453 (ulong_t)len, (ulong_t)UINT8_MAX));
444 454
445 455 ASSERT(aip->lsai_sense_len == 0);
446 456 aip->lsai_sense_len = len;
447 457
448 458 return (0);
449 459 }
450 460
451 461 /*
452 462 * Allocate an action object. The object will contain a CDB area sufficiently
453 463 * large to hold a CDB for the given command, and the CDB's opcode will be
454 464 * filled in. A pointer to this CDB, the contents of which may be modified by
455 465 * the caller, may be obtained by a subsequent call to libscsi_action_cdb().
456 466 *
457 467 * If flags includes LIBSCSI_AF_READ or LIBSCSI_AF_WRITE, buflen must be
458 468 * greater than zero. Otherwise, buflen must be 0 and buf must be NULL.
459 469 * If buflen is nonzero but buf is NULL, a suitably-sized buffer will be
460 470 * allocated; otherwise, the specified buffer will be used. In either case,
461 471 * a pointer to the buffer may be obtained via a subsequent call to
462 472 * libscsi_action_buffer().
463 473 *
464 474 * If flags includes LIBSCSI_AF_RQSENSE, a REQUEST SENSE command will be
465 475 * issued immediately following the termination of the specified command.
466 476 * A buffer will be allocated to receive this sense data. Following successful
467 477 * execution of the action, a pointer to this buffer and the length of
468 478 * valid sense data may be obtained by a call to libscsi_action_sense().
469 479 * If cmd is SPC3_CMD_REQUEST_SENSE, this flag must be clear.
470 480 */
471 481 libscsi_action_t *
472 482 libscsi_action_alloc(libscsi_hdl_t *hp, spc3_cmd_t cmd, uint_t flags,
473 483 void *buf, size_t buflen)
474 484 {
475 485 libscsi_action_impl_t *aip;
476 486 size_t cdbsz, sz;
477 487 ptrdiff_t off;
478 488
479 489 /*
480 490 * If there's no buffer, it makes no sense to try to read or write
481 491 * data. Likewise, if we're neither reading nor writing data, we
482 492 * should not have a buffer. Both of these are programmer error.
483 493 */
484 494 if (buflen == 0 && (flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE))) {
485 495 (void) libscsi_error(hp, ESCSI_NEEDBUF, "a buffer is "
486 496 "required when reading or writing");
487 497 return (NULL);
488 498 }
489 499 if (buflen > 0 && !(flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE))) {
490 500 (void) libscsi_error(hp, ESCSI_BADFLAGS, "one of "
491 501 "LIBSCSI_AF_READ and LIBSCSI_AF_WRITE must be specified "
492 502 "in order to use a buffer");
493 503 return (NULL);
494 504 }
495 505 if (cmd == SPC3_CMD_REQUEST_SENSE && (flags & LIBSCSI_AF_RQSENSE)) {
496 506 (void) libscsi_error(hp, ESCSI_BADFLAGS, "request sense "
497 507 "flag not allowed for request sense command");
498 508 return (NULL);
499 509 }
500 510
501 511 if ((sz = cdbsz = libscsi_cmd_cdblen(hp, cmd)) == 0)
502 512 return (NULL);
503 513
504 514 /*
505 515 * If the caller has asked for a buffer but has not provided one, we
506 516 * will allocate it in our internal buffer along with the CDB and
507 517 * request sense space (if requested).
508 518 */
509 519 if (buf == NULL)
510 520 sz += buflen;
511 521
512 522 if (flags & LIBSCSI_AF_RQSENSE)
513 523 sz += UINT8_MAX;
514 524
515 525 sz += offsetof(libscsi_action_impl_t, lsai_buf[0]);
516 526
517 527 if ((aip = libscsi_zalloc(hp, sz)) == NULL)
518 528 return (NULL);
519 529
520 530 aip->lsai_hdl = hp;
521 531 aip->lsai_flags = flags;
522 532
523 533 off = 0;
524 534
525 535 aip->lsai_cdb = aip->lsai_buf + off;
526 536 aip->lsai_cdb_len = cdbsz;
527 537 off += cdbsz;
528 538 aip->lsai_cdb[0] = (uint8_t)cmd;
529 539
530 540 if (buflen > 0) {
531 541 if (buf != NULL) {
532 542 aip->lsai_data = buf;
533 543 } else {
534 544 aip->lsai_data = aip->lsai_buf + off;
535 545 off += buflen;
536 546 }
537 547 aip->lsai_data_alloc = buflen;
538 548 if (flags & LIBSCSI_AF_WRITE)
539 549 aip->lsai_data_len = buflen;
540 550 }
541 551
542 552 if (flags & LIBSCSI_AF_RQSENSE) {
543 553 aip->lsai_sense_data = aip->lsai_buf + off;
544 554 off += UINT8_MAX;
545 555 }
546 556
547 557 aip->lsai_status = LIBSCSI_STATUS_INVALID;
548 558
549 559 return ((libscsi_action_t *)aip);
550 560 }
551 561
552 562 void
553 563 libscsi_action_free(libscsi_action_t *ap)
554 564 {
555 565 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
556 566
557 567 libscsi_free(aip->lsai_hdl, aip);
558 568 }
559 569
560 570 /*
561 571 * For testing purposes, we allow data to be corrupted via an environment
562 572 * variable setting. This helps ensure that higher level software can cope with
563 573 * arbitrarily broken targets. The mtbf value represents the number of bytes we
564 574 * will see, on average, in between each failure. Therefore, for each N bytes,
565 575 * we would expect to see (N / mtbf) bytes of corruption.
566 576 */
567 577 static void
568 578 scsi_inject_errors(void *data, size_t len, uint_t mtbf)
569 579 {
570 580 char *buf = data;
571 581 double prob;
572 582 size_t index;
573 583
574 584 if (len == 0)
575 585 return;
576 586
577 587 prob = (double)len / mtbf;
578 588
579 589 while (prob > 1) {
580 590 index = lrand48() % len;
581 591 buf[index] = (lrand48() % 256);
582 592 prob -= 1;
583 593 }
584 594
585 595 if (drand48() <= prob) {
586 596 index = lrand48() % len;
587 597 buf[index] = (lrand48() % 256);
588 598 }
589 599 }
590 600
591 601 int
592 602 libscsi_exec(libscsi_action_t *ap, libscsi_target_t *tp)
593 603 {
594 604 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
595 605 libscsi_hdl_t *hp = aip->lsai_hdl;
596 606 int ret;
597 607
598 608 if (tp->lst_mtbf_write != 0 &&
599 609 (aip->lsai_flags & LIBSCSI_AF_WRITE)) {
600 610 scsi_inject_errors(aip->lsai_data, aip->lsai_data_len,
601 611 tp->lst_mtbf_write);
602 612 }
603 613
604 614 if (tp->lst_mtbf_cdb != 0) {
605 615 scsi_inject_errors(aip->lsai_cdb, aip->lsai_cdb_len,
606 616 tp->lst_mtbf_cdb);
607 617 }
608 618
609 619 ret = tp->lst_engine->lse_ops->lseo_exec(hp, tp->lst_priv, ap);
610 620
611 621 if (ret == 0 && tp->lst_mtbf_read != 0 &&
612 622 (aip->lsai_flags & LIBSCSI_AF_READ)) {
613 623 scsi_inject_errors(aip->lsai_data, aip->lsai_data_len,
614 624 tp->lst_mtbf_read);
615 625 }
616 626
617 627 return (ret);
618 628 }
|
↓ open down ↓ |
392 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX