1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1998 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * support functions for hba drivers to handle scsi reset notifications. 31 */ 32 33 #include <sys/scsi/scsi.h> 34 #include <sys/scsi/impl/scsi_reset_notify.h> 35 36 /* 37 * routine for reset notification setup. 38 * The function is entered without adapter driver mutex being held. 39 */ 40 41 int 42 scsi_hba_reset_notify_setup(struct scsi_address *ap, int flag, 43 void (*callback)(caddr_t), caddr_t arg, kmutex_t *mutex, 44 struct scsi_reset_notify_entry **listp) 45 { 46 struct scsi_reset_notify_entry *p, *beforep; 47 int rval = DDI_FAILURE; 48 49 mutex_enter(mutex); 50 p = *listp; 51 beforep = NULL; 52 while (p) { 53 if (p->ap == ap) 54 break; /* An entry exist for this target */ 55 beforep = p; 56 p = p->next; 57 } 58 59 if ((flag & SCSI_RESET_CANCEL) && (p != NULL)) { 60 if (beforep == NULL) { 61 *listp = p->next; 62 } else { 63 beforep->next = p->next; 64 } 65 kmem_free(p, sizeof (struct scsi_reset_notify_entry)); 66 rval = DDI_SUCCESS; 67 68 } else if ((flag & SCSI_RESET_NOTIFY) && (p == NULL)) { 69 p = kmem_zalloc(sizeof (struct scsi_reset_notify_entry), 70 KM_SLEEP); 71 p->ap = ap; 72 p->callback = callback; 73 p->arg = arg; 74 p->next = *listp; 75 *listp = p; 76 rval = DDI_SUCCESS; 77 } 78 mutex_exit(mutex); 79 return (rval); 80 } 81 82 /* 83 * routine to deallocate the callback list 84 */ 85 void 86 scsi_hba_reset_notify_tear_down(struct scsi_reset_notify_entry *listp) 87 { 88 struct scsi_reset_notify_entry *p, *next; 89 90 p = listp; 91 while (p) { 92 next = p->next; 93 kmem_free(p, sizeof (struct scsi_reset_notify_entry)); 94 p = next; 95 } 96 } 97 98 99 /* 100 * routine to perform the notification callbacks after a reset. 101 * The function is entered with adapter driver mutex being held. 102 */ 103 void 104 scsi_hba_reset_notify_callback(kmutex_t *mutex, 105 struct scsi_reset_notify_entry **listp) 106 { 107 int i, count; 108 struct scsi_reset_notify_entry *p; 109 struct notify_entry { 110 void (*callback)(caddr_t); 111 caddr_t arg; 112 } *list; 113 114 if ((p = *listp) == NULL) 115 return; 116 117 count = 0; 118 while (p != NULL) { 119 count++; 120 p = p->next; 121 } 122 123 list = kmem_alloc(count * sizeof (struct notify_entry), KM_NOSLEEP); 124 if (list == NULL) { 125 cmn_err(CE_WARN, "scsi_reset_notify: kmem_alloc failed"); 126 return; 127 } 128 129 for (i = 0, p = *listp; i < count; i++, p = p->next) { 130 list[i].callback = p->callback; 131 list[i].arg = p->arg; 132 } 133 134 mutex_exit(mutex); 135 for (i = 0; i < count; i++) { 136 if (list[i].callback != NULL) 137 (void) (*list[i].callback)(list[i].arg); 138 } 139 kmem_free(list, count * sizeof (struct notify_entry)); 140 mutex_enter(mutex); 141 } 142