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 * Enclosure Services Devices, SEN Enclosure Routines 24 * 25 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <sys/modctl.h> 31 #include <sys/file.h> 32 #include <sys/scsi/scsi.h> 33 #include <sys/stat.h> 34 #include <sys/scsi/targets/sesio.h> 35 #include <sys/scsi/targets/ses.h> 36 37 38 /* 39 * The SEN unit is wired to support 7 disk units, 40 * two power supplies, one fan module, one overtemp sensor, 41 * and one alarm. 42 */ 43 #define NOBJECTS (7+2+1+1+1) 44 #define DRVOFF 0 45 #define SDRVOFF 20 46 #define NDRV 7 47 48 #define PWROFF NDRV 49 #define SPWROFF 28 50 #define NPWR 2 51 52 #define FANOFF (PWROFF + NPWR) 53 #define SFANOFF 30 54 #define NFAN 1 55 56 #define THMOFF (FANOFF + NFAN) 57 #define STHMOFF 31 58 #define NTHM 1 59 60 #define ALRMOFF (THMOFF + NTHM) 61 #define NALRM 1 62 #define SALRMOFF 8 63 64 #define SENPGINSIZE 32 65 #define SENPGOUTSIZE 22 66 67 int 68 sen_softc_init(ses_softc_t *ssc, int doinit) 69 { 70 int i; 71 if (doinit == 0) { 72 mutex_enter(&ssc->ses_devp->sd_mutex); 73 if (ssc->ses_nobjects) { 74 kmem_free(ssc->ses_objmap, 75 ssc->ses_nobjects * sizeof (encobj)); 76 ssc->ses_objmap = NULL; 77 ssc->ses_nobjects = 0; 78 } 79 mutex_exit(&ssc->ses_devp->sd_mutex); 80 return (0); 81 } 82 mutex_enter(&ssc->ses_devp->sd_mutex); 83 ssc->ses_nobjects = 0; 84 ssc->ses_encstat = 0; 85 ssc->ses_objmap = (encobj *) 86 kmem_zalloc(NOBJECTS * sizeof (encobj), KM_SLEEP); 87 if (ssc->ses_objmap == NULL) { 88 mutex_exit(&ssc->ses_devp->sd_mutex); 89 return (ENOMEM); 90 } 91 for (i = DRVOFF; i < DRVOFF + NDRV; i++) { 92 ssc->ses_objmap[i].enctype = SESTYP_DEVICE; 93 } 94 for (i = PWROFF; i < PWROFF + NPWR; i++) { 95 ssc->ses_objmap[i].enctype = SESTYP_POWER; 96 } 97 for (i = FANOFF; i < FANOFF + NFAN; i++) { 98 ssc->ses_objmap[i].enctype = SESTYP_FAN; 99 } 100 for (i = THMOFF; i < THMOFF + NTHM; i++) { 101 ssc->ses_objmap[i].enctype = SESTYP_THERM; 102 } 103 for (i = ALRMOFF; i < ALRMOFF + NALRM; i++) { 104 ssc->ses_objmap[i].enctype = SESTYP_ALARM; 105 } 106 ssc->ses_nobjects = NOBJECTS; 107 mutex_exit(&ssc->ses_devp->sd_mutex); 108 return (0); 109 } 110 111 int 112 sen_init_enc(ses_softc_t *ssc) 113 { 114 UNUSED_PARAMETER(ssc); 115 return (0); 116 } 117 118 static int 119 sen_rdstat(ses_softc_t *ssc, int slpflag) 120 { 121 int err, i, oid, baseid, tmp; 122 Uscmd local, *lp = &local; 123 char rqbuf[SENSE_LENGTH], *sdata; 124 static char cdb[CDB_GROUP0] = 125 { SCMD_GDIAG, 0x10, 0x4, 0, SENPGINSIZE, 0 }; 126 127 /* 128 * Fetch current data 129 */ 130 sdata = kmem_alloc(SENPGINSIZE, slpflag); 131 if (sdata == NULL) 132 return (ENOMEM); 133 134 lp->uscsi_flags = USCSI_READ|USCSI_RQENABLE; 135 lp->uscsi_timeout = ses_io_time; 136 lp->uscsi_cdb = cdb; 137 lp->uscsi_bufaddr = sdata; 138 lp->uscsi_buflen = SENPGINSIZE; 139 lp->uscsi_cdblen = sizeof (cdb); 140 lp->uscsi_rqbuf = rqbuf; 141 lp->uscsi_rqlen = sizeof (rqbuf); 142 err = ses_runcmd(ssc, lp); 143 if (err) { 144 kmem_free(sdata, SENPGINSIZE); 145 return (err); 146 } 147 148 if ((lp->uscsi_buflen - lp->uscsi_resid) < SENPGINSIZE) { 149 SES_LOG(ssc, CE_NOTE, "sen_rdstat: too little data (%ld)", 150 lp->uscsi_buflen - lp->uscsi_resid); 151 kmem_free(sdata, SENPGINSIZE); 152 return (EIO); 153 } 154 155 /* 156 * Set base SCSI id for drives... 157 */ 158 if (sdata[10] & 0x80) 159 baseid = 8; 160 else 161 baseid = 0; 162 163 oid = 0; 164 165 mutex_enter(&ssc->ses_devp->sd_mutex); 166 /* 167 * Invalidate all status bits. 168 */ 169 for (i = 0; i < ssc->ses_nobjects; i++) 170 ssc->ses_objmap[i].svalid = 0; 171 ssc->ses_encstat = 0; 172 173 /* 174 * Do Drives... 175 */ 176 for (i = SDRVOFF; i < SDRVOFF + NDRV; i++) { 177 ssc->ses_objmap[oid].encstat[1] = baseid + i - SDRVOFF; 178 ssc->ses_objmap[oid].encstat[2] = 0; 179 if (sdata[i] & 0x80) { 180 /* 181 * Drive is present 182 */ 183 ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK; 184 } else { 185 ssc->ses_objmap[oid].encstat[0] = SESSTAT_NOTINSTALLED; 186 ssc->ses_encstat |= ENCSTAT_INFO; 187 } 188 /* 189 * Is the fault LED lit? 190 */ 191 if (sdata[i] & 0x40) { 192 ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT; 193 ssc->ses_objmap[oid].encstat[3] = 0x40; 194 ssc->ses_encstat |= ENCSTAT_CRITICAL; 195 } else { 196 ssc->ses_objmap[oid].encstat[3] = 0x0; 197 } 198 ssc->ses_objmap[oid++].svalid = 1; 199 } 200 201 /* 202 * Do Power Supplies... 203 * 204 * Power supply bad, or not installed cannot be distinguished. 205 * Which one to pick? Let's say 'bad' and make it NONCRITICAL 206 * if only one is bad but CRITICAL if both are bad. 207 */ 208 for (tmp = 0, i = SPWROFF; i < SPWROFF + NPWR; i++) { 209 ssc->ses_objmap[oid].encstat[1] = 0; 210 ssc->ses_objmap[oid].encstat[2] = 0; 211 if ((sdata[i] & 0x80) == 0) { 212 /* 213 * Power supply 'ok'... 214 */ 215 ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK; 216 tmp++; 217 } else { 218 ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT; 219 ssc->ses_encstat |= ENCSTAT_NONCRITICAL; 220 } 221 ssc->ses_objmap[oid++].svalid = 1; 222 } 223 if (tmp == 0) { 224 ssc->ses_encstat |= ENCSTAT_CRITICAL; 225 } 226 227 /* 228 * Do the Fan(s) 229 */ 230 for (i = SFANOFF; i < SFANOFF + NFAN; i++) { 231 ssc->ses_objmap[oid].encstat[1] = 0; 232 ssc->ses_objmap[oid].encstat[2] = 0; 233 if (sdata[i] & 0x20) { /* both fans have failed */ 234 ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT; 235 ssc->ses_objmap[oid].encstat[3] = 0x40; 236 ssc->ses_encstat |= ENCSTAT_CRITICAL; 237 } else if (sdata[i] & 0x80) { /* one fan has failed */ 238 ssc->ses_objmap[oid].encstat[0] = SESSTAT_NONCRIT; 239 ssc->ses_objmap[oid].encstat[3] = 0x41; 240 ssc->ses_encstat |= ENCSTAT_NONCRITICAL; 241 } else { 242 ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK; 243 ssc->ses_objmap[oid].encstat[3] = 0x6; 244 } 245 ssc->ses_objmap[oid++].svalid = 1; 246 } 247 248 /* 249 * Do the temperature sensor... 250 */ 251 for (i = STHMOFF; i < STHMOFF + NTHM; i++) { 252 ssc->ses_objmap[oid].encstat[1] = 0; 253 if (sdata[i] & 0x80) { 254 ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT; 255 /* ssc->ses_objmap[oid].encstat[2] = 0; */ 256 ssc->ses_objmap[oid].encstat[3] = 0x8; 257 ssc->ses_encstat |= ENCSTAT_CRITICAL; 258 } else { 259 ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK; 260 /* ssc->ses_objmap[oid].encstat[2] = 0; */ 261 ssc->ses_objmap[oid].encstat[3] = 0; 262 } 263 ssc->ses_objmap[oid++].svalid = 1; 264 } 265 266 /* 267 * and last, but not least, check the state of the alarm. 268 */ 269 for (i = SALRMOFF; i < SALRMOFF + NALRM; i++) { 270 ssc->ses_objmap[oid].encstat[1] = 0; 271 ssc->ses_objmap[oid].encstat[2] = 0; 272 if (sdata[i] & 0x80) { /* Alarm is or was sounding */ 273 ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT; 274 ssc->ses_objmap[oid].encstat[3] = 0x2; 275 if ((sdata[i] & 0xf)) 276 ssc->ses_objmap[oid].encstat[3] |= 0x40; 277 ssc->ses_encstat |= ENCSTAT_CRITICAL; 278 } else { 279 ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK; 280 ssc->ses_objmap[oid].encstat[3] = 0; 281 } 282 ssc->ses_objmap[oid++].svalid = 1; 283 } 284 ssc->ses_encstat |= ENCI_SVALID; 285 mutex_exit(&ssc->ses_devp->sd_mutex); 286 kmem_free(sdata, SENPGINSIZE); 287 return (0); 288 } 289 290 int 291 sen_get_encstat(ses_softc_t *ssc, int slpflag) 292 { 293 return (sen_rdstat(ssc, slpflag)); 294 } 295 296 int 297 sen_set_encstat(ses_softc_t *ssc, uchar_t encstat, int slpflag) 298 { 299 UNUSED_PARAMETER(ssc); 300 UNUSED_PARAMETER(encstat); 301 UNUSED_PARAMETER(slpflag); 302 return (0); 303 } 304 305 int 306 sen_get_objstat(ses_softc_t *ssc, ses_objarg *obp, int slpflag) 307 { 308 int i = (int)obp->obj_id; 309 310 if ((ssc->ses_encstat & ENCI_SVALID) == 0 || 311 (ssc->ses_objmap[i].svalid) == 0) { 312 int r = sen_rdstat(ssc, slpflag); 313 if (r) 314 return (r); 315 } 316 obp->cstat[0] = ssc->ses_objmap[i].encstat[0]; 317 obp->cstat[1] = ssc->ses_objmap[i].encstat[1]; 318 obp->cstat[2] = ssc->ses_objmap[i].encstat[2]; 319 obp->cstat[3] = ssc->ses_objmap[i].encstat[3]; 320 return (0); 321 } 322 323 324 int 325 sen_set_objstat(ses_softc_t *ssc, ses_objarg *obp, int slpflag) 326 { 327 encobj *ep; 328 int err, runcmd, idx; 329 Uscmd local, *lp = &local; 330 char rqbuf[SENSE_LENGTH], *sdata; 331 static char cdb[CDB_GROUP0] = 332 { SCMD_GDIAG, 0x10, 0x4, 0, SENPGINSIZE, 0 }; 333 static char cdb1[CDB_GROUP0] = 334 { SCMD_SDIAG, 0x10, 0, 0, SENPGOUTSIZE, 0 }; 335 336 /* 337 * If this is clear, we don't do diddly. 338 */ 339 if ((obp->cstat[0] & SESCTL_CSEL) == 0) { 340 return (0); 341 } 342 /* 343 * Fetch current data 344 */ 345 sdata = kmem_alloc(SENPGINSIZE, slpflag); 346 if (sdata == NULL) 347 return (ENOMEM); 348 lp->uscsi_flags = USCSI_READ|USCSI_RQENABLE; 349 lp->uscsi_timeout = ses_io_time; 350 lp->uscsi_cdb = cdb; 351 lp->uscsi_bufaddr = sdata; 352 lp->uscsi_buflen = SENPGINSIZE; 353 lp->uscsi_cdblen = sizeof (cdb); 354 lp->uscsi_rqbuf = rqbuf; 355 lp->uscsi_rqlen = sizeof (rqbuf); 356 err = ses_runcmd(ssc, lp); 357 if (err) { 358 kmem_free(sdata, SENPGINSIZE); 359 return (err); 360 } 361 if ((lp->uscsi_buflen - lp->uscsi_resid) < SENPGINSIZE) { 362 SES_LOG(ssc, CE_NOTE, "Too Little Data Returned (%ld)", 363 lp->uscsi_buflen - lp->uscsi_resid); 364 kmem_free(sdata, SENPGINSIZE); 365 return (EIO); 366 } 367 /* 368 * Okay, now convert the input page to the output page. 369 */ 370 sdata[1] = 0; 371 sdata[3] = 0x12; 372 sdata[6] = 1; 373 sdata[8] &= ~0x80; 374 sdata[10] = 0; 375 sdata[14] = sdata[20] & ~0x80; 376 sdata[15] = sdata[21] & ~0x80; 377 sdata[16] = sdata[22] & ~0x80; 378 sdata[17] = sdata[23] & ~0x80; 379 sdata[18] = sdata[24] & ~0x80; 380 sdata[19] = sdata[25] & ~0x80; 381 sdata[20] = sdata[26] & ~0x80; 382 sdata[21] = 0; 383 384 runcmd = 0; 385 386 idx = (int)obp->obj_id; 387 ep = &ssc->ses_objmap[idx]; 388 switch (ep->enctype) { 389 case SESTYP_DEVICE: 390 if (idx < 0 || idx >= NDRV) { 391 err = EINVAL; 392 } else if ((obp->cstat[3] & SESCTL_RQSFLT) != 0) { 393 SES_LOG(ssc, SES_CE_DEBUG1, "faulted %d", idx); 394 sdata[14 + idx] |= 0x40; 395 runcmd++; 396 } else { 397 SES_LOG(ssc, SES_CE_DEBUG1, "clrd fault on %d", idx); 398 sdata[14 + idx] &= ~0x40; 399 runcmd++; 400 } 401 break; 402 case SESTYP_POWER: 403 if ((obp->cstat[3] & SESCTL_RQSTFAIL) || 404 (obp->cstat[0] & SESCTL_DISABLE)) { 405 SES_LOG(ssc, CE_WARN, "Commanding Off Power Supply!"); 406 sdata[10] |= 0x40; /* Seppuku!!!! */ 407 runcmd++; 408 } 409 break; 410 case SESTYP_ALARM: 411 /* 412 * On all nonzero but the 'muted' bit, 413 * we turn on the alarm, 414 */ 415 obp->cstat[3] &= ~0xa; 416 if ((obp->cstat[3] & 0x40) || 417 (obp->cstat[0] & SESCTL_DISABLE)) { 418 sdata[8] = 0; 419 } else if (obp->cstat[3] != 0) { 420 sdata[8] = 0x40; 421 } else { 422 sdata[8] = 0; 423 } 424 runcmd++; 425 SES_LOG(ssc, SES_CE_DEBUG1, "%sabling alarm", 426 (sdata[8] & 0x40)? "en" : "dis"); 427 break; 428 default: 429 break; 430 } 431 432 if (runcmd) { 433 lp->uscsi_flags = USCSI_WRITE|USCSI_RQENABLE; 434 lp->uscsi_timeout = ses_io_time; 435 lp->uscsi_cdb = cdb1; 436 lp->uscsi_bufaddr = sdata; 437 lp->uscsi_buflen = SENPGOUTSIZE; 438 lp->uscsi_cdblen = sizeof (cdb); 439 lp->uscsi_rqbuf = rqbuf; 440 lp->uscsi_rqlen = sizeof (rqbuf); 441 err = ses_runcmd(ssc, lp); 442 /* preserve error across the rest of the action */ 443 } else { 444 err = 0; 445 } 446 447 mutex_enter(&ssc->ses_devp->sd_mutex); 448 ep->svalid = 0; 449 mutex_exit(&ssc->ses_devp->sd_mutex); 450 kmem_free(sdata, SENPGINSIZE); 451 return (err); 452 } 453 /* 454 * mode: c 455 * Local variables: 456 * c-indent-level: 8 457 * c-brace-imaginary-offset: 0 458 * c-brace-offset: -8 459 * c-argdecl-indent: 8 460 * c-label-offset: -8 461 * c-continued-statement-offset: 8 462 * c-continued-brace-offset: 0 463 * End: 464 */ 465