3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/atomic.h>
26 #include <sys/conf.h>
27 #include <sys/byteorder.h>
28 #include <sys/scsi/scsi_types.h>
29 #include <sys/scsi/generic/persist.h>
30
31 #include <sys/lpif.h>
32 #include <sys/stmf.h>
33 #include <sys/stmf_ioctl.h>
34 #include <sys/portif.h>
35 #include <sys/stmf_sbd_ioctl.h>
36
37 #include "stmf_sbd.h"
38 #include "sbd_impl.h"
39
40 #define MAX_PGR_PARAM_LIST_LENGTH (256 * 1024)
41
42 int sbd_pgr_reservation_conflict(scsi_task_t *);
43 void sbd_pgr_reset(sbd_lu_t *);
44 void sbd_pgr_initialize_it(scsi_task_t *, sbd_it_data_t *);
45 void sbd_handle_pgr_in_cmd(scsi_task_t *, stmf_data_buf_t *);
46 void sbd_handle_pgr_out_cmd(scsi_task_t *, stmf_data_buf_t *);
47 void sbd_handle_pgr_out_data(scsi_task_t *, stmf_data_buf_t *);
48 void sbd_pgr_keylist_dealloc(sbd_lu_t *);
49 char *sbd_get_devid_string(sbd_lu_t *);
50
51 sbd_status_t sbd_pgr_meta_init(sbd_lu_t *);
52 sbd_status_t sbd_pgr_meta_load(sbd_lu_t *);
53 sbd_status_t sbd_pgr_meta_write(sbd_lu_t *);
54 static void sbd_swap_pgr_info(sbd_pgr_info_t *);
55 static void sbd_swap_pgrkey_info(sbd_pgr_key_info_t *);
56 static void sbd_pgr_key_free(sbd_pgr_key_t *);
57 static void sbd_pgr_remove_key(sbd_lu_t *, sbd_pgr_key_t *);
58 static uint32_t sbd_pgr_remove_keys(sbd_lu_t *, sbd_it_data_t *,
59 sbd_pgr_key_t *, uint64_t, boolean_t);
60 static boolean_t sbd_pgr_key_compare(sbd_pgr_key_t *, scsi_devid_desc_t *,
61 stmf_remote_port_t *);
62 static sbd_pgr_key_t *sbd_pgr_key_alloc(scsi_devid_desc_t *,
65 static void sbd_pgr_set_pgr_check_flag(sbd_lu_t *, boolean_t);
66 static void sbd_pgr_set_ua_conditions(sbd_lu_t *, sbd_it_data_t *, uint8_t);
67 static void sbd_pgr_in_read_keys(scsi_task_t *, stmf_data_buf_t *);
68 static void sbd_pgr_in_report_capabilities(scsi_task_t *, stmf_data_buf_t *);
69 static void sbd_pgr_in_read_reservation(scsi_task_t *, stmf_data_buf_t *);
70 static void sbd_pgr_in_read_full_status(scsi_task_t *, stmf_data_buf_t *);
71 static void sbd_pgr_out_register(scsi_task_t *, stmf_data_buf_t *);
72 static void sbd_pgr_out_reserve(scsi_task_t *);
73 static void sbd_pgr_out_release(scsi_task_t *);
74 static void sbd_pgr_out_clear(scsi_task_t *);
75 static void sbd_pgr_out_preempt(scsi_task_t *, stmf_data_buf_t *);
76 static void sbd_pgr_out_register_and_move(scsi_task_t *, stmf_data_buf_t *);
77
78 static sbd_pgr_key_t *sbd_pgr_do_register(sbd_lu_t *, sbd_it_data_t *,
79 scsi_devid_desc_t *, stmf_remote_port_t *, uint8_t, uint64_t);
80 static void sbd_pgr_do_unregister(sbd_lu_t *, sbd_it_data_t *, sbd_pgr_key_t *);
81 static void sbd_pgr_do_release(sbd_lu_t *, sbd_it_data_t *, uint8_t);
82 static void sbd_pgr_do_reserve(sbd_pgr_t *, sbd_pgr_key_t *, sbd_it_data_t *it,
83 stmf_scsi_session_t *, scsi_cdb_prout_t *);
84
85 extern sbd_status_t sbd_write_meta_section(sbd_lu_t *, sm_section_hdr_t *);
86 extern sbd_status_t sbd_read_meta_section(sbd_lu_t *, sm_section_hdr_t **,
87 uint16_t);
88 extern void sbd_swap_section_hdr(sm_section_hdr_t *);
89 extern void sbd_handle_short_write_transfers(scsi_task_t *task,
90 stmf_data_buf_t *dbuf, uint32_t cdb_xfer_size);
91 extern void sbd_handle_short_read_transfers(scsi_task_t *task,
92 stmf_data_buf_t *dbuf, uint8_t *p, uint32_t cdb_xfer_size,
93 uint32_t cmd_xfer_size);
94 extern uint16_t stmf_scsilib_get_lport_rtid(scsi_devid_desc_t *devid);
95 extern scsi_devid_desc_t *stmf_scsilib_get_devid_desc(uint16_t rtpid);
96 extern char sbd_ctoi(char c);
97
98 /*
99 *
100 *
101 * +-----------+
102 * | |sl_it_list
103 * | |---------------------------------------+
104 * | | |
278
279 sbd_status_t
280 sbd_pgr_meta_init(sbd_lu_t *slu)
281 {
282 sbd_pgr_info_t *spi = NULL;
283 uint32_t sz;
284 sbd_status_t ret;
285
286 sz = sizeof (sbd_pgr_info_t);
287 spi = (sbd_pgr_info_t *)kmem_zalloc(sz, KM_SLEEP);
288 spi->pgr_data_order = SMS_DATA_ORDER;
289 spi->pgr_sms_header.sms_size = sz;
290 spi->pgr_sms_header.sms_id = SMS_ID_PGR_INFO;
291 spi->pgr_sms_header.sms_data_order = SMS_DATA_ORDER;
292
293 ret = sbd_write_meta_section(slu, (sm_section_hdr_t *)spi);
294 kmem_free(spi, sz);
295 return (ret);
296 }
297
298 sbd_status_t
299 sbd_pgr_meta_load(sbd_lu_t *slu)
300 {
301 sbd_pgr_t *pgr = slu->sl_pgr;
302 sbd_pgr_info_t *spi = NULL;
303 sbd_pgr_key_t *key, *last_key = NULL;
304 sbd_pgr_key_info_t *spi_key;
305 sbd_status_t ret = SBD_SUCCESS;
306 scsi_devid_desc_t *lpt;
307 uint8_t *ptr, *keyoffset, *endoffset;
308 uint32_t i, sz;
309
310 ret = sbd_read_meta_section(slu, (sm_section_hdr_t **)&spi,
311 SMS_ID_PGR_INFO);
312 if (ret != SBD_SUCCESS) {
313 /* No PGR section found, means volume made before PGR support */
314 if (ret == SBD_NOT_FOUND) {
315 /* So just create a default PGR section */
316 ret = sbd_pgr_meta_init(slu);
317 }
318 return (ret);
319 }
320
321 if (spi->pgr_data_order != SMS_DATA_ORDER) {
322 sbd_swap_pgr_info(spi);
323 }
324
325 pgr->pgr_flags = spi->pgr_flags;
326 if (pgr->pgr_flags & SBD_PGR_APTPL) {
327 pgr->pgr_rsv_type = spi->pgr_rsv_type;
328 pgr->pgr_rsv_scope = spi->pgr_rsv_scope;
329 } else {
330 PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
331 }
332
333 PGR_CLEAR_FLAG(slu->sl_pgr->pgr_flags, SBD_PGR_ALL_KEYS_HAS_IT);
334
335 endoffset = (uint8_t *)spi;
336 endoffset += spi->pgr_sms_header.sms_size;
337 keyoffset = (uint8_t *)(spi + 1);
338 for (i = 1; i <= spi->pgr_numkeys; i++) {
339
340 spi_key = (sbd_pgr_key_info_t *)keyoffset;
341 if (spi->pgr_data_order != SMS_DATA_ORDER) {
342 sbd_swap_pgrkey_info(spi_key);
343 }
344
345 /* Calculate the size and next offset */
346 sz = ALIGNED_TO_8BYTE_BOUNDARY(sizeof (sbd_pgr_key_info_t) - 1 +
396 key->pgr_key_flags = spi_key->pgr_key_flags;
397 key->pgr_key_prev = last_key;
398
399 if (last_key) {
400 last_key->pgr_key_next = key;
401 } else {
402 pgr->pgr_keylist = key;
403 }
404 last_key = key;
405
406 if ((pgr->pgr_flags & SBD_PGR_RSVD_ONE) &&
407 (i == spi->pgr_rsvholder_indx)) {
408 pgr->pgr_rsvholder = key;
409 }
410 }
411
412 kmem_free(spi, spi->pgr_sms_header.sms_size);
413 return (ret);
414
415 sbd_pgr_meta_load_failed:
416 {
417 char *lun_name = sbd_get_devid_string(slu);
418 sbd_pgr_keylist_dealloc(slu);
419 kmem_free(spi, spi->pgr_sms_header.sms_size);
420 cmn_err(CE_WARN, "sbd_pgr_meta_load: Failed to load PGR meta data "
421 "for lun %s.", lun_name);
422 kmem_free(lun_name, strlen(lun_name) + 1);
423 return (ret);
424 }
425 }
426
427 sbd_status_t
428 sbd_pgr_meta_write(sbd_lu_t *slu)
429 {
430 sbd_pgr_key_t *key;
431 sbd_pgr_info_t *spi;
432 sbd_pgr_key_info_t *spi_key;
433 sbd_pgr_t *pgr = slu->sl_pgr;
434 sbd_status_t ret = SBD_SUCCESS;
435 uint32_t sz, totalsz;
436
437 /* Calculate total pgr meta section size needed */
438 sz = sizeof (sbd_pgr_info_t);
439 if (pgr->pgr_flags & SBD_PGR_APTPL) {
440 key = pgr->pgr_keylist;
441 while (key != NULL) {
442 sz = ALIGNED_TO_8BYTE_BOUNDARY(sz +
443 sizeof (sbd_pgr_key_info_t) - 1 +
444 key->pgr_key_lpt_len + key->pgr_key_rpt_len);
445 key = key->pgr_key_next;
446 }
447 }
448 totalsz = sz;
449
450 spi = (sbd_pgr_info_t *)kmem_zalloc(totalsz, KM_SLEEP);
451 spi->pgr_flags = pgr->pgr_flags;
452 spi->pgr_rsv_type = pgr->pgr_rsv_type;
453 spi->pgr_rsv_scope = pgr->pgr_rsv_scope;
454 spi->pgr_data_order = SMS_DATA_ORDER;
455 spi->pgr_numkeys = 0;
456
457 spi->pgr_sms_header.sms_size = totalsz;
458 spi->pgr_sms_header.sms_id = SMS_ID_PGR_INFO;
459 spi->pgr_sms_header.sms_data_order = SMS_DATA_ORDER;
460
461 if (pgr->pgr_flags & SBD_PGR_APTPL) {
462 uint8_t *ptr;
463 key = pgr->pgr_keylist;
464 sz = sizeof (sbd_pgr_info_t);
465 while (key != NULL) {
466 spi_key = (sbd_pgr_key_info_t *)((uint8_t *)spi + sz);
467 spi_key->pgr_key = key->pgr_key;
468 spi_key->pgr_key_flags = key->pgr_key_flags;
469 spi_key->pgr_key_lpt_len = key->pgr_key_lpt_len;
470 spi_key->pgr_key_rpt_len = key->pgr_key_rpt_len;
471 ptr = spi_key->pgr_key_it;
472 bcopy(key->pgr_key_lpt_id, ptr, key->pgr_key_lpt_len);
473 ptr += key->pgr_key_lpt_len;
474 bcopy(key->pgr_key_rpt_id, ptr, key->pgr_key_rpt_len);
475
476 spi->pgr_numkeys++;
477 if (key == pgr->pgr_rsvholder) {
478 spi->pgr_rsvholder_indx = spi->pgr_numkeys;
479 }
480
481 sz = ALIGNED_TO_8BYTE_BOUNDARY(sz +
482 sizeof (sbd_pgr_key_info_t) - 1 +
483 key->pgr_key_lpt_len + key->pgr_key_rpt_len);
484 key = key->pgr_key_next;
485 }
486 }
487
488 ret = sbd_write_meta_section(slu, (sm_section_hdr_t *)spi);
489 kmem_free(spi, totalsz);
490 if (ret != SBD_SUCCESS) {
491 sbd_pgr_key_t *tmp_list;
492 tmp_list = pgr->pgr_keylist;
493 pgr->pgr_keylist = NULL;
494 if (sbd_pgr_meta_load(slu) != SBD_SUCCESS) {
495 char *lun_name = sbd_get_devid_string(slu);
496 cmn_err(CE_WARN, "sbd_pgr_meta_write: Failed to revert "
497 "back to existing PGR state after meta write "
498 "failure, may cause PGR inconsistancy for lun %s.",
499 lun_name);
500 kmem_free(lun_name, strlen(lun_name) + 1);
501 pgr->pgr_keylist = tmp_list;
502 } else {
503 key = pgr->pgr_keylist;
504 pgr->pgr_keylist = tmp_list;
505 sbd_pgr_set_pgr_check_flag(slu, B_TRUE);
506 sbd_pgr_keylist_dealloc(slu);
507 pgr->pgr_keylist = key;
508 }
561 it->pgr_key_ptr = NULL;
562 }
563 mutex_exit(&slu->sl_lock);
564
565 while (pgr->pgr_keylist != NULL) {
566 key = pgr->pgr_keylist;
567 pgr->pgr_keylist = key->pgr_key_next;
568 sbd_pgr_key_free(key);
569 }
570 }
571
572 /*
573 * Reset and clear the keys, Can be used in the case of Lun Reset
574 */
575 void
576 sbd_pgr_reset(sbd_lu_t *slu)
577 {
578 sbd_pgr_t *pgr = slu->sl_pgr;
579
580 rw_enter(&pgr->pgr_lock, RW_WRITER);
581 if (!(pgr->pgr_flags & SBD_PGR_APTPL)) {
582 sbd_pgr_keylist_dealloc(slu);
583 pgr->pgr_PRgeneration = 0;
584 pgr->pgr_rsvholder = NULL;
585 pgr->pgr_rsv_type = 0;
586 pgr->pgr_flags = 0;
587 }
588 rw_exit(&pgr->pgr_lock);
589 }
590
591 static void
592 sbd_pgr_remove_key(sbd_lu_t *slu, sbd_pgr_key_t *key)
593 {
594 sbd_pgr_t *pgr = slu->sl_pgr;
595 sbd_it_data_t *it;
596
597 ASSERT(key);
598
599 mutex_enter(&slu->sl_lock);
600 if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
601 for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
795 }
796 }
797
798 } else {
799 key->pgr_key_it = it;
800 }
801
802 mutex_enter(&slu->sl_lock);
803 it->pgr_key_ptr = key;
804 mutex_exit(&slu->sl_lock);
805 rw_exit(&pgr->pgr_lock);
806 return;
807 }
808 rw_exit(&pgr->pgr_lock);
809 }
810
811 /*
812 * Check for any PGR Reservation conflict. return 0 if access allowed
813 */
814 int
815 sbd_pgr_reservation_conflict(scsi_task_t *task)
816 {
817 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
818 sbd_pgr_t *pgr = slu->sl_pgr;
819 sbd_it_data_t *it = (sbd_it_data_t *)task->task_lu_itl_handle;
820
821 /* If Registered */
822 if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS && it->pgr_key_ptr)
823 return (0);
824
825 /* If you are registered */
826 if (pgr->pgr_flags & SBD_PGR_RSVD_ONE) {
827 rw_enter(&pgr->pgr_lock, RW_READER);
828
829 /*
830 * Note: it->pgr_key_ptr is protected by sl_lock. Also,
831 * it is expected to change its value only with pgr_lock
832 * held. Hence we are safe to read its value without
833 * grabbing sl_lock. But make sure that the value used is
834 * not from registers by using "volatile" keyword.
835 * Since this funtion is in performance path, we may want
836 * to avoid grabbing sl_lock.
837 */
1369 sizeof (stmf_remote_port_t) * max_tpdnum);
1370 stmf_scsilib_send_status(task, STATUS_CHECK,
1371 STMF_SAA_INVALID_FIELD_IN_CDB);
1372 return;
1373 }
1374
1375 for (i = 0; i < tpdnum; i++) {
1376 (void) sbd_pgr_do_register(slu, NULL, lpt, &rpt_ary[i],
1377 keyflag, svc_key);
1378 }
1379 kmem_free(rpt_ary, sizeof (stmf_remote_port_t) * max_tpdnum);
1380 }
1381
1382 rport.rport_tptid = ses->ss_rport->rport_tptid;
1383 rport.rport_tptid_sz = ses->ss_rport->rport_tptid_sz;
1384
1385 (void) sbd_pgr_do_register(slu, it, lpt, &rport, keyflag, svc_key);
1386
1387 sbd_pgr_reg_done:
1388
1389 if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) {
1390 if (plist->aptpl)
1391 PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1392 else
1393 PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1394
1395 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1396 stmf_scsilib_send_status(task, STATUS_CHECK,
1397 STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1398 return;
1399 }
1400 }
1401
1402 pgr->pgr_PRgeneration++;
1403 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1404 }
1405
1406 static sbd_pgr_key_t *
1407 sbd_pgr_do_register(sbd_lu_t *slu, sbd_it_data_t *it, scsi_devid_desc_t *lpt,
1408 stmf_remote_port_t *rpt, uint8_t keyflag, uint64_t svc_key)
1409 {
1474 return;
1475 }
1476
1477 if (SBD_PGR_RSVD(pgr)) {
1478 if (PGR_RESERVATION_HOLDER(pgr, key, it)) {
1479 if (pgr->pgr_rsv_type != pr_out->type ||
1480 pgr->pgr_rsv_scope != pr_out->scope) {
1481 stmf_scsilib_send_status(task,
1482 STATUS_RESERVATION_CONFLICT, 0);
1483 return;
1484 }
1485 } else {
1486 stmf_scsilib_send_status(task,
1487 STATUS_RESERVATION_CONFLICT, 0);
1488 return;
1489
1490 }
1491 /* In case there is no reservation exist */
1492 } else {
1493 sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
1494 if (pgr->pgr_flags & SBD_PGR_APTPL) {
1495 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1496 stmf_scsilib_send_status(task, STATUS_CHECK,
1497 STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1498 return;
1499 }
1500 }
1501 }
1502
1503 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1504 }
1505
1506 static void
1507 sbd_pgr_do_reserve(sbd_pgr_t *pgr, sbd_pgr_key_t *key, sbd_it_data_t *it,
1508 stmf_scsi_session_t *ses, scsi_cdb_prout_t *pr_out)
1509 {
1510 scsi_devid_desc_t *lpt;
1511 uint16_t lpt_len;
1512
1513 pgr->pgr_rsv_type = pr_out->type;
1514 pgr->pgr_rsv_scope = pr_out->scope;
1531 bcopy(lpt, key->pgr_key_lpt_id, lpt_len);
1532 key->pgr_key_it = it;
1533 }
1534
1535 PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_RSVD_ONE);
1536 pgr->pgr_rsvholder = key;
1537 }
1538 }
1539
1540 static void
1541 sbd_pgr_out_release(scsi_task_t *task)
1542 {
1543 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
1544 scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb;
1545 sbd_it_data_t *it = task->task_lu_itl_handle;
1546 sbd_pgr_t *pgr = slu->sl_pgr;
1547 sbd_pgr_key_t *key = it->pgr_key_ptr;
1548
1549 ASSERT(key);
1550
1551 if (SBD_PGR_RSVD(pgr)) {
1552 if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS ||
1553 pgr->pgr_rsvholder == key) {
1554 if (pgr->pgr_rsv_type != pr_out->type ||
1555 pgr->pgr_rsv_scope != pr_out->scope) {
1556 stmf_scsilib_send_status(task, STATUS_CHECK,
1557 STMF_SAA_INVALID_RELEASE_OF_PR);
1558 return;
1559 }
1560 sbd_pgr_do_release(slu, it,
1561 SBD_UA_RESERVATIONS_RELEASED);
1562 }
1563 }
1564 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1565 }
1566
1567 static void
1568 sbd_pgr_do_release(sbd_lu_t *slu, sbd_it_data_t *it, uint8_t ua_condition)
1569 {
1570
1571 sbd_pgr_t *pgr = slu->sl_pgr;
1572
1573 /* Reset pgr_flags */
1574 PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
1575 pgr->pgr_rsvholder = NULL;
1576
1577 /* set unit attention condition if necessary */
1578 if (pgr->pgr_rsv_type != PGR_TYPE_WR_EX &&
1579 pgr->pgr_rsv_type != PGR_TYPE_EX_AC) {
1580 sbd_pgr_set_ua_conditions(slu, it, ua_condition);
1581 }
1582 pgr->pgr_rsv_type = 0;
1583 }
1585 static void
1586 sbd_pgr_out_clear(scsi_task_t *task)
1587 {
1588 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
1589 sbd_it_data_t *it = task->task_lu_itl_handle;
1590 sbd_pgr_t *pgr = slu->sl_pgr;
1591
1592 ASSERT(it->pgr_key_ptr);
1593
1594 PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
1595 pgr->pgr_rsvholder = NULL;
1596 pgr->pgr_rsv_type = 0;
1597 mutex_enter(&slu->sl_lock);
1598 /* Remove all pointers from IT to pgr keys */
1599 for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
1600 it->pgr_key_ptr = NULL;
1601 }
1602 mutex_exit(&slu->sl_lock);
1603 sbd_pgr_keylist_dealloc(slu);
1604 sbd_pgr_set_ua_conditions(slu, it, SBD_UA_RESERVATIONS_PREEMPTED);
1605 if (pgr->pgr_flags & SBD_PGR_APTPL) {
1606 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1607 stmf_scsilib_send_status(task, STATUS_CHECK,
1608 STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1609 return;
1610 }
1611 }
1612 pgr->pgr_PRgeneration++;
1613 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1614 }
1615
1616 static void
1617 sbd_pgr_out_preempt(scsi_task_t *task, stmf_data_buf_t *dbuf)
1618 {
1619 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
1620 stmf_scsi_session_t *ses = task->task_session;
1621 scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb;
1622 sbd_it_data_t *it = task->task_lu_itl_handle;
1623 sbd_pgr_t *pgr = slu->sl_pgr;
1624 sbd_pgr_key_t *key = it->pgr_key_ptr;
1625 scsi_prout_plist_t *plist;
1700 if (!(PGR_VALID_SCOPE(pr_out->scope) &&
1701 PGR_VALID_TYPE(pr_out->type))) {
1702 stmf_scsilib_send_status(task, STATUS_CHECK,
1703 STMF_SAA_INVALID_FIELD_IN_CDB);
1704 return;
1705 }
1706 sbd_pgr_do_release(slu, it,
1707 SBD_UA_REGISTRATIONS_PREEMPTED);
1708 (void) sbd_pgr_remove_keys(slu, it, key, 0, B_FALSE);
1709 sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
1710 } else {
1711 if (sbd_pgr_remove_keys(slu, it, key, svc_key, B_TRUE)
1712 == 0) {
1713 stmf_scsilib_send_status(task,
1714 STATUS_RESERVATION_CONFLICT, 0);
1715 return;
1716 }
1717 }
1718 }
1719
1720 if (pgr->pgr_flags & SBD_PGR_APTPL) {
1721 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1722 stmf_scsilib_send_status(task, STATUS_CHECK,
1723 STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1724 return;
1725 }
1726 }
1727
1728 pgr->pgr_PRgeneration++;
1729
1730 if (pr_out->action == PR_OUT_PREEMPT_ABORT) {
1731 stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED,
1732 (void *)slu->sl_lu);
1733 }
1734 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1735 }
1736
1737 static void
1738 sbd_pgr_out_register_and_move(scsi_task_t *task, stmf_data_buf_t *dbuf)
1739 {
1740 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
1814 kmem_zalloc(lpt_len, KM_SLEEP);
1815 bcopy(lpt, newkey->pgr_key_lpt_id, lpt_len);
1816 }
1817 /* No IT nexus information, hence set PGR_CHEK flag */
1818 sbd_pgr_set_pgr_check_flag(slu, B_TRUE);
1819 } else {
1820 newkey = sbd_pgr_do_register(slu, NULL, lpt, &rport,
1821 SBD_PGR_KEY_TPT_ID_FLAG, svc_key);
1822 }
1823
1824 kmem_free(lpt, sizeof (scsi_devid_desc_t) + lpt->ident_length);
1825
1826 /* Now reserve the key corresponding to the specified IT nexus */
1827 pgr->pgr_rsvholder = newkey;
1828
1829 if (plist->unreg) {
1830 sbd_pgr_do_unregister(slu, it, key);
1831 }
1832
1833
1834 /* Write to disk if currenty aptpl is set or given task is setting it */
1835 if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) {
1836 if (plist->aptpl)
1837 PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1838 else
1839 PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1840
1841 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1842 stmf_scsilib_send_status(task, STATUS_CHECK,
1843 STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1844 return;
1845 }
1846 }
1847
1848 pgr->pgr_PRgeneration++;
1849 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1850 }
1851
1852 void
1853 sbd_pgr_remove_it_handle(sbd_lu_t *sl, sbd_it_data_t *my_it) {
1854 sbd_it_data_t *it;
1855
|
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23 *
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 #include <sys/atomic.h>
28 #include <sys/conf.h>
29 #include <sys/byteorder.h>
30 #include <sys/scsi/scsi_types.h>
31 #include <sys/scsi/generic/persist.h>
32
33 #include <sys/lpif.h>
34 #include <sys/stmf.h>
35 #include <sys/stmf_ioctl.h>
36 #include <sys/portif.h>
37 #include <sys/stmf_sbd_ioctl.h>
38
39 #include "stmf_sbd.h"
40 #include "sbd_impl.h"
41
42 #define MAX_PGR_PARAM_LIST_LENGTH (256 * 1024)
43
44 int sbd_pgr_reservation_conflict(scsi_task_t *, struct sbd_lu *sl);
45 void sbd_pgr_reset(sbd_lu_t *);
46 void sbd_pgr_initialize_it(scsi_task_t *, sbd_it_data_t *);
47 void sbd_handle_pgr_in_cmd(scsi_task_t *, stmf_data_buf_t *);
48 void sbd_handle_pgr_out_cmd(scsi_task_t *, stmf_data_buf_t *);
49 void sbd_handle_pgr_out_data(scsi_task_t *, stmf_data_buf_t *);
50 void sbd_pgr_keylist_dealloc(sbd_lu_t *);
51 char *sbd_get_devid_string(sbd_lu_t *);
52
53 sbd_status_t sbd_pgr_meta_init(sbd_lu_t *);
54 sbd_status_t sbd_pgr_meta_load(sbd_lu_t *);
55 sbd_status_t sbd_pgr_meta_write(sbd_lu_t *);
56 static void sbd_swap_pgr_info(sbd_pgr_info_t *);
57 static void sbd_swap_pgrkey_info(sbd_pgr_key_info_t *);
58 static void sbd_pgr_key_free(sbd_pgr_key_t *);
59 static void sbd_pgr_remove_key(sbd_lu_t *, sbd_pgr_key_t *);
60 static uint32_t sbd_pgr_remove_keys(sbd_lu_t *, sbd_it_data_t *,
61 sbd_pgr_key_t *, uint64_t, boolean_t);
62 static boolean_t sbd_pgr_key_compare(sbd_pgr_key_t *, scsi_devid_desc_t *,
63 stmf_remote_port_t *);
64 static sbd_pgr_key_t *sbd_pgr_key_alloc(scsi_devid_desc_t *,
67 static void sbd_pgr_set_pgr_check_flag(sbd_lu_t *, boolean_t);
68 static void sbd_pgr_set_ua_conditions(sbd_lu_t *, sbd_it_data_t *, uint8_t);
69 static void sbd_pgr_in_read_keys(scsi_task_t *, stmf_data_buf_t *);
70 static void sbd_pgr_in_report_capabilities(scsi_task_t *, stmf_data_buf_t *);
71 static void sbd_pgr_in_read_reservation(scsi_task_t *, stmf_data_buf_t *);
72 static void sbd_pgr_in_read_full_status(scsi_task_t *, stmf_data_buf_t *);
73 static void sbd_pgr_out_register(scsi_task_t *, stmf_data_buf_t *);
74 static void sbd_pgr_out_reserve(scsi_task_t *);
75 static void sbd_pgr_out_release(scsi_task_t *);
76 static void sbd_pgr_out_clear(scsi_task_t *);
77 static void sbd_pgr_out_preempt(scsi_task_t *, stmf_data_buf_t *);
78 static void sbd_pgr_out_register_and_move(scsi_task_t *, stmf_data_buf_t *);
79
80 static sbd_pgr_key_t *sbd_pgr_do_register(sbd_lu_t *, sbd_it_data_t *,
81 scsi_devid_desc_t *, stmf_remote_port_t *, uint8_t, uint64_t);
82 static void sbd_pgr_do_unregister(sbd_lu_t *, sbd_it_data_t *, sbd_pgr_key_t *);
83 static void sbd_pgr_do_release(sbd_lu_t *, sbd_it_data_t *, uint8_t);
84 static void sbd_pgr_do_reserve(sbd_pgr_t *, sbd_pgr_key_t *, sbd_it_data_t *it,
85 stmf_scsi_session_t *, scsi_cdb_prout_t *);
86
87 static boolean_t sbd_pgr_should_save(sbd_lu_t *);
88 extern sbd_status_t sbd_write_meta_section(sbd_lu_t *, sm_section_hdr_t *);
89 extern sbd_status_t sbd_read_meta_section(sbd_lu_t *, sm_section_hdr_t **,
90 uint16_t);
91 extern void sbd_swap_section_hdr(sm_section_hdr_t *);
92 extern void sbd_handle_short_write_transfers(scsi_task_t *task,
93 stmf_data_buf_t *dbuf, uint32_t cdb_xfer_size);
94 extern void sbd_handle_short_read_transfers(scsi_task_t *task,
95 stmf_data_buf_t *dbuf, uint8_t *p, uint32_t cdb_xfer_size,
96 uint32_t cmd_xfer_size);
97 extern uint16_t stmf_scsilib_get_lport_rtid(scsi_devid_desc_t *devid);
98 extern scsi_devid_desc_t *stmf_scsilib_get_devid_desc(uint16_t rtpid);
99 extern char sbd_ctoi(char c);
100
101 /*
102 *
103 *
104 * +-----------+
105 * | |sl_it_list
106 * | |---------------------------------------+
107 * | | |
281
282 sbd_status_t
283 sbd_pgr_meta_init(sbd_lu_t *slu)
284 {
285 sbd_pgr_info_t *spi = NULL;
286 uint32_t sz;
287 sbd_status_t ret;
288
289 sz = sizeof (sbd_pgr_info_t);
290 spi = (sbd_pgr_info_t *)kmem_zalloc(sz, KM_SLEEP);
291 spi->pgr_data_order = SMS_DATA_ORDER;
292 spi->pgr_sms_header.sms_size = sz;
293 spi->pgr_sms_header.sms_id = SMS_ID_PGR_INFO;
294 spi->pgr_sms_header.sms_data_order = SMS_DATA_ORDER;
295
296 ret = sbd_write_meta_section(slu, (sm_section_hdr_t *)spi);
297 kmem_free(spi, sz);
298 return (ret);
299 }
300
301 /*
302 * Evaluate common cases where a PERSISTENT RESERVE OUT CDB handler should call
303 * sbd_pgr_meta_write().
304 */
305 static boolean_t
306 sbd_pgr_should_save(sbd_lu_t *slu)
307 {
308 sbd_pgr_t *pgr = slu->sl_pgr;
309
310 if (stmf_is_pgr_aptpl_always() == B_TRUE ||
311 (pgr->pgr_flags & (SBD_PGR_APTPL)))
312 return (B_TRUE);
313 else
314 return (B_FALSE);
315 }
316
317 sbd_status_t
318 sbd_pgr_meta_load(sbd_lu_t *slu)
319 {
320 sbd_pgr_t *pgr = slu->sl_pgr;
321 sbd_pgr_info_t *spi = NULL;
322 sbd_pgr_key_t *key, *last_key = NULL;
323 sbd_pgr_key_info_t *spi_key;
324 sbd_status_t ret = SBD_SUCCESS;
325 scsi_devid_desc_t *lpt;
326 uint8_t *ptr, *keyoffset, *endoffset;
327 uint32_t i, sz;
328
329 ret = sbd_read_meta_section(slu, (sm_section_hdr_t **)&spi,
330 SMS_ID_PGR_INFO);
331 if (ret != SBD_SUCCESS) {
332 /* No PGR section found, means volume made before PGR support */
333 if (ret == SBD_NOT_FOUND) {
334 /* So just create a default PGR section */
335 ret = sbd_pgr_meta_init(slu);
336 }
337 return (ret);
338 }
339
340 if (spi->pgr_data_order != SMS_DATA_ORDER) {
341 sbd_swap_pgr_info(spi);
342 }
343
344 pgr->pgr_flags = spi->pgr_flags;
345 /*
346 * We reload APTPL reservations when:
347 * 1. Global override is enabled
348 * 2. APTPL was explicitly asserted in the PERSISTENT RESERVE OUT CDB
349 */
350 if (stmf_is_pgr_aptpl_always() || (pgr->pgr_flags & SBD_PGR_APTPL)) {
351 pgr->pgr_rsv_type = spi->pgr_rsv_type;
352 pgr->pgr_rsv_scope = spi->pgr_rsv_scope;
353 } else {
354 PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
355 }
356
357 PGR_CLEAR_FLAG(slu->sl_pgr->pgr_flags, SBD_PGR_ALL_KEYS_HAS_IT);
358
359 endoffset = (uint8_t *)spi;
360 endoffset += spi->pgr_sms_header.sms_size;
361 keyoffset = (uint8_t *)(spi + 1);
362 for (i = 1; i <= spi->pgr_numkeys; i++) {
363
364 spi_key = (sbd_pgr_key_info_t *)keyoffset;
365 if (spi->pgr_data_order != SMS_DATA_ORDER) {
366 sbd_swap_pgrkey_info(spi_key);
367 }
368
369 /* Calculate the size and next offset */
370 sz = ALIGNED_TO_8BYTE_BOUNDARY(sizeof (sbd_pgr_key_info_t) - 1 +
420 key->pgr_key_flags = spi_key->pgr_key_flags;
421 key->pgr_key_prev = last_key;
422
423 if (last_key) {
424 last_key->pgr_key_next = key;
425 } else {
426 pgr->pgr_keylist = key;
427 }
428 last_key = key;
429
430 if ((pgr->pgr_flags & SBD_PGR_RSVD_ONE) &&
431 (i == spi->pgr_rsvholder_indx)) {
432 pgr->pgr_rsvholder = key;
433 }
434 }
435
436 kmem_free(spi, spi->pgr_sms_header.sms_size);
437 return (ret);
438
439 sbd_pgr_meta_load_failed:
440 /* CSTYLED */
441 {
442 char *lun_name = sbd_get_devid_string(slu);
443 sbd_pgr_keylist_dealloc(slu);
444 kmem_free(spi, spi->pgr_sms_header.sms_size);
445 cmn_err(CE_WARN, "sbd_pgr_meta_load: Failed to load PGR meta data "
446 "for lun %s.", lun_name);
447 kmem_free(lun_name, strlen(lun_name) + 1);
448 return (ret);
449 }
450 }
451
452 sbd_status_t
453 sbd_pgr_meta_write(sbd_lu_t *slu)
454 {
455 sbd_pgr_key_t *key;
456 sbd_pgr_info_t *spi;
457 sbd_pgr_key_info_t *spi_key;
458 sbd_pgr_t *pgr = slu->sl_pgr;
459 sbd_status_t ret = SBD_SUCCESS;
460 uint32_t sz, totalsz;
461
462 /* Calculate total pgr meta section size needed */
463 sz = sizeof (sbd_pgr_info_t);
464 if ((pgr->pgr_flags & SBD_PGR_APTPL) || stmf_is_pgr_aptpl_always()) {
465 key = pgr->pgr_keylist;
466 while (key != NULL) {
467 sz = ALIGNED_TO_8BYTE_BOUNDARY(sz +
468 sizeof (sbd_pgr_key_info_t) - 1 +
469 key->pgr_key_lpt_len + key->pgr_key_rpt_len);
470 key = key->pgr_key_next;
471 }
472 }
473 totalsz = sz;
474
475 spi = (sbd_pgr_info_t *)kmem_zalloc(totalsz, KM_SLEEP);
476 spi->pgr_flags = pgr->pgr_flags;
477 spi->pgr_rsv_type = pgr->pgr_rsv_type;
478 spi->pgr_rsv_scope = pgr->pgr_rsv_scope;
479 spi->pgr_data_order = SMS_DATA_ORDER;
480 spi->pgr_numkeys = 0;
481
482 spi->pgr_sms_header.sms_size = totalsz;
483 spi->pgr_sms_header.sms_id = SMS_ID_PGR_INFO;
484 spi->pgr_sms_header.sms_data_order = SMS_DATA_ORDER;
485
486 if ((pgr->pgr_flags & SBD_PGR_APTPL) || stmf_is_pgr_aptpl_always()) {
487 uint8_t *ptr;
488 key = pgr->pgr_keylist;
489 sz = sizeof (sbd_pgr_info_t);
490 while (key != NULL) {
491 spi_key = (sbd_pgr_key_info_t *)((uint8_t *)spi + sz);
492 spi_key->pgr_key = key->pgr_key;
493 spi_key->pgr_key_flags = key->pgr_key_flags;
494 spi_key->pgr_key_lpt_len = key->pgr_key_lpt_len;
495 spi_key->pgr_key_rpt_len = key->pgr_key_rpt_len;
496 ptr = spi_key->pgr_key_it;
497 bcopy(key->pgr_key_lpt_id, ptr, key->pgr_key_lpt_len);
498 ptr += key->pgr_key_lpt_len;
499 bcopy(key->pgr_key_rpt_id, ptr, key->pgr_key_rpt_len);
500
501 spi->pgr_numkeys++;
502 if (key == pgr->pgr_rsvholder) {
503 spi->pgr_rsvholder_indx = spi->pgr_numkeys;
504 }
505
506 sz = ALIGNED_TO_8BYTE_BOUNDARY(sz +
507 sizeof (sbd_pgr_key_info_t) - 1 +
508 key->pgr_key_lpt_len + key->pgr_key_rpt_len);
509 key = key->pgr_key_next;
510 }
511 }
512 rw_downgrade(&pgr->pgr_lock);
513 ret = sbd_write_meta_section(slu, (sm_section_hdr_t *)spi);
514 if (!rw_tryupgrade(&pgr->pgr_lock)) {
515 rw_exit(&pgr->pgr_lock);
516 rw_enter(&pgr->pgr_lock, RW_WRITER);
517 }
518 kmem_free(spi, totalsz);
519 if (ret != SBD_SUCCESS) {
520 sbd_pgr_key_t *tmp_list;
521 tmp_list = pgr->pgr_keylist;
522 pgr->pgr_keylist = NULL;
523 if (sbd_pgr_meta_load(slu) != SBD_SUCCESS) {
524 char *lun_name = sbd_get_devid_string(slu);
525 cmn_err(CE_WARN, "sbd_pgr_meta_write: Failed to revert "
526 "back to existing PGR state after meta write "
527 "failure, may cause PGR inconsistancy for lun %s.",
528 lun_name);
529 kmem_free(lun_name, strlen(lun_name) + 1);
530 pgr->pgr_keylist = tmp_list;
531 } else {
532 key = pgr->pgr_keylist;
533 pgr->pgr_keylist = tmp_list;
534 sbd_pgr_set_pgr_check_flag(slu, B_TRUE);
535 sbd_pgr_keylist_dealloc(slu);
536 pgr->pgr_keylist = key;
537 }
590 it->pgr_key_ptr = NULL;
591 }
592 mutex_exit(&slu->sl_lock);
593
594 while (pgr->pgr_keylist != NULL) {
595 key = pgr->pgr_keylist;
596 pgr->pgr_keylist = key->pgr_key_next;
597 sbd_pgr_key_free(key);
598 }
599 }
600
601 /*
602 * Reset and clear the keys, Can be used in the case of Lun Reset
603 */
604 void
605 sbd_pgr_reset(sbd_lu_t *slu)
606 {
607 sbd_pgr_t *pgr = slu->sl_pgr;
608
609 rw_enter(&pgr->pgr_lock, RW_WRITER);
610 if (!(pgr->pgr_flags & SBD_PGR_APTPL) &&
611 stmf_is_pgr_aptpl_always() == B_FALSE) {
612 sbd_pgr_keylist_dealloc(slu);
613 pgr->pgr_PRgeneration = 0;
614 pgr->pgr_rsvholder = NULL;
615 pgr->pgr_rsv_type = 0;
616 pgr->pgr_flags = 0;
617 }
618 rw_exit(&pgr->pgr_lock);
619 }
620
621 static void
622 sbd_pgr_remove_key(sbd_lu_t *slu, sbd_pgr_key_t *key)
623 {
624 sbd_pgr_t *pgr = slu->sl_pgr;
625 sbd_it_data_t *it;
626
627 ASSERT(key);
628
629 mutex_enter(&slu->sl_lock);
630 if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
631 for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
825 }
826 }
827
828 } else {
829 key->pgr_key_it = it;
830 }
831
832 mutex_enter(&slu->sl_lock);
833 it->pgr_key_ptr = key;
834 mutex_exit(&slu->sl_lock);
835 rw_exit(&pgr->pgr_lock);
836 return;
837 }
838 rw_exit(&pgr->pgr_lock);
839 }
840
841 /*
842 * Check for any PGR Reservation conflict. return 0 if access allowed
843 */
844 int
845 sbd_pgr_reservation_conflict(scsi_task_t *task, sbd_lu_t *slu)
846 {
847 sbd_pgr_t *pgr = slu->sl_pgr;
848 sbd_it_data_t *it = (sbd_it_data_t *)task->task_lu_itl_handle;
849
850 /* If Registered */
851 if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS && it->pgr_key_ptr)
852 return (0);
853
854 /* If you are registered */
855 if (pgr->pgr_flags & SBD_PGR_RSVD_ONE) {
856 rw_enter(&pgr->pgr_lock, RW_READER);
857
858 /*
859 * Note: it->pgr_key_ptr is protected by sl_lock. Also,
860 * it is expected to change its value only with pgr_lock
861 * held. Hence we are safe to read its value without
862 * grabbing sl_lock. But make sure that the value used is
863 * not from registers by using "volatile" keyword.
864 * Since this funtion is in performance path, we may want
865 * to avoid grabbing sl_lock.
866 */
1398 sizeof (stmf_remote_port_t) * max_tpdnum);
1399 stmf_scsilib_send_status(task, STATUS_CHECK,
1400 STMF_SAA_INVALID_FIELD_IN_CDB);
1401 return;
1402 }
1403
1404 for (i = 0; i < tpdnum; i++) {
1405 (void) sbd_pgr_do_register(slu, NULL, lpt, &rpt_ary[i],
1406 keyflag, svc_key);
1407 }
1408 kmem_free(rpt_ary, sizeof (stmf_remote_port_t) * max_tpdnum);
1409 }
1410
1411 rport.rport_tptid = ses->ss_rport->rport_tptid;
1412 rport.rport_tptid_sz = ses->ss_rport->rport_tptid_sz;
1413
1414 (void) sbd_pgr_do_register(slu, it, lpt, &rport, keyflag, svc_key);
1415
1416 sbd_pgr_reg_done:
1417
1418 if (plist->aptpl || (sbd_pgr_should_save(slu) == B_TRUE)) {
1419 if (plist->aptpl)
1420 PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1421 else
1422 PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1423
1424 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1425 stmf_scsilib_send_status(task, STATUS_CHECK,
1426 STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1427 return;
1428 }
1429 }
1430
1431 pgr->pgr_PRgeneration++;
1432 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1433 }
1434
1435 static sbd_pgr_key_t *
1436 sbd_pgr_do_register(sbd_lu_t *slu, sbd_it_data_t *it, scsi_devid_desc_t *lpt,
1437 stmf_remote_port_t *rpt, uint8_t keyflag, uint64_t svc_key)
1438 {
1503 return;
1504 }
1505
1506 if (SBD_PGR_RSVD(pgr)) {
1507 if (PGR_RESERVATION_HOLDER(pgr, key, it)) {
1508 if (pgr->pgr_rsv_type != pr_out->type ||
1509 pgr->pgr_rsv_scope != pr_out->scope) {
1510 stmf_scsilib_send_status(task,
1511 STATUS_RESERVATION_CONFLICT, 0);
1512 return;
1513 }
1514 } else {
1515 stmf_scsilib_send_status(task,
1516 STATUS_RESERVATION_CONFLICT, 0);
1517 return;
1518
1519 }
1520 /* In case there is no reservation exist */
1521 } else {
1522 sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
1523 if (sbd_pgr_should_save(slu) == B_TRUE) {
1524 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1525 stmf_scsilib_send_status(task, STATUS_CHECK,
1526 STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1527 return;
1528 }
1529 }
1530 }
1531
1532 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1533 }
1534
1535 static void
1536 sbd_pgr_do_reserve(sbd_pgr_t *pgr, sbd_pgr_key_t *key, sbd_it_data_t *it,
1537 stmf_scsi_session_t *ses, scsi_cdb_prout_t *pr_out)
1538 {
1539 scsi_devid_desc_t *lpt;
1540 uint16_t lpt_len;
1541
1542 pgr->pgr_rsv_type = pr_out->type;
1543 pgr->pgr_rsv_scope = pr_out->scope;
1560 bcopy(lpt, key->pgr_key_lpt_id, lpt_len);
1561 key->pgr_key_it = it;
1562 }
1563
1564 PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_RSVD_ONE);
1565 pgr->pgr_rsvholder = key;
1566 }
1567 }
1568
1569 static void
1570 sbd_pgr_out_release(scsi_task_t *task)
1571 {
1572 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
1573 scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb;
1574 sbd_it_data_t *it = task->task_lu_itl_handle;
1575 sbd_pgr_t *pgr = slu->sl_pgr;
1576 sbd_pgr_key_t *key = it->pgr_key_ptr;
1577
1578 ASSERT(key);
1579
1580 /*
1581 * XXX this does not honor APTPL
1582 * (i.e., changes made to a formerly-persistent reservation are not
1583 * updated here!!!)
1584 */
1585 if (SBD_PGR_RSVD(pgr)) {
1586 if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS ||
1587 pgr->pgr_rsvholder == key) {
1588 if (pgr->pgr_rsv_type != pr_out->type ||
1589 pgr->pgr_rsv_scope != pr_out->scope) {
1590 stmf_scsilib_send_status(task, STATUS_CHECK,
1591 STMF_SAA_INVALID_RELEASE_OF_PR);
1592 return;
1593 }
1594 sbd_pgr_do_release(slu, it,
1595 SBD_UA_RESERVATIONS_RELEASED);
1596
1597 /*
1598 * XXX T10 SPC-3 5.6.10.2 says nothing about what to
1599 * do in the event of a failure updating the
1600 * PGR nvram store for a reservation associated with
1601 * an APTPL-enabled (see SPC-3 5.6.4.1) I_T
1602 * registration during a RELEASE service action.
1603 *
1604 * Technically, the CDB completed successfully, as per
1605 * the spec, but at some point we may need to enter
1606 * a recovery mode on the initiator(s) if we power cycle
1607 * the target at the wrong instant...
1608 */
1609 if (sbd_pgr_should_save(slu) == B_TRUE) {
1610 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1611 stmf_scsilib_send_status(task,
1612 STATUS_CHECK, /* CSTYLED */
1613 STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1614 return;
1615 }
1616 }
1617 }
1618 }
1619 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1620 }
1621
1622 static void
1623 sbd_pgr_do_release(sbd_lu_t *slu, sbd_it_data_t *it, uint8_t ua_condition)
1624 {
1625
1626 sbd_pgr_t *pgr = slu->sl_pgr;
1627
1628 /* Reset pgr_flags */
1629 PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
1630 pgr->pgr_rsvholder = NULL;
1631
1632 /* set unit attention condition if necessary */
1633 if (pgr->pgr_rsv_type != PGR_TYPE_WR_EX &&
1634 pgr->pgr_rsv_type != PGR_TYPE_EX_AC) {
1635 sbd_pgr_set_ua_conditions(slu, it, ua_condition);
1636 }
1637 pgr->pgr_rsv_type = 0;
1638 }
1640 static void
1641 sbd_pgr_out_clear(scsi_task_t *task)
1642 {
1643 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
1644 sbd_it_data_t *it = task->task_lu_itl_handle;
1645 sbd_pgr_t *pgr = slu->sl_pgr;
1646
1647 ASSERT(it->pgr_key_ptr);
1648
1649 PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
1650 pgr->pgr_rsvholder = NULL;
1651 pgr->pgr_rsv_type = 0;
1652 mutex_enter(&slu->sl_lock);
1653 /* Remove all pointers from IT to pgr keys */
1654 for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
1655 it->pgr_key_ptr = NULL;
1656 }
1657 mutex_exit(&slu->sl_lock);
1658 sbd_pgr_keylist_dealloc(slu);
1659 sbd_pgr_set_ua_conditions(slu, it, SBD_UA_RESERVATIONS_PREEMPTED);
1660 if (sbd_pgr_should_save(slu) == B_TRUE) {
1661 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1662 stmf_scsilib_send_status(task, STATUS_CHECK,
1663 STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1664 return;
1665 }
1666 }
1667 pgr->pgr_PRgeneration++;
1668 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1669 }
1670
1671 static void
1672 sbd_pgr_out_preempt(scsi_task_t *task, stmf_data_buf_t *dbuf)
1673 {
1674 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
1675 stmf_scsi_session_t *ses = task->task_session;
1676 scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb;
1677 sbd_it_data_t *it = task->task_lu_itl_handle;
1678 sbd_pgr_t *pgr = slu->sl_pgr;
1679 sbd_pgr_key_t *key = it->pgr_key_ptr;
1680 scsi_prout_plist_t *plist;
1755 if (!(PGR_VALID_SCOPE(pr_out->scope) &&
1756 PGR_VALID_TYPE(pr_out->type))) {
1757 stmf_scsilib_send_status(task, STATUS_CHECK,
1758 STMF_SAA_INVALID_FIELD_IN_CDB);
1759 return;
1760 }
1761 sbd_pgr_do_release(slu, it,
1762 SBD_UA_REGISTRATIONS_PREEMPTED);
1763 (void) sbd_pgr_remove_keys(slu, it, key, 0, B_FALSE);
1764 sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
1765 } else {
1766 if (sbd_pgr_remove_keys(slu, it, key, svc_key, B_TRUE)
1767 == 0) {
1768 stmf_scsilib_send_status(task,
1769 STATUS_RESERVATION_CONFLICT, 0);
1770 return;
1771 }
1772 }
1773 }
1774
1775 if (sbd_pgr_should_save(slu) == B_TRUE) {
1776 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1777 stmf_scsilib_send_status(task, STATUS_CHECK,
1778 STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1779 return;
1780 }
1781 }
1782
1783 pgr->pgr_PRgeneration++;
1784
1785 if (pr_out->action == PR_OUT_PREEMPT_ABORT) {
1786 stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED,
1787 (void *)slu->sl_lu);
1788 }
1789 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1790 }
1791
1792 static void
1793 sbd_pgr_out_register_and_move(scsi_task_t *task, stmf_data_buf_t *dbuf)
1794 {
1795 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
1869 kmem_zalloc(lpt_len, KM_SLEEP);
1870 bcopy(lpt, newkey->pgr_key_lpt_id, lpt_len);
1871 }
1872 /* No IT nexus information, hence set PGR_CHEK flag */
1873 sbd_pgr_set_pgr_check_flag(slu, B_TRUE);
1874 } else {
1875 newkey = sbd_pgr_do_register(slu, NULL, lpt, &rport,
1876 SBD_PGR_KEY_TPT_ID_FLAG, svc_key);
1877 }
1878
1879 kmem_free(lpt, sizeof (scsi_devid_desc_t) + lpt->ident_length);
1880
1881 /* Now reserve the key corresponding to the specified IT nexus */
1882 pgr->pgr_rsvholder = newkey;
1883
1884 if (plist->unreg) {
1885 sbd_pgr_do_unregister(slu, it, key);
1886 }
1887
1888
1889 /* Write to disk if aptpl is currently set or this task is setting it */
1890 if (plist->aptpl || (sbd_pgr_should_save(slu) == B_TRUE)) {
1891 if (plist->aptpl)
1892 PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1893 else
1894 PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1895
1896 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1897 stmf_scsilib_send_status(task, STATUS_CHECK,
1898 STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1899 return;
1900 }
1901 }
1902
1903 pgr->pgr_PRgeneration++;
1904 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1905 }
1906
1907 void
1908 sbd_pgr_remove_it_handle(sbd_lu_t *sl, sbd_it_data_t *my_it) {
1909 sbd_it_data_t *it;
1910
|