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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "cfga_scsi.h" 30 31 #define MAX_FORMAT 80 32 33 static scfga_ret_t scsi_rcm_info_table(rcm_info_t *, char **); 34 static scfga_ret_t scsi_rcm_init(uint_t, char **, rcm_handle_t **); 35 36 /* 37 * scsi_rcm_offline() 38 * 39 * Offline SCSI resource consumers. 40 */ 41 scfga_ret_t 42 scsi_rcm_offline(char **rsrclist, char **errstring, cfga_flags_t flags) 43 { 44 int rret; 45 uint_t rflags = 0; 46 rcm_info_t *rinfo = NULL; 47 scfga_ret_t ret = SCFGA_OK; 48 rcm_handle_t *rcm_handle; 49 50 if (rsrclist == NULL) 51 return (ret); 52 53 if ((ret = scsi_rcm_init(0, errstring, &rcm_handle)) 54 != SCFGA_OK) 55 return (ret); 56 57 if (flags & CFGA_FLAG_FORCE) 58 rflags = RCM_FORCE; 59 60 if ((rret = rcm_request_offline_list(rcm_handle, rsrclist, rflags, 61 &rinfo)) != RCM_SUCCESS) { 62 cfga_err(errstring, 0, ERRARG_RCM_OFFLINE, 0); 63 if (rinfo) { 64 (void) scsi_rcm_info_table(rinfo, errstring); 65 rcm_free_info(rinfo); 66 } 67 if (rret == RCM_FAILURE) 68 (void) rcm_notify_online_list(rcm_handle, rsrclist, 69 rflags & ~RCM_FORCE, NULL); 70 ret = SCFGA_BUSY; 71 } 72 rcm_free_handle(rcm_handle); 73 return (ret); 74 } 75 76 /* 77 * scsi_rcm_online() 78 * 79 * Online SCSI resource consumers that were previously offlined. 80 */ 81 /*ARGSUSED2*/ 82 scfga_ret_t 83 scsi_rcm_online(char **rsrclist, char **errstring, cfga_flags_t flags) 84 { 85 rcm_info_t *rinfo = NULL; 86 scfga_ret_t ret = SCFGA_OK; 87 rcm_handle_t *rcm_handle; 88 89 if (rsrclist == NULL) 90 return (ret); 91 92 if ((ret = scsi_rcm_init(0, errstring, &rcm_handle)) 93 != SCFGA_OK) 94 return (ret); 95 96 if (rcm_notify_online_list(rcm_handle, rsrclist, 0, &rinfo) 97 != RCM_SUCCESS) { 98 cfga_err(errstring, 0, ERRARG_RCM_ONLINE, 0); 99 if (rinfo != NULL) { 100 (void) scsi_rcm_info_table(rinfo, errstring); 101 rcm_free_info(rinfo); 102 } 103 ret = SCFGA_BUSY; 104 } 105 rcm_free_handle(rcm_handle); 106 return (ret); 107 } 108 109 /* 110 * scsi_rcm_remove() 111 * 112 * Remove SCSI resource consumers after their kernel removal. 113 */ 114 /*ARGSUSED2*/ 115 scfga_ret_t 116 scsi_rcm_remove(char **rsrclist, char **errstring, cfga_flags_t flags) 117 { 118 rcm_info_t *rinfo = NULL; 119 scfga_ret_t ret = SCFGA_OK; 120 rcm_handle_t *rcm_handle; 121 122 if (rsrclist == NULL) 123 return (ret); 124 125 if ((ret = scsi_rcm_init(0, errstring, &rcm_handle)) 126 != SCFGA_OK) 127 return (ret); 128 129 if (rcm_notify_remove_list(rcm_handle, rsrclist, 0, &rinfo) 130 != RCM_SUCCESS) { 131 cfga_err(errstring, 0, ERRARG_RCM_REMOVE, 0); 132 if (rinfo) { 133 (void) scsi_rcm_info_table(rinfo, errstring); 134 rcm_free_info(rinfo); 135 } 136 ret = SCFGA_BUSY; 137 } 138 139 rcm_free_handle(rcm_handle); 140 return (ret); 141 } 142 143 /* 144 * scsi_rcm_suspend() 145 * 146 * Suspend SCSI resource consumers before a bus quiesce. 147 */ 148 scfga_ret_t 149 scsi_rcm_suspend(char **rsrclist, char **errstring, cfga_flags_t flags, 150 int pflag) 151 { 152 int rret; 153 uint_t rflags = 0; 154 rcm_info_t *rinfo = NULL; 155 scfga_ret_t ret = SCFGA_OK; 156 rcm_handle_t *rcm_handle; 157 timespec_t zerotime = { 0, 0 }; 158 159 if (rsrclist == NULL) 160 return (ret); 161 162 pflag = pflag ? RCM_NOPID : 0; 163 if ((ret = scsi_rcm_init(pflag, errstring, &rcm_handle)) 164 != SCFGA_OK) 165 return (ret); 166 167 if (flags & CFGA_FLAG_FORCE) 168 rflags = RCM_FORCE; 169 170 /* 171 * attempt a suspension on a list of resources 172 */ 173 if ((rret = rcm_request_suspend_list(rcm_handle, rsrclist, rflags, 174 &zerotime, &rinfo)) != RCM_SUCCESS) { 175 cfga_err(errstring, 0, ERRARG_RCM_SUSPEND, 0); 176 if (rinfo) { 177 (void) scsi_rcm_info_table(rinfo, errstring); 178 rcm_free_info(rinfo); 179 } 180 if (rret == RCM_FAILURE) 181 (void) rcm_notify_resume_list(rcm_handle, rsrclist, 182 (rflags & (~RCM_FORCE)), NULL); 183 ret = SCFGA_BUSY; 184 } 185 rcm_free_handle(rcm_handle); 186 return (ret); 187 } 188 189 /* 190 * scsi_rcm_resume() 191 * 192 * Resume SCSI resource consumers after a bus has been unquiesced. 193 */ 194 /*ARGSUSED2*/ 195 scfga_ret_t 196 scsi_rcm_resume(char **rsrclist, char **errstring, cfga_flags_t flags, 197 int pflag) 198 { 199 rcm_info_t *rinfo = NULL; 200 scfga_ret_t ret = SCFGA_OK; 201 rcm_handle_t *rcm_handle; 202 203 if (rsrclist == NULL) 204 return (ret); 205 206 pflag = pflag ? RCM_NOPID : 0; 207 if ((ret = scsi_rcm_init(pflag, errstring, &rcm_handle)) 208 != SCFGA_OK) 209 return (ret); 210 211 /* 212 * resume the resource list. 213 */ 214 if (rcm_notify_resume_list(rcm_handle, rsrclist, 0, &rinfo) 215 != RCM_SUCCESS) { 216 cfga_err(errstring, 0, ERRARG_RCM_RESUME, 0); 217 if (rinfo != NULL) { 218 (void) scsi_rcm_info_table(rinfo, errstring); 219 rcm_free_info(rinfo); 220 } 221 ret = SCFGA_BUSY; 222 } 223 rcm_free_handle(rcm_handle); 224 return (ret); 225 } 226 227 /* 228 * scsi_rcm_init() 229 * 230 * Contains common initialization code for entering a scsi_rcm_xx() 231 * routine. 232 */ 233 static scfga_ret_t 234 scsi_rcm_init(uint_t rcm_flag, char **errstring, rcm_handle_t **hdlp) 235 { 236 /* Get a handle for the RCM operations */ 237 if (rcm_alloc_handle(NULL, rcm_flag, NULL, hdlp) != RCM_SUCCESS) { 238 cfga_err(errstring, 0, ERR_RCM_HANDLE, 0); 239 return (SCFGA_LIB_ERR); 240 } 241 242 return (SCFGA_OK); 243 } 244 245 /* 246 * scsi_rcm_info_table 247 * 248 * Takes an opaque rcm_info_t pointer and a character pointer, and appends 249 * the rcm_info_t data in the form of a table to the given character pointer. 250 */ 251 static scfga_ret_t 252 scsi_rcm_info_table(rcm_info_t *rinfo, char **table) 253 { 254 int i; 255 size_t w; 256 size_t width = 0; 257 size_t w_rsrc = 0; 258 size_t w_info = 0; 259 size_t table_size = 0; 260 uint_t tuples = 0; 261 rcm_info_tuple_t *tuple = NULL; 262 char *rsrc; 263 char *info; 264 char *newtable; 265 static char format[MAX_FORMAT]; 266 const char *infostr; 267 268 /* Protect against invalid arguments */ 269 if (rinfo == NULL || table == NULL) 270 return (SCFGA_ERR); 271 272 /* Set localized table header strings */ 273 rsrc = dgettext(TEXT_DOMAIN, "Resource"); 274 info = dgettext(TEXT_DOMAIN, "Information"); 275 276 /* A first pass, to size up the RCM information */ 277 while (tuple = rcm_info_next(rinfo, tuple)) { 278 if ((infostr = rcm_info_info(tuple)) != NULL) { 279 tuples++; 280 if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc) 281 w_rsrc = w; 282 if ((w = strlen(infostr)) > w_info) 283 w_info = w; 284 } 285 } 286 287 /* If nothing was sized up above, stop early */ 288 if (tuples == 0) 289 return (SCFGA_OK); 290 291 /* Adjust column widths for column headings */ 292 if ((w = strlen(rsrc)) > w_rsrc) 293 w_rsrc = w; 294 else if ((w_rsrc - w) % 2) 295 w_rsrc++; 296 if ((w = strlen(info)) > w_info) 297 w_info = w; 298 else if ((w_info - w) % 2) 299 w_info++; 300 301 /* 302 * Compute the total line width of each line, 303 * accounting for intercolumn spacing. 304 */ 305 width = w_info + w_rsrc + 4; 306 307 /* Allocate space for the table */ 308 table_size = (2 + tuples) * (width + 1) + 2; 309 if (*table == NULL) { 310 /* zero fill for the strcat() call below */ 311 *table = calloc(table_size, sizeof (char)); 312 if (*table == NULL) 313 return (SCFGA_ERR); 314 } else { 315 newtable = realloc(*table, strlen(*table) + table_size); 316 if (newtable == NULL) 317 return (SCFGA_ERR); 318 else 319 *table = newtable; 320 } 321 322 /* Place a table header into the string */ 323 324 /* The resource header */ 325 (void) strcat(*table, "\n"); 326 w = strlen(rsrc); 327 for (i = 0; i < ((w_rsrc - w) / 2); i++) 328 (void) strcat(*table, " "); 329 (void) strcat(*table, rsrc); 330 for (i = 0; i < ((w_rsrc - w) / 2); i++) 331 (void) strcat(*table, " "); 332 333 /* The information header */ 334 (void) strcat(*table, " "); 335 w = strlen(info); 336 for (i = 0; i < ((w_info - w) / 2); i++) 337 (void) strcat(*table, " "); 338 (void) strcat(*table, info); 339 for (i = 0; i < ((w_info - w) / 2); i++) 340 (void) strcat(*table, " "); 341 342 /* Underline the headers */ 343 (void) strcat(*table, "\n"); 344 for (i = 0; i < w_rsrc; i++) 345 (void) strcat(*table, "-"); 346 (void) strcat(*table, " "); 347 for (i = 0; i < w_info; i++) 348 (void) strcat(*table, "-"); 349 350 /* Construct the format string */ 351 (void) snprintf(format, MAX_FORMAT, "%%-%ds %%-%ds", 352 (int)w_rsrc, (int)w_info); 353 354 /* Add the tuples to the table string */ 355 tuple = NULL; 356 while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) { 357 if ((infostr = rcm_info_info(tuple)) != NULL) { 358 (void) strcat(*table, "\n"); 359 (void) sprintf(&((*table)[strlen(*table)]), 360 format, rcm_info_rsrc(tuple), 361 infostr); 362 } 363 } 364 365 return (SCFGA_OK); 366 } 367