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