Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/scsi/targets/ses.c
+++ new/usr/src/uts/common/io/scsi/targets/ses.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Enclosure Services Device target driver
23 23 *
24 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 25 * Use is subject to license terms.
26 26 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
27 27 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28 28 */
29 29
30 30 #include <sys/modctl.h>
31 31 #include <sys/file.h>
32 32 #include <sys/scsi/scsi.h>
33 33 #include <sys/scsi/generic/status.h>
34 34 #include <sys/scsi/targets/sesio.h>
35 35 #include <sys/scsi/targets/ses.h>
36 36
37 37
38 38
39 39 /*
40 40 * Power management defines (should be in a common include file?)
41 41 */
42 42 #define PM_HARDWARE_STATE_PROP "pm-hardware-state"
43 43 #define PM_NEEDS_SUSPEND_RESUME "needs-suspend-resume"
44 44
45 45
46 46 /*
47 47 * Global Driver Data
48 48 */
49 49 int ses_io_time = SES_IO_TIME;
50 50
51 51 static int ses_retry_count = SES_RETRY_COUNT * SES_RETRY_MULTIPLIER;
52 52
53 53 #ifdef DEBUG
54 54 int ses_debug = 0;
55 55 #else /* DEBUG */
56 56 #define ses_debug 0
57 57 #endif /* DEBUG */
58 58
59 59
60 60 /*
61 61 * External Enclosure Functions
62 62 */
63 63 extern int ses_softc_init(ses_softc_t *, int);
64 64 extern int ses_init_enc(ses_softc_t *);
65 65 extern int ses_get_encstat(ses_softc_t *, int);
66 66 extern int ses_set_encstat(ses_softc_t *, uchar_t, int);
67 67 extern int ses_get_objstat(ses_softc_t *, ses_objarg *, int);
68 68 extern int ses_set_objstat(ses_softc_t *, ses_objarg *, int);
69 69
70 70 extern int safte_softc_init(ses_softc_t *, int);
71 71 extern int safte_init_enc(ses_softc_t *);
72 72 extern int safte_get_encstat(ses_softc_t *, int);
73 73 extern int safte_set_encstat(ses_softc_t *, uchar_t, int);
74 74 extern int safte_get_objstat(ses_softc_t *, ses_objarg *, int);
75 75 extern int safte_set_objstat(ses_softc_t *, ses_objarg *, int);
76 76
77 77 extern int sen_softc_init(ses_softc_t *, int);
78 78 extern int sen_init_enc(ses_softc_t *);
79 79 extern int sen_get_encstat(ses_softc_t *, int);
80 80 extern int sen_set_encstat(ses_softc_t *, uchar_t, int);
81 81 extern int sen_get_objstat(ses_softc_t *, ses_objarg *, int);
82 82 extern int sen_set_objstat(ses_softc_t *, ses_objarg *, int);
83 83
84 84 /*
85 85 * Local Function prototypes
86 86 */
87 87 static int ses_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
88 88 static int ses_probe(dev_info_t *);
89 89 static int ses_attach(dev_info_t *, ddi_attach_cmd_t);
90 90 static int ses_detach(dev_info_t *, ddi_detach_cmd_t);
91 91
92 92 static int is_enc_dev(ses_softc_t *, struct scsi_inquiry *, int, enctyp *);
93 93 static int ses_doattach(dev_info_t *dip);
94 94
95 95 static int ses_open(dev_t *, int, int, cred_t *);
96 96 static int ses_close(dev_t, int, int, cred_t *);
97 97 static int ses_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
98 98
99 99 static encvec vecs[3] = {
100 100 {
101 101 ses_softc_init, ses_init_enc, ses_get_encstat,
102 102 ses_set_encstat, ses_get_objstat, ses_set_objstat
103 103 },
104 104 {
105 105 safte_softc_init, safte_init_enc, safte_get_encstat,
106 106 safte_set_encstat, safte_get_objstat, safte_set_objstat,
107 107 },
108 108 {
109 109 sen_softc_init, sen_init_enc, sen_get_encstat,
110 110 sen_set_encstat, sen_get_objstat, sen_set_objstat
111 111 }
112 112 };
113 113
114 114
115 115 /*
116 116 * Local Functions
117 117 */
118 118 static int ses_start(struct buf *bp);
119 119 static int ses_decode_sense(struct scsi_pkt *pkt, int *err);
120 120
121 121 static void ses_get_pkt(struct buf *bp, int (*func)(opaque_t));
122 122 static void ses_callback(struct scsi_pkt *pkt);
123 123 static void ses_restart(void *arg);
124 124
125 125
126 126 /*
127 127 * Local Static Data
128 128 */
129 129 #ifndef D_HOTPLUG
130 130 #define D_HOTPLUG 0
131 131 #endif /* D_HOTPLUG */
132 132
133 133 static struct cb_ops ses_cb_ops = {
134 134 ses_open, /* open */
135 135 ses_close, /* close */
136 136 nodev, /* strategy */
137 137 nodev, /* print */
138 138 nodev, /* dump */
139 139 nodev, /* read */
140 140 nodev, /* write */
141 141 ses_ioctl, /* ioctl */
142 142 nodev, /* devmap */
143 143 nodev, /* mmap */
144 144 nodev, /* segmap */
145 145 nochpoll, /* poll */
146 146 ddi_prop_op, /* cb_prop_op */
147 147 0, /* streamtab */
148 148 #if !defined(CB_REV)
149 149 D_MP | D_NEW | D_HOTPLUG /* Driver compatibility flag */
150 150 #else /* !defined(CB_REV) */
151 151 D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */
152 152 CB_REV, /* cb_ops version number */
153 153 nodev, /* aread */
154 154 nodev /* awrite */
155 155 #endif /* !defined(CB_REV) */
156 156 };
157 157
158 158 static struct dev_ops ses_dev_ops = {
159 159 DEVO_REV, /* devo_rev, */
160 160 0, /* refcnt */
161 161 ses_info, /* info */
162 162 nulldev, /* identify */
163 163 ses_probe, /* probe */
164 164 ses_attach, /* attach */
165 165 ses_detach, /* detach */
166 166 nodev, /* reset */
167 167 &ses_cb_ops, /* driver operations */
168 168 (struct bus_ops *)NULL, /* bus operations */
169 169 NULL, /* power */
170 170 ddi_quiesce_not_needed, /* quiesce */
171 171 };
172 172
173 173 static void *estate = NULL;
174 174 static const char *Snm = "ses";
175 175 static const char *Str = "%s\n";
176 176 static const char *efl = "copyin/copyout EFAULT @ line %d";
177 177 static const char *fail_msg = "%stransport failed: reason '%s': %s";
178 178
179 179
180 180
181 181 /*
↓ open down ↓ |
181 lines elided |
↑ open up ↑ |
182 182 * autoconfiguration routines.
183 183 */
184 184
185 185 static struct modldrv modldrv = {
186 186 &mod_driverops,
187 187 "SCSI Enclosure Services",
188 188 &ses_dev_ops
189 189 };
190 190
191 191 static struct modlinkage modlinkage = {
192 - MODREV_1, &modldrv, NULL
192 + MODREV_1, { &modldrv, NULL }
193 193 };
194 194
195 195
196 196 int
197 197 _init(void)
198 198 {
199 199 int status;
200 200 status = ddi_soft_state_init(&estate, sizeof (ses_softc_t), 0);
201 201 if (status == 0) {
202 202 if ((status = mod_install(&modlinkage)) != 0) {
203 203 ddi_soft_state_fini(&estate);
204 204 }
205 205 }
206 206 return (status);
207 207 }
208 208
209 209 int
210 210 _fini(void)
211 211 {
212 212 int status;
213 213 if ((status = mod_remove(&modlinkage)) != 0) {
214 214 return (status);
215 215 }
216 216 ddi_soft_state_fini(&estate);
217 217 return (status);
218 218 }
219 219
220 220 int
221 221 _info(struct modinfo *modinfop)
222 222 {
223 223 return (mod_info(&modlinkage, modinfop));
224 224 }
225 225
226 226 static int
227 227 ses_probe(dev_info_t *dip)
228 228 {
229 229 int err;
230 230 struct scsi_device *devp;
231 231 enctyp ep;
232 232
233 233 /*
234 234 * I finally figured out why we return success
235 235 * on every probe. The devices that we attach to
236 236 * don't all report as being the same "device type"
237 237 *
238 238 * 1) A5x00 -- report as Enclosure Services (0xD) SES
239 239 * 2) A1000 -- report as Direct Access (0x0) SES
240 240 * uses the same target as raid controler.
241 241 * 3) D1000 -- report as processor (0x3) SAFTE
242 242 * 3) D240 -- report as processor (0x3) SAFTE
243 243 *
244 244 * We also reportedly attach to SEN devices which I
245 245 * believe reside in a Tobasco tray. I have never
246 246 * been able to get one to attach.
247 247 *
248 248 */
249 249 if (dip == NULL)
250 250 return (DDI_PROBE_FAILURE);
251 251 /* SES_LOG(NULL, SES_CE_DEBUG1, "ses_probe: OK"); */
252 252 if (ddi_dev_is_sid(dip) == DDI_SUCCESS) {
253 253 return (DDI_PROBE_DONTCARE);
254 254 }
255 255
256 256 devp = ddi_get_driver_private(dip);
257 257
258 258 /* Legacy: prevent driver.conf specified ses nodes on atapi. */
259 259 if (scsi_ifgetcap(&devp->sd_address, "interconnect-type", -1) ==
260 260 INTERCONNECT_ATAPI)
261 261 return (DDI_PROBE_FAILURE);
262 262
263 263 /*
264 264 * XXX: Breakage from the x86 folks.
265 265 */
266 266 if (strcmp(ddi_get_name(ddi_get_parent(dip)), "ata") == 0) {
267 267 return (DDI_PROBE_FAILURE);
268 268 }
269 269
270 270 switch (err = scsi_probe(devp, SLEEP_FUNC)) {
271 271 case SCSIPROBE_EXISTS:
272 272 if (is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &ep)) {
273 273 break;
274 274 }
275 275 /* FALLTHROUGH */
276 276 case SCSIPROBE_NORESP:
277 277 scsi_unprobe(devp);
278 278 return (DDI_PROBE_FAILURE);
279 279 default:
280 280 SES_LOG(NULL, SES_CE_DEBUG9,
281 281 "ses_probe: probe error %d", err);
282 282 scsi_unprobe(devp);
283 283 return (DDI_PROBE_FAILURE);
284 284 }
285 285 scsi_unprobe(devp);
286 286 return (DDI_PROBE_SUCCESS);
287 287 }
288 288
289 289 static int
290 290 ses_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
291 291 {
292 292 int inst, err;
293 293 ses_softc_t *ssc;
294 294
295 295 inst = ddi_get_instance(dip);
296 296 switch (cmd) {
297 297 case DDI_ATTACH:
298 298 SES_LOG(NULL, SES_CE_DEBUG9, "ses_attach: DDI_ATTACH ses%d",
299 299 inst);
300 300
301 301 err = ses_doattach(dip);
302 302
303 303 if (err == DDI_FAILURE) {
304 304 return (DDI_FAILURE);
305 305 }
306 306 SES_LOG(NULL, SES_CE_DEBUG4,
307 307 "ses_attach: DDI_ATTACH OK ses%d", inst);
308 308 break;
309 309
310 310 case DDI_RESUME:
311 311 if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
312 312 return (DDI_FAILURE);
313 313 }
314 314 SES_LOG(ssc, SES_CE_DEBUG1, "ses_attach: DDI_ATTACH ses%d",
315 315 inst);
316 316 ssc->ses_suspended = 0;
317 317 break;
318 318
319 319 default:
320 320 return (DDI_FAILURE);
321 321 }
322 322 return (DDI_SUCCESS);
323 323 }
324 324
325 325 static int
326 326 is_enc_dev(ses_softc_t *ssc, struct scsi_inquiry *inqp, int iqlen, enctyp *ep)
327 327 {
328 328 uchar_t dt = (inqp->inq_dtype & DTYPE_MASK);
329 329 uchar_t *iqd = (uchar_t *)inqp;
330 330
331 331 if (dt == DTYPE_ESI) {
332 332 if (strncmp(inqp->inq_vid, SEN_ID, SEN_ID_LEN) == 0) {
333 333 SES_LOG(ssc, SES_CE_DEBUG3, "SEN device found");
334 334 *ep = SEN_TYPE;
335 335 } else if (inqp->inq_rdf == RDF_SCSI2) {
336 336 /*
337 337 * Per SPC4 #6.4.2 Standard Inquiry Data, response
338 338 * data format (RDF) values of 0 and 1 are Obsolete,
339 339 * whereas values greater than 2 are Reserved
340 340 */
341 341 SES_LOG(ssc, SES_CE_DEBUG3, "SES device found");
342 342 *ep = SES_TYPE;
343 343 } else {
344 344 SES_LOG(ssc, SES_CE_DEBUG3, "Pre-SCSI3 SES device");
345 345 *ep = SES_TYPE;
346 346 }
347 347 return (1);
348 348 }
349 349 if ((iqd[6] & 0x40) && inqp->inq_rdf >= RDF_SCSI2) {
350 350 /*
351 351 * PassThrough Device.
352 352 */
353 353 *ep = SES_TYPE;
354 354 SES_LOG(ssc, SES_CE_DEBUG3, "Passthru SES device");
355 355 return (1);
356 356 }
357 357
358 358 if (iqlen < 47) {
359 359 SES_LOG(ssc, CE_NOTE,
360 360 "INQUIRY data too short to determine SAF-TE");
361 361 return (0);
362 362 }
363 363 if (strncmp((char *)&iqd[44], "SAF-TE", 4) == 0) {
364 364 *ep = SAFT_TYPE;
365 365 SES_LOG(ssc, SES_CE_DEBUG3, "SAF-TE device found");
366 366 return (1);
367 367 }
368 368 return (0);
369 369 }
370 370
371 371
372 372 /*
373 373 * Attach ses device.
374 374 *
375 375 * XXX: Power management is NOT supported. A token framework
376 376 * is provided that will need to be extended assuming we have
377 377 * ses devices we can power down. Currently, we don't have any.
378 378 */
379 379 static int
380 380 ses_doattach(dev_info_t *dip)
381 381 {
382 382 int inst, err;
383 383 Scsidevp devp;
384 384 ses_softc_t *ssc;
385 385 enctyp etyp;
386 386
387 387 inst = ddi_get_instance(dip);
388 388 /*
389 389 * Workaround for bug #4154979- for some reason we can
390 390 * be called with identical instance numbers but for
391 391 * different dev_info_t-s- all but one are bogus.
392 392 *
393 393 * Bad Dog! No Biscuit!
394 394 *
395 395 * A quick workaround might be to call ddi_soft_state_zalloc
396 396 * unconditionally, as the implementation fails these calls
397 397 * if there's an item already allocated. A more reasonable
398 398 * and longer term change is to move the allocation past
399 399 * the probe for the device's existence as most of these
400 400 * 'bogus' calls are for nonexistent devices.
401 401 */
402 402
403 403 devp = ddi_get_driver_private(dip);
404 404 devp->sd_dev = dip;
405 405
406 406 /*
407 407 * Determine whether the { i, t, l } we're called
408 408 * to start is an enclosure services device.
409 409 */
410 410
411 411 /*
412 412 * Call the scsi_probe routine to see whether
413 413 * we actually have an Enclosure Services device at
414 414 * this address.
415 415 */
416 416 err = scsi_probe(devp, SLEEP_FUNC);
417 417 if (err != SCSIPROBE_EXISTS) {
418 418 SES_LOG(NULL, SES_CE_DEBUG9,
419 419 "ses_doattach: probe error %d", err);
420 420 scsi_unprobe(devp);
421 421 return (DDI_FAILURE);
422 422 }
423 423 /* Call is_enc_dev() to get the etyp */
424 424 if (!(is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &etyp))) {
425 425 SES_LOG(NULL, CE_WARN,
426 426 "ses_doattach: ses%d: is_enc_dev failure", inst);
427 427 scsi_unprobe(devp);
428 428 return (DDI_FAILURE);
429 429 }
430 430
431 431 if (ddi_soft_state_zalloc(estate, inst) != DDI_SUCCESS) {
432 432 scsi_unprobe(devp);
433 433 SES_LOG(NULL, CE_NOTE, "ses%d: softalloc fails", inst);
434 434 return (DDI_FAILURE);
435 435 }
436 436 ssc = ddi_get_soft_state(estate, inst);
437 437 if (ssc == NULL) {
438 438 scsi_unprobe(devp);
439 439 SES_LOG(NULL, CE_NOTE, "ses%d: get_soft_state fails", inst);
440 440 return (DDI_FAILURE);
441 441 }
442 442 devp->sd_private = (opaque_t)ssc;
443 443 ssc->ses_devp = devp;
444 444 err = ddi_create_minor_node(dip, "0", S_IFCHR, inst,
445 445 DDI_NT_SCSI_ENCLOSURE, NULL);
446 446 if (err == DDI_FAILURE) {
447 447 ddi_remove_minor_node(dip, NULL);
448 448 SES_LOG(ssc, CE_NOTE, "minor node creation failed");
449 449 ddi_soft_state_free(estate, inst);
450 450 scsi_unprobe(devp);
451 451 return (DDI_FAILURE);
452 452 }
453 453
454 454 ssc->ses_type = etyp;
455 455 ssc->ses_vec = vecs[etyp];
456 456
457 457 /* Call SoftC Init Routine A bit later... */
458 458
459 459 ssc->ses_rqbp = scsi_alloc_consistent_buf(SES_ROUTE(ssc),
460 460 NULL, MAX_SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL);
461 461 if (ssc->ses_rqbp != NULL) {
462 462 ssc->ses_rqpkt = scsi_init_pkt(SES_ROUTE(ssc), NULL,
463 463 ssc->ses_rqbp, CDB_GROUP0, 1, 0, PKT_CONSISTENT,
464 464 SLEEP_FUNC, NULL);
465 465 }
466 466 if (ssc->ses_rqbp == NULL || ssc->ses_rqpkt == NULL) {
467 467 ddi_remove_minor_node(dip, NULL);
468 468 SES_LOG(ssc, CE_NOTE, "scsi_init_pkt of rqbuf failed");
469 469 if (ssc->ses_rqbp != NULL) {
470 470 scsi_free_consistent_buf(ssc->ses_rqbp);
471 471 ssc->ses_rqbp = NULL;
472 472 }
473 473 ddi_soft_state_free(estate, inst);
474 474 scsi_unprobe(devp);
475 475 return (DDI_FAILURE);
476 476 }
477 477 ssc->ses_rqpkt->pkt_private = (opaque_t)ssc;
478 478 ssc->ses_rqpkt->pkt_address = *(SES_ROUTE(ssc));
479 479 ssc->ses_rqpkt->pkt_comp = ses_callback;
480 480 ssc->ses_rqpkt->pkt_time = ses_io_time;
481 481 ssc->ses_rqpkt->pkt_flags = FLAG_NOPARITY|FLAG_NODISCON|FLAG_SENSING;
482 482 ssc->ses_rqpkt->pkt_cdbp[0] = SCMD_REQUEST_SENSE;
483 483 ssc->ses_rqpkt->pkt_cdbp[1] = 0;
484 484 ssc->ses_rqpkt->pkt_cdbp[2] = 0;
485 485 ssc->ses_rqpkt->pkt_cdbp[3] = 0;
486 486 ssc->ses_rqpkt->pkt_cdbp[4] = MAX_SENSE_LENGTH;
487 487 ssc->ses_rqpkt->pkt_cdbp[5] = 0;
488 488
489 489 switch (scsi_ifgetcap(SES_ROUTE(ssc), "auto-rqsense", 1)) {
490 490 case 1:
491 491 /* if already set, don't reset it */
492 492 ssc->ses_arq = 1;
493 493 break;
494 494 case 0:
495 495 /* try and set it */
496 496 ssc->ses_arq = ((scsi_ifsetcap(SES_ROUTE(ssc),
497 497 "auto-rqsense", 1, 1) == 1) ? 1 : 0);
498 498 break;
499 499 default:
500 500 /* probably undefined, so zero it out */
501 501 ssc->ses_arq = 0;
502 502 break;
503 503 }
504 504
505 505 ssc->ses_sbufp = getrbuf(KM_SLEEP);
506 506 cv_init(&ssc->ses_sbufcv, NULL, CV_DRIVER, NULL);
507 507
508 508 /*
509 509 * If the HBA supports wide, tell it to use wide.
510 510 */
511 511 if (scsi_ifgetcap(SES_ROUTE(ssc), "wide-xfer", 1) != -1) {
512 512 int wd = ((devp->sd_inq->inq_rdf == RDF_SCSI2) &&
513 513 (devp->sd_inq->inq_wbus16 || devp->sd_inq->inq_wbus32))
514 514 ? 1 : 0;
515 515 (void) scsi_ifsetcap(SES_ROUTE(ssc), "wide-xfer", wd, 1);
516 516 }
517 517
518 518 /*
519 519 * Now do ssc init of enclosure specifics.
520 520 * At the same time, check to make sure getrbuf
521 521 * actually succeeded.
522 522 */
523 523 if ((*ssc->ses_vec.softc_init)(ssc, 1)) {
524 524 SES_LOG(ssc, SES_CE_DEBUG3, "failed softc init");
525 525 (void) (*ssc->ses_vec.softc_init)(ssc, 0);
526 526 ddi_remove_minor_node(dip, NULL);
527 527 scsi_destroy_pkt(ssc->ses_rqpkt);
528 528 scsi_free_consistent_buf(ssc->ses_rqbp);
529 529 if (ssc->ses_sbufp) {
530 530 freerbuf(ssc->ses_sbufp);
531 531 }
532 532 cv_destroy(&ssc->ses_sbufcv);
533 533 ddi_soft_state_free(estate, inst);
534 534 scsi_unprobe(devp);
535 535 return (DDI_FAILURE);
536 536 }
537 537
538 538 /*
539 539 * create this property so that PM code knows we want
540 540 * to be suspended at PM time
541 541 */
542 542 (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
543 543 PM_HARDWARE_STATE_PROP, PM_NEEDS_SUSPEND_RESUME);
544 544
545 545 /* announce the existence of this device */
546 546 ddi_report_dev(dip);
547 547 return (DDI_SUCCESS);
548 548 }
549 549
550 550
551 551 /*
552 552 * Detach ses device.
553 553 *
554 554 * XXX: Power management is NOT supported. A token framework
555 555 * is provided that will need to be extended assuming we have
556 556 * ses devices we can power down. Currently, we don't have any.
557 557 */
558 558 static int
559 559 ses_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
560 560 {
561 561 ses_softc_t *ssc;
562 562 int inst;
563 563
564 564 switch (cmd) {
565 565 case DDI_DETACH:
566 566 inst = ddi_get_instance(dip);
567 567 ssc = ddi_get_soft_state(estate, inst);
568 568 if (ssc == NULL) {
569 569 cmn_err(CE_NOTE,
570 570 "ses%d: DDI_DETACH, no softstate found", inst);
571 571 return (DDI_FAILURE);
572 572 }
573 573 if (ISOPEN(ssc)) {
574 574 return (DDI_FAILURE);
575 575 }
576 576
577 577 #if !defined(lint)
578 578 /* LINTED */
579 579 _NOTE(COMPETING_THREADS_NOW);
580 580 #endif /* !defined(lint) */
581 581
582 582 if (ssc->ses_vec.softc_init)
583 583 (void) (*ssc->ses_vec.softc_init)(ssc, 0);
584 584
585 585 #if !defined(lint)
586 586 _NOTE(NO_COMPETING_THREADS_NOW);
587 587 #endif /* !defined(lint) */
588 588
589 589 (void) scsi_ifsetcap(SES_ROUTE(ssc), "auto-rqsense", 1, 0);
590 590 scsi_destroy_pkt(ssc->ses_rqpkt);
591 591 scsi_free_consistent_buf(ssc->ses_rqbp);
592 592 freerbuf(ssc->ses_sbufp);
593 593 cv_destroy(&ssc->ses_sbufcv);
594 594 ddi_soft_state_free(estate, inst);
595 595 ddi_prop_remove_all(dip);
596 596 ddi_remove_minor_node(dip, NULL);
597 597 scsi_unprobe(ddi_get_driver_private(dip));
598 598 break;
599 599
600 600 case DDI_SUSPEND:
601 601 inst = ddi_get_instance(dip);
602 602 if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
603 603 cmn_err(CE_NOTE,
604 604 "ses%d: DDI_SUSPEND, no softstate found", inst);
605 605 return (DDI_FAILURE);
606 606 }
607 607
608 608 /*
609 609 * If driver idle, accept suspend request.
610 610 * If it's busy, reject it. This keeps things simple!
611 611 */
612 612 mutex_enter(SES_MUTEX);
613 613 if (ssc->ses_sbufbsy) {
614 614 mutex_exit(SES_MUTEX);
615 615 return (DDI_FAILURE);
616 616 }
617 617 ssc->ses_suspended = 1;
618 618 mutex_exit(SES_MUTEX);
619 619 break;
620 620
621 621 default:
622 622 return (DDI_FAILURE);
623 623 }
624 624 return (DDI_SUCCESS);
625 625 }
626 626
627 627 /* ARGSUSED */
628 628 static int
629 629 ses_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
630 630 {
631 631 dev_t dev;
632 632 ses_softc_t *ssc;
633 633 int inst, error;
634 634
635 635 switch (infocmd) {
636 636 case DDI_INFO_DEVT2DEVINFO:
637 637 dev = (dev_t)arg;
638 638 inst = getminor(dev);
639 639 if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
640 640 return (DDI_FAILURE);
641 641 }
642 642 *result = (void *) ssc->ses_devp->sd_dev;
643 643 error = DDI_SUCCESS;
644 644 break;
645 645 case DDI_INFO_DEVT2INSTANCE:
646 646 dev = (dev_t)arg;
647 647 inst = getminor(dev);
648 648 *result = (void *)(uintptr_t)inst;
649 649 error = DDI_SUCCESS;
650 650 break;
651 651 default:
652 652 error = DDI_FAILURE;
653 653 }
654 654 return (error);
655 655 }
656 656
657 657
658 658 /*
659 659 * Unix Entry Points
660 660 */
661 661
662 662 /* ARGSUSED */
663 663 static int
664 664 ses_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
665 665 {
666 666 ses_softc_t *ssc;
667 667
668 668 if ((ssc = ddi_get_soft_state(estate, getminor(*dev_p))) == NULL) {
669 669 return (ENXIO);
670 670 }
671 671
672 672 /*
673 673 * If the device is powered down, request it's activation.
674 674 * If it can't be activated, fail open.
675 675 */
676 676 if (ssc->ses_suspended &&
677 677 ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) {
678 678 return (EIO);
679 679 }
680 680
681 681 mutex_enter(SES_MUTEX);
682 682 if (otyp == OTYP_LYR)
683 683 ssc->ses_lyropen++;
684 684 else
685 685 ssc->ses_oflag = 1;
686 686
687 687 ssc->ses_present = (ssc->ses_present)? ssc->ses_present: SES_OPENING;
688 688 mutex_exit(SES_MUTEX);
689 689 return (EOK);
690 690 }
691 691
692 692 /*ARGSUSED*/
693 693 static int
694 694 ses_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
695 695 {
696 696 ses_softc_t *ssc;
697 697 if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL) {
698 698 return (ENXIO);
699 699 }
700 700
701 701 if (ssc->ses_suspended) {
702 702 (void) ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1);
703 703 }
704 704
705 705 mutex_enter(SES_MUTEX);
706 706 if (otyp == OTYP_LYR)
707 707 ssc->ses_lyropen -= (ssc->ses_lyropen)? 1: 0;
708 708 else
709 709 ssc->ses_oflag = 0;
710 710 mutex_exit(SES_MUTEX);
711 711 return (0);
712 712 }
713 713
714 714
715 715 /*ARGSUSED3*/
716 716 static int
717 717 ses_ioctl(dev_t dev, int cmd, intptr_t arg, int flg, cred_t *cred_p, int *rvalp)
718 718 {
719 719 ses_softc_t *ssc;
720 720 ses_object k, *up;
721 721 ses_objarg x;
722 722 uchar_t t;
723 723 uchar_t i;
724 724 int rv = 0;
725 725
726 726 if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL ||
727 727 ssc->ses_present == SES_CLOSED) {
728 728 return (ENXIO);
729 729 }
730 730
731 731
732 732 switch (cmd) {
733 733 case SESIOC_GETNOBJ:
734 734 if (ddi_copyout(&ssc->ses_nobjects, (void *)arg,
735 735 sizeof (int), flg)) {
736 736 rv = EFAULT;
737 737 break;
738 738 }
739 739 break;
740 740
741 741 case SESIOC_GETOBJMAP:
742 742 up = (ses_object *) arg;
743 743 mutex_enter(SES_MUTEX);
744 744 for (i = 0; i != ssc->ses_nobjects; i++) {
745 745 k.obj_id = i;
746 746 k.subencid = ssc->ses_objmap[i].subenclosure;
747 747 k.elem_type = ssc->ses_objmap[i].enctype;
748 748 if (ddi_copyout(&k, up, sizeof (k), flg)) {
749 749 rv = EFAULT;
750 750 break;
751 751 }
752 752 up++;
753 753 }
754 754 mutex_exit(SES_MUTEX);
755 755 break;
756 756
757 757 case SESIOC_INIT:
758 758 if (drv_priv(cred_p) != 0) {
759 759 rv = EPERM;
760 760 break;
761 761 }
762 762 rv = (*ssc->ses_vec.init_enc)(ssc);
763 763 break;
764 764
765 765 case SESIOC_GETENCSTAT:
766 766 if ((ssc->ses_encstat & ENCI_SVALID) == 0) {
767 767 rv = (*ssc->ses_vec.get_encstat)(ssc, KM_SLEEP);
768 768 if (rv) {
769 769 break;
770 770 }
771 771 }
772 772 t = ssc->ses_encstat & 0xf;
773 773 if (ddi_copyout(&t, (void *)arg, sizeof (t), flg))
774 774 rv = EFAULT;
775 775 /*
776 776 * And always invalidate enclosure status on the way out.
777 777 */
778 778 mutex_enter(SES_MUTEX);
779 779 ssc->ses_encstat &= ~ENCI_SVALID;
780 780 mutex_exit(SES_MUTEX);
781 781 break;
782 782
783 783 case SESIOC_SETENCSTAT:
784 784 if (drv_priv(cred_p) != 0) {
785 785 rv = EPERM;
786 786 break;
787 787 }
788 788 if (ddi_copyin((void *)arg, &t, sizeof (t), flg))
789 789 rv = EFAULT;
790 790 else
791 791 rv = (*ssc->ses_vec.set_encstat)(ssc, t, KM_SLEEP);
792 792 mutex_enter(SES_MUTEX);
793 793 ssc->ses_encstat &= ~ENCI_SVALID;
794 794 mutex_exit(SES_MUTEX);
795 795 break;
796 796
797 797 case SESIOC_GETOBJSTAT:
798 798 if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) {
799 799 rv = EFAULT;
800 800 break;
801 801 }
802 802 if (x.obj_id >= ssc->ses_nobjects) {
803 803 rv = EINVAL;
804 804 break;
805 805 }
806 806 if ((rv = (*ssc->ses_vec.get_objstat)(ssc, &x, KM_SLEEP)) != 0)
807 807 break;
808 808 if (ddi_copyout(&x, (void *)arg, sizeof (x), flg))
809 809 rv = EFAULT;
810 810 else {
811 811 /*
812 812 * Now that we no longer poll, svalid never stays true.
813 813 */
814 814 mutex_enter(SES_MUTEX);
815 815 ssc->ses_objmap[x.obj_id].svalid = 0;
816 816 mutex_exit(SES_MUTEX);
817 817 }
818 818 break;
819 819
820 820 case SESIOC_SETOBJSTAT:
821 821 if (drv_priv(cred_p) != 0) {
822 822 rv = EPERM;
823 823 break;
824 824 }
825 825 if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) {
826 826 rv = EFAULT;
827 827 break;
828 828 }
829 829 if (x.obj_id >= ssc->ses_nobjects) {
830 830 rv = EINVAL;
831 831 break;
832 832 }
833 833 rv = (*ssc->ses_vec.set_objstat)(ssc, &x, KM_SLEEP);
834 834 if (rv == 0) {
835 835 mutex_enter(SES_MUTEX);
836 836 ssc->ses_objmap[x.obj_id].svalid = 0;
837 837 mutex_exit(SES_MUTEX);
838 838 }
839 839 break;
840 840
841 841 case USCSICMD:
842 842 if (drv_priv(cred_p) != 0) {
843 843 rv = EPERM;
844 844 break;
845 845 }
846 846 rv = ses_uscsi_cmd(ssc, (Uscmd *)arg, flg);
847 847 break;
848 848
849 849 default:
850 850 rv = ENOTTY;
851 851 break;
852 852 }
853 853 return (rv);
854 854 }
855 855
856 856
857 857 /*
858 858 * Loop on running a kernel based command
859 859 *
860 860 * FIXME: This routine is not really needed.
861 861 */
862 862 int
863 863 ses_runcmd(ses_softc_t *ssc, Uscmd *lp)
864 864 {
865 865 int e;
866 866
867 867 lp->uscsi_status = 0;
868 868 e = ses_uscsi_cmd(ssc, lp, FKIOCTL);
869 869
870 870 #ifdef not
871 871 /*
872 872 * Debug: Nice cross-check code for verifying consistent status.
873 873 */
874 874 if (lp->uscsi_status) {
875 875 if (lp->uscsi_status == STATUS_CHECK) {
876 876 SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]="
877 877 "0x%x->%s ASC/ASCQ=0x%x/0x%x>",
878 878 lp->uscsi_cdb[0],
879 879 scsi_sname(lp->uscsi_rqbuf[2] & 0xf),
880 880 lp->uscsi_rqbuf[12] & 0xff,
881 881 lp->uscsi_rqbuf[13] & 0xff);
882 882 } else {
883 883 SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]="
884 884 "0x%x -> Status 0x%x", lp->uscsi_cdb[0],
885 885 lp->uscsi_status);
886 886 }
887 887 }
888 888 #endif /* not */
889 889 return (e);
890 890 }
891 891
892 892
893 893 /*
894 894 * Run a scsi command.
895 895 */
896 896 int
897 897 ses_uscsi_cmd(ses_softc_t *ssc, Uscmd *Uc, int Uf)
898 898 {
899 899 Uscmd *uscmd;
900 900 struct buf *bp;
901 901 enum uio_seg uioseg;
902 902 int err;
903 903
904 904 /*
905 905 * Grab local 'special' buffer
906 906 */
907 907 mutex_enter(SES_MUTEX);
908 908 while (ssc->ses_sbufbsy) {
909 909 cv_wait(&ssc->ses_sbufcv, &ssc->ses_devp->sd_mutex);
910 910 }
911 911 ssc->ses_sbufbsy = 1;
912 912 mutex_exit(SES_MUTEX);
913 913
914 914 /*
915 915 * If the device is powered down, request it's activation.
916 916 * This check must be done after setting ses_sbufbsy!
917 917 */
918 918 if (ssc->ses_suspended &&
919 919 ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) {
920 920 mutex_enter(SES_MUTEX);
921 921 ssc->ses_sbufbsy = 0;
922 922 mutex_exit(SES_MUTEX);
923 923 return (EIO);
924 924 }
925 925
926 926 err = scsi_uscsi_alloc_and_copyin((intptr_t)Uc, Uf,
927 927 SES_ROUTE(ssc), &uscmd);
928 928 if (err != 0) {
929 929 SES_LOG(ssc, SES_CE_DEBUG1, "ses_uscsi_cmd: "
930 930 "scsi_uscsi_alloc_and_copyin failed\n");
931 931 mutex_enter(SES_MUTEX);
932 932 ssc->ses_sbufbsy = 0;
933 933 cv_signal(&ssc->ses_sbufcv);
934 934 mutex_exit(SES_MUTEX);
935 935 SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__);
936 936 return (err);
937 937 }
938 938
939 939 /*
940 940 * Copy the uscsi command related infos to ssc for use in ses_start()
941 941 * and ses_callback().
942 942 */
943 943 bcopy(uscmd, &ssc->ses_uscsicmd, sizeof (Uscmd));
944 944 if (uscmd->uscsi_cdb != NULL) {
945 945 bcopy(uscmd->uscsi_cdb, &ssc->ses_srqcdb,
946 946 (size_t)(uscmd->uscsi_cdblen));
947 947 }
948 948 ssc->ses_uscsicmd.uscsi_status = 0;
949 949
950 950 bp = ssc->ses_sbufp;
951 951 bp->av_back = (struct buf *)NULL;
952 952 bp->av_forw = (struct buf *)NULL;
953 953 bp->b_back = (struct buf *)ssc;
954 954 bp->b_edev = NODEV;
955 955
956 956 if (uscmd->uscsi_cdb != NULL) {
957 957 if (uscmd->uscsi_cdblen == CDB_GROUP0) {
958 958 SES_LOG(ssc, SES_CE_DEBUG7,
959 959 "scsi_cmd: %x %x %x %x %x %x",
960 960 ((char *)uscmd->uscsi_cdb)[0],
961 961 ((char *)uscmd->uscsi_cdb)[1],
962 962 ((char *)uscmd->uscsi_cdb)[2],
963 963 ((char *)uscmd->uscsi_cdb)[3],
964 964 ((char *)uscmd->uscsi_cdb)[4],
965 965 ((char *)uscmd->uscsi_cdb)[5]);
966 966 } else {
967 967 SES_LOG(ssc, SES_CE_DEBUG7,
968 968 "scsi cmd: %x %x %x %x %x %x %x %x %x %x",
969 969 ((char *)uscmd->uscsi_cdb)[0],
970 970 ((char *)uscmd->uscsi_cdb)[1],
971 971 ((char *)uscmd->uscsi_cdb)[2],
972 972 ((char *)uscmd->uscsi_cdb)[3],
973 973 ((char *)uscmd->uscsi_cdb)[4],
974 974 ((char *)uscmd->uscsi_cdb)[5],
975 975 ((char *)uscmd->uscsi_cdb)[6],
976 976 ((char *)uscmd->uscsi_cdb)[7],
977 977 ((char *)uscmd->uscsi_cdb)[8],
978 978 ((char *)uscmd->uscsi_cdb)[9]);
979 979 }
980 980 }
981 981
982 982 uioseg = (Uf & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE;
983 983 err = scsi_uscsi_handle_cmd(NODEV, uioseg, uscmd,
984 984 ses_start, bp, NULL);
985 985
986 986 /*
987 987 * ses_callback() may set values for ssc->ses_uscsicmd or
988 988 * ssc->ses_srqsbuf, so copy them back to uscmd.
989 989 */
990 990 if (uscmd->uscsi_rqbuf != NULL) {
991 991 bcopy(&ssc->ses_srqsbuf, uscmd->uscsi_rqbuf,
992 992 (size_t)(uscmd->uscsi_rqlen));
993 993 uscmd->uscsi_rqresid = ssc->ses_uscsicmd.uscsi_rqresid;
994 994 }
995 995 uscmd->uscsi_status = ssc->ses_uscsicmd.uscsi_status;
996 996
997 997 (void) scsi_uscsi_copyout_and_free((intptr_t)Uc, uscmd);
998 998 mutex_enter(SES_MUTEX);
999 999 ssc->ses_sbufbsy = 0;
1000 1000 cv_signal(&ssc->ses_sbufcv);
1001 1001 mutex_exit(SES_MUTEX);
1002 1002
1003 1003 return (err);
1004 1004 }
1005 1005
1006 1006
1007 1007
1008 1008 /*
1009 1009 * Command start and done functions.
1010 1010 */
1011 1011 static int
1012 1012 ses_start(struct buf *bp)
1013 1013 {
1014 1014 ses_softc_t *ssc = (ses_softc_t *)bp->b_back;
1015 1015
1016 1016 SES_LOG(ssc, SES_CE_DEBUG9, "ses_start");
1017 1017 if (!BP_PKT(bp)) {
1018 1018 /*
1019 1019 * Allocate a packet.
1020 1020 */
1021 1021 ses_get_pkt(bp, SLEEP_FUNC);
1022 1022 if (!BP_PKT(bp)) {
1023 1023 int err;
1024 1024 bp->b_resid = bp->b_bcount;
1025 1025 if (geterror(bp) == 0)
1026 1026 SET_BP_ERROR(bp, EIO);
1027 1027 err = geterror(bp);
1028 1028 biodone(bp);
1029 1029 return (err);
1030 1030 }
1031 1031 }
1032 1032
1033 1033 /*
1034 1034 * Initialize the transfer residue, error code, and retry count.
1035 1035 */
1036 1036 bp->b_resid = 0;
1037 1037 SET_BP_ERROR(bp, 0);
1038 1038
1039 1039 #if !defined(lint)
1040 1040 _NOTE(NO_COMPETING_THREADS_NOW);
1041 1041 #endif /* !defined(lint) */
1042 1042 ssc->ses_retries = ses_retry_count;
1043 1043
1044 1044 #if !defined(lint)
1045 1045 /* LINTED */
1046 1046 _NOTE(COMPETING_THREADS_NOW);
1047 1047 #endif /* !defined(lint) */
1048 1048
1049 1049 SES_LOG(ssc, SES_CE_DEBUG9, "ses_start -> scsi_transport");
1050 1050 switch (scsi_transport(BP_PKT(bp))) {
1051 1051 case TRAN_ACCEPT:
1052 1052 return (0);
1053 1053 /* break; */
1054 1054
1055 1055 case TRAN_BUSY:
1056 1056 SES_LOG(ssc, SES_CE_DEBUG2,
1057 1057 "ses_start: TRANSPORT BUSY");
1058 1058 SES_ENABLE_RESTART(SES_RESTART_TIME, BP_PKT(bp));
1059 1059 return (0);
1060 1060 /* break; */
1061 1061
1062 1062 default:
1063 1063 SES_LOG(ssc, SES_CE_DEBUG2, "TRANSPORT ERROR\n");
1064 1064 SET_BP_ERROR(bp, EIO);
1065 1065 scsi_destroy_pkt(BP_PKT(bp));
1066 1066 SET_BP_PKT(bp, NULL);
1067 1067 biodone(bp);
1068 1068 return (EIO);
1069 1069 /* break; */
1070 1070 }
1071 1071 }
1072 1072
1073 1073
1074 1074 static void
1075 1075 ses_get_pkt(struct buf *bp, int (*func)())
1076 1076 {
1077 1077 ses_softc_t *ssc = (ses_softc_t *)bp->b_back;
1078 1078 Uscmd *scmd = &ssc->ses_uscsicmd;
1079 1079 struct scsi_pkt *pkt;
1080 1080 int stat_size = 1;
1081 1081 int flags = 0;
1082 1082
1083 1083 if ((scmd->uscsi_flags & USCSI_RQENABLE) && ssc->ses_arq) {
1084 1084 if (scmd->uscsi_rqlen > SENSE_LENGTH) {
1085 1085 stat_size = (int)(scmd->uscsi_rqlen) +
1086 1086 sizeof (struct scsi_arq_status) -
1087 1087 sizeof (struct scsi_extended_sense);
1088 1088 flags = PKT_XARQ;
1089 1089 } else {
1090 1090 stat_size = sizeof (struct scsi_arq_status);
1091 1091 }
1092 1092 }
1093 1093
1094 1094 if (bp->b_bcount) {
1095 1095 pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, bp,
1096 1096 scmd->uscsi_cdblen, stat_size, 0, flags,
1097 1097 func, (caddr_t)ssc);
1098 1098 } else {
1099 1099 pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, NULL,
1100 1100 scmd->uscsi_cdblen, stat_size, 0, flags,
1101 1101 func, (caddr_t)ssc);
1102 1102 }
1103 1103 SET_BP_PKT(bp, pkt);
1104 1104 if (pkt == (struct scsi_pkt *)NULL)
1105 1105 return;
1106 1106 bcopy(scmd->uscsi_cdb, pkt->pkt_cdbp, (size_t)scmd->uscsi_cdblen);
1107 1107
1108 1108 /* Set an upper bound timeout of ses_io_time if zero is passed in */
1109 1109 pkt->pkt_time = (scmd->uscsi_timeout == 0) ?
1110 1110 ses_io_time : scmd->uscsi_timeout;
1111 1111
1112 1112 pkt->pkt_comp = ses_callback;
1113 1113 pkt->pkt_private = (opaque_t)ssc;
1114 1114 }
1115 1115
1116 1116
1117 1117 /*
1118 1118 * Restart ses command.
1119 1119 */
1120 1120 static void
1121 1121 ses_restart(void *arg)
1122 1122 {
1123 1123 struct scsi_pkt *pkt = (struct scsi_pkt *)arg;
1124 1124 ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
1125 1125 struct buf *bp = ssc->ses_sbufp;
1126 1126 SES_LOG(ssc, SES_CE_DEBUG9, "ses_restart");
1127 1127
1128 1128 ssc->ses_restart_id = NULL;
1129 1129
1130 1130 switch (scsi_transport(pkt)) {
1131 1131 case TRAN_ACCEPT:
1132 1132 SES_LOG(ssc, SES_CE_DEBUG9,
1133 1133 "RESTART %d ok", ssc->ses_retries);
1134 1134 return;
1135 1135 /* break; */
1136 1136 case TRAN_BUSY:
1137 1137 SES_LOG(ssc, SES_CE_DEBUG1,
1138 1138 "RESTART %d TRANSPORT BUSY\n", ssc->ses_retries);
1139 1139 if (ssc->ses_retries > SES_NO_RETRY) {
1140 1140 ssc->ses_retries -= SES_BUSY_RETRY;
1141 1141 SES_ENABLE_RESTART(SES_RESTART_TIME, pkt);
1142 1142 return;
1143 1143 }
1144 1144 SET_BP_ERROR(bp, EBUSY);
1145 1145 break;
1146 1146 default:
1147 1147 SET_BP_ERROR(bp, EIO);
1148 1148 break;
1149 1149 }
1150 1150 SES_LOG(ssc, SES_CE_DEBUG1,
1151 1151 "RESTART %d TRANSPORT FAILED\n", ssc->ses_retries);
1152 1152
1153 1153 pkt = (struct scsi_pkt *)bp->av_back;
1154 1154 scsi_destroy_pkt(pkt);
1155 1155 bp->b_resid = bp->b_bcount;
1156 1156 SET_BP_PKT(bp, NULL);
1157 1157 biodone(bp);
1158 1158 }
1159 1159
1160 1160
1161 1161 /*
1162 1162 * Command completion processing
1163 1163 */
1164 1164 #define HBA_RESET (STAT_BUS_RESET|STAT_DEV_RESET|STAT_ABORTED)
1165 1165 static void
1166 1166 ses_callback(struct scsi_pkt *pkt)
1167 1167 {
1168 1168 ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
1169 1169 struct buf *bp;
1170 1170 Uscmd *scmd;
1171 1171 int err;
1172 1172 char action;
1173 1173
1174 1174 bp = ssc->ses_sbufp;
1175 1175 scmd = &ssc->ses_uscsicmd;
1176 1176 /* SES_LOG(ssc, SES_CE_DEBUG9, "ses_callback"); */
1177 1177
1178 1178 /*
1179 1179 * Optimization: Normal completion.
1180 1180 */
1181 1181 if (pkt->pkt_reason == CMD_CMPLT &&
1182 1182 !SCBP_C(pkt) &&
1183 1183 !(pkt->pkt_flags & FLAG_SENSING) &&
1184 1184 !pkt->pkt_resid) {
1185 1185 scsi_destroy_pkt(pkt);
1186 1186 SET_BP_PKT(bp, NULL);
1187 1187 biodone(bp);
1188 1188 return;
1189 1189 }
1190 1190
1191 1191
1192 1192 /*
1193 1193 * Abnormal completion.
1194 1194 *
1195 1195 * Assume most common error initially.
1196 1196 */
1197 1197 err = EIO;
1198 1198 action = COMMAND_DONE;
1199 1199 if (scmd->uscsi_flags & USCSI_DIAGNOSE) {
1200 1200 ssc->ses_retries = SES_NO_RETRY;
1201 1201 }
1202 1202
1203 1203 CHECK_PKT:
1204 1204 if (pkt->pkt_reason != CMD_CMPLT) {
1205 1205 /* Process transport errors. */
1206 1206 switch (pkt->pkt_reason) {
1207 1207 case CMD_TIMEOUT:
1208 1208 /*
1209 1209 * If the transport layer didn't clear the problem,
1210 1210 * reset the target.
1211 1211 */
1212 1212 if (! (pkt->pkt_statistics & HBA_RESET)) {
1213 1213 (void) scsi_reset(&pkt->pkt_address,
1214 1214 RESET_TARGET);
1215 1215 }
1216 1216 err = ETIMEDOUT;
1217 1217 break;
1218 1218
1219 1219 case CMD_INCOMPLETE:
1220 1220 case CMD_UNX_BUS_FREE:
1221 1221 /*
1222 1222 * No response? If probing, give up.
1223 1223 * Otherwise, keep trying until retries exhausted.
1224 1224 * Then lockdown the driver as the device is
1225 1225 * unplugged.
1226 1226 */
1227 1227 if (ssc->ses_retries <= SES_NO_RETRY &&
1228 1228 !(scmd->uscsi_flags & USCSI_DIAGNOSE)) {
1229 1229 ssc->ses_present = SES_CLOSED;
1230 1230 }
1231 1231 /* Inhibit retries to speed probe/attach. */
1232 1232 if (ssc->ses_present < SES_OPEN) {
1233 1233 ssc->ses_retries = SES_NO_RETRY;
1234 1234 }
1235 1235 /* SES_CMD_RETRY4(ssc->ses_retries); */
1236 1236 err = ENXIO;
1237 1237 break;
1238 1238
1239 1239 case CMD_DATA_OVR:
1240 1240 /*
1241 1241 * XXX: Some HBA's (e.g. Adaptec 1740 and
1242 1242 * earlier ISP revs) report a DATA OVERRUN
1243 1243 * error instead of a transfer residue. So,
1244 1244 * we convert the error and restart.
1245 1245 */
1246 1246 if ((bp->b_bcount - pkt->pkt_resid) > 0) {
1247 1247 SES_LOG(ssc, SES_CE_DEBUG6,
1248 1248 "ignoring overrun");
1249 1249 pkt->pkt_reason = CMD_CMPLT;
1250 1250 err = EOK;
1251 1251 goto CHECK_PKT;
1252 1252 }
1253 1253 ssc->ses_retries = SES_NO_RETRY;
1254 1254 /* err = EIO; */
1255 1255 break;
1256 1256
1257 1257 case CMD_DMA_DERR:
1258 1258 ssc->ses_retries = SES_NO_RETRY;
1259 1259 err = EFAULT;
1260 1260 break;
1261 1261
1262 1262 default:
1263 1263 /* err = EIO; */
1264 1264 break;
1265 1265 }
1266 1266 if (pkt == ssc->ses_rqpkt) {
1267 1267 SES_LOG(ssc, CE_WARN, fail_msg,
1268 1268 "Request Sense ",
1269 1269 scsi_rname(pkt->pkt_reason),
1270 1270 (ssc->ses_retries > 0)?
1271 1271 "retrying": "giving up");
1272 1272 pkt = (struct scsi_pkt *)bp->av_back;
1273 1273 action = QUE_SENSE;
1274 1274 } else {
1275 1275 SES_LOG(ssc, CE_WARN, fail_msg,
1276 1276 "", scsi_rname(pkt->pkt_reason),
1277 1277 (ssc->ses_retries > 0)?
1278 1278 "retrying": "giving up");
1279 1279 action = QUE_COMMAND;
1280 1280 }
1281 1281 /* Device exists, allow full error recovery. */
1282 1282 if (ssc->ses_retries > SES_NO_RETRY) {
1283 1283 ssc->ses_present = SES_OPEN;
1284 1284 }
1285 1285
1286 1286
1287 1287 /*
1288 1288 * Process status and sense data errors.
1289 1289 */
1290 1290 } else {
1291 1291 ssc->ses_present = SES_OPEN;
1292 1292 action = ses_decode_sense(pkt, &err);
1293 1293 }
1294 1294
1295 1295
1296 1296 /*
1297 1297 * Initiate error recovery action, as needed.
1298 1298 */
1299 1299 switch (action) {
1300 1300 case QUE_COMMAND_NOW:
1301 1301 /* SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd now"); */
1302 1302 if (ssc->ses_retries > SES_NO_RETRY) {
1303 1303 ssc->ses_retries -= SES_CMD_RETRY;
1304 1304 scmd->uscsi_status = 0;
1305 1305 if (ssc->ses_arq)
1306 1306 bzero(pkt->pkt_scbp,
1307 1307 sizeof (struct scsi_arq_status));
1308 1308
1309 1309 if (scsi_transport((struct scsi_pkt *)bp->av_back)
1310 1310 != TRAN_ACCEPT) {
1311 1311 SES_ENABLE_RESTART(SES_RESTART_TIME,
1312 1312 (struct scsi_pkt *)bp->av_back);
1313 1313 }
1314 1314 return;
1315 1315 }
1316 1316 break;
1317 1317
1318 1318 case QUE_COMMAND:
1319 1319 SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd");
1320 1320 if (ssc->ses_retries > SES_NO_RETRY) {
1321 1321 ssc->ses_retries -=
1322 1322 (err == EBUSY)? SES_BUSY_RETRY: SES_CMD_RETRY;
1323 1323 scmd->uscsi_status = 0;
1324 1324 if (ssc->ses_arq)
1325 1325 bzero(pkt->pkt_scbp,
1326 1326 sizeof (struct scsi_arq_status));
1327 1327
1328 1328 SES_ENABLE_RESTART(
1329 1329 (err == EBUSY)? SES_BUSY_TIME: SES_RESTART_TIME,
1330 1330 (struct scsi_pkt *)bp->av_back);
1331 1331 return;
1332 1332 }
1333 1333 break;
1334 1334
1335 1335 case QUE_SENSE:
1336 1336 SES_LOG(ssc, SES_CE_DEBUG1, "retrying sense");
1337 1337 if (ssc->ses_retries > SES_NO_RETRY) {
1338 1338 ssc->ses_retries -= SES_SENSE_RETRY;
1339 1339 scmd->uscsi_status = 0;
1340 1340 bzero(&ssc->ses_srqsbuf, MAX_SENSE_LENGTH);
1341 1341
1342 1342 if (scsi_transport(ssc->ses_rqpkt) != TRAN_ACCEPT) {
1343 1343 SES_ENABLE_RESTART(SES_RESTART_TIME,
1344 1344 ssc->ses_rqpkt);
1345 1345 }
1346 1346 return;
1347 1347 }
1348 1348 break;
1349 1349
1350 1350 case COMMAND_DONE:
1351 1351 SES_LOG(ssc, SES_CE_DEBUG4, "cmd done");
1352 1352 pkt = (struct scsi_pkt *)bp->av_back;
1353 1353 bp->b_resid = pkt->pkt_resid;
1354 1354 if (bp->b_resid) {
1355 1355 SES_LOG(ssc, SES_CE_DEBUG6,
1356 1356 "transfer residue %ld(%ld)",
1357 1357 bp->b_bcount - bp->b_resid, bp->b_bcount);
1358 1358 }
1359 1359 break;
1360 1360 }
1361 1361 pkt = (struct scsi_pkt *)bp->av_back;
1362 1362 if (err) {
1363 1363 SES_LOG(ssc, SES_CE_DEBUG1, "SES: ERROR %d\n", err);
1364 1364 SET_BP_ERROR(bp, err);
1365 1365 bp->b_resid = bp->b_bcount;
1366 1366 }
1367 1367 scsi_destroy_pkt(pkt);
1368 1368 SET_BP_PKT(bp, NULL);
1369 1369 biodone(bp);
1370 1370 }
1371 1371
1372 1372
1373 1373 /*
1374 1374 * Check status and sense data and determine recovery.
1375 1375 */
1376 1376 static int
1377 1377 ses_decode_sense(struct scsi_pkt *pkt, int *err)
1378 1378 {
1379 1379 ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
1380 1380 struct scsi_extended_sense *sense =
1381 1381 (struct scsi_extended_sense *)&ssc->ses_srqsbuf;
1382 1382 Uscmd *scmd = &ssc->ses_uscsicmd;
1383 1383 char sense_flag = 0;
1384 1384 uchar_t status = SCBP_C(pkt) & STATUS_MASK;
1385 1385 char *err_action;
1386 1386 char action;
1387 1387 uchar_t rqlen;
1388 1388 int amt;
1389 1389
1390 1390 /*
1391 1391 * Process manual request sense.
1392 1392 * Copy manual request sense to sense buffer.
1393 1393 *
1394 1394 * This is done if auto request sense is not enabled.
1395 1395 * Or the auto request sense failed and the request
1396 1396 * sense needs to be retried.
1397 1397 */
1398 1398 if (pkt->pkt_flags & FLAG_SENSING) {
1399 1399 struct buf *sbp = ssc->ses_rqbp;
1400 1400 amt = min(MAX_SENSE_LENGTH,
1401 1401 sbp->b_bcount - sbp->b_resid);
1402 1402 rqlen = min((uchar_t)amt, scmd->uscsi_rqlen);
1403 1403 bcopy(sbp->b_un.b_addr, sense, rqlen);
1404 1404 scmd->uscsi_rqresid = scmd->uscsi_rqlen - rqlen;
1405 1405 sense_flag = 1;
1406 1406 /*
1407 1407 * Process auto request sense.
1408 1408 * Copy auto request sense to sense buffer.
1409 1409 *
1410 1410 * If auto request sense failed due to transport error,
1411 1411 * retry the command. Otherwise process the status and
1412 1412 * sense data.
1413 1413 */
1414 1414 } else if (ssc->ses_arq && pkt->pkt_state & STATE_ARQ_DONE) {
1415 1415 struct scsi_arq_status *arq =
1416 1416 (struct scsi_arq_status *)(pkt->pkt_scbp);
1417 1417 uchar_t *arq_status = (uchar_t *)&arq->sts_rqpkt_status;
1418 1418 if (pkt->pkt_state & STATE_XARQ_DONE) {
1419 1419 amt = MAX_SENSE_LENGTH - arq->sts_rqpkt_resid;
1420 1420 } else {
1421 1421 if (arq->sts_rqpkt_resid > SENSE_LENGTH) {
1422 1422 amt = MAX_SENSE_LENGTH - arq->sts_rqpkt_resid;
1423 1423 } else {
1424 1424 amt = SENSE_LENGTH - arq->sts_rqpkt_resid;
1425 1425 }
1426 1426 }
1427 1427
1428 1428 if (arq->sts_rqpkt_reason != CMD_CMPLT) {
1429 1429 return (QUE_COMMAND);
1430 1430 }
1431 1431
1432 1432 rqlen = min((uchar_t)amt, scmd->uscsi_rqlen);
1433 1433 bcopy(&arq->sts_sensedata, sense, rqlen);
1434 1434 scmd->uscsi_status = status;
1435 1435 scmd->uscsi_rqresid = scmd->uscsi_rqlen - rqlen;
1436 1436 status = *arq_status & STATUS_MASK;
1437 1437 pkt->pkt_state &= ~STATE_ARQ_DONE;
1438 1438 sense_flag = 1;
1439 1439 }
1440 1440
1441 1441
1442 1442 /*
1443 1443 * Check status of REQUEST SENSE or command.
1444 1444 *
1445 1445 * If it's not successful, try retrying the original command
1446 1446 * and hope that it goes away. If not, we'll eventually run
1447 1447 * out of retries and die.
1448 1448 */
1449 1449 switch (status) {
1450 1450 case STATUS_GOOD:
1451 1451 case STATUS_INTERMEDIATE:
1452 1452 case STATUS_MET:
1453 1453 /*
1454 1454 * If the command status is ok, we're done.
1455 1455 * Otherwise, examine the request sense data.
1456 1456 */
1457 1457 if (! sense_flag) {
1458 1458 *err = EOK;
1459 1459 return (COMMAND_DONE);
1460 1460 }
1461 1461 break;
1462 1462
1463 1463 case STATUS_CHECK:
1464 1464 SES_LOG(ssc, SES_CE_DEBUG3, "status decode: check");
1465 1465 *err = EIO;
1466 1466 return (QUE_SENSE);
1467 1467 /* break; */
1468 1468
1469 1469 case STATUS_BUSY:
1470 1470 SES_LOG(ssc, SES_CE_DEBUG1, "status decode: busy");
1471 1471 /* SES_CMD_RETRY2(ssc->ses_retries); */
1472 1472 *err = EBUSY;
1473 1473 return (QUE_COMMAND);
1474 1474 /* break; */
1475 1475
1476 1476 case STATUS_RESERVATION_CONFLICT:
1477 1477 SES_LOG(ssc, SES_CE_DEBUG1, "status decode: reserved");
1478 1478 *err = EACCES;
1479 1479 return (COMMAND_DONE_ERROR);
1480 1480 /* break; */
1481 1481
1482 1482 case STATUS_TERMINATED:
1483 1483 SES_LOG(ssc, SES_CE_DEBUG1, "status decode: terminated");
1484 1484 *err = ECANCELED;
1485 1485 return (COMMAND_DONE_ERROR);
1486 1486 /* break; */
1487 1487
1488 1488 default:
1489 1489 SES_LOG(ssc, SES_CE_DEBUG1, "status 0x%x", status);
1490 1490 *err = EIO;
1491 1491 return (QUE_COMMAND);
1492 1492 /* break; */
1493 1493 }
1494 1494
1495 1495
1496 1496 /*
1497 1497 * Check REQUEST SENSE error code.
1498 1498 *
1499 1499 * Either there's no error, a retryable error,
1500 1500 * or it's dead. SES devices aren't very complex.
1501 1501 */
1502 1502 err_action = "retrying";
1503 1503 switch (sense->es_key) {
1504 1504 case KEY_RECOVERABLE_ERROR:
1505 1505 *err = EOK;
1506 1506 err_action = "recovered";
1507 1507 action = COMMAND_DONE;
1508 1508 break;
1509 1509
1510 1510 case KEY_UNIT_ATTENTION:
1511 1511 /*
1512 1512 * This is common for RAID!
1513 1513 */
1514 1514 /* *err = EIO; */
1515 1515 SES_CMD_RETRY1(ssc->ses_retries);
1516 1516 action = QUE_COMMAND_NOW;
1517 1517 break;
1518 1518
1519 1519 case KEY_NOT_READY:
1520 1520 case KEY_NO_SENSE:
1521 1521 /* *err = EIO; */
1522 1522 action = QUE_COMMAND;
1523 1523 break;
1524 1524
1525 1525 default:
1526 1526 /* *err = EIO; */
1527 1527 err_action = "fatal";
1528 1528 action = COMMAND_DONE_ERROR;
1529 1529 break;
1530 1530 }
1531 1531 SES_LOG(ssc, SES_CE_DEBUG1,
1532 1532 "cdb[0]= 0x%x %s, key=0x%x, ASC/ASCQ=0x%x/0x%x",
1533 1533 scmd->uscsi_cdb[0], err_action,
1534 1534 sense->es_key, sense->es_add_code, sense->es_qual_code);
1535 1535
1536 1536 #ifdef not
1537 1537 /*
1538 1538 * Dump cdb and sense data stat's for manufacturing.
1539 1539 */
1540 1540 if (DEBUGGING_ERR || sd_error_level == SDERR_ALL) {
1541 1541 auto buf[128];
1542 1542
1543 1543 p = pkt->pkt_cdbp;
1544 1544 if ((j = scsi_cdb_size[CDB_GROUPID(*p)]) == 0)
1545 1545 j = CDB_SIZE;
1546 1546
1547 1547 /* Print cdb */
1548 1548 (void) sprintf(buf, "cmd:");
1549 1549 for (i = 0; i < j; i++) {
1550 1550 (void) sprintf(&buf[strlen(buf)],
1551 1551 hex, (uchar_t)*p++);
1552 1552 }
1553 1553 SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
1554 1554
1555 1555 /* Suppress trailing zero's in sense data */
1556 1556 if (amt > 3) {
1557 1557 p = (char *)devp->sd_sense + amt;
1558 1558 for (j = amt; j > 3; j--) {
1559 1559 if (*(--p)) break;
1560 1560 }
1561 1561 } else {
1562 1562 j = amt;
1563 1563 }
1564 1564
1565 1565 /* Print sense data. */
1566 1566 (void) sprintf(buf, "sense:");
1567 1567 p = (char *)devp->sd_sense;
1568 1568 for (i = 0; i < j; i++) {
1569 1569 (void) sprintf(&buf[strlen(buf)],
1570 1570 hex, (uchar_t)*p++);
1571 1571 }
1572 1572 SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
1573 1573 }
1574 1574 #endif /* not */
1575 1575 return (action);
1576 1576 }
1577 1577
1578 1578
1579 1579 /*PRINTFLIKE3*/
1580 1580 void
1581 1581 ses_log(ses_softc_t *ssc, int level, const char *fmt, ...)
1582 1582 {
1583 1583 va_list ap;
1584 1584 char buf[256];
1585 1585
1586 1586 va_start(ap, fmt);
1587 1587 (void) vsprintf(buf, fmt, ap);
1588 1588 va_end(ap);
1589 1589
1590 1590 if (ssc == (ses_softc_t *)NULL) {
1591 1591 switch (level) {
1592 1592 case SES_CE_DEBUG1:
1593 1593 if (ses_debug > 1)
1594 1594 cmn_err(CE_NOTE, "%s", buf);
1595 1595 break;
1596 1596 case SES_CE_DEBUG2:
1597 1597 if (ses_debug > 2)
1598 1598 cmn_err(CE_NOTE, "%s", buf);
1599 1599 break;
1600 1600 case SES_CE_DEBUG3:
1601 1601 if (ses_debug > 3)
1602 1602 cmn_err(CE_NOTE, "%s", buf);
1603 1603 break;
1604 1604 case SES_CE_DEBUG4:
1605 1605 if (ses_debug > 4)
1606 1606 cmn_err(CE_NOTE, "%s", buf);
1607 1607 break;
1608 1608 case SES_CE_DEBUG5:
1609 1609 if (ses_debug > 5)
1610 1610 cmn_err(CE_NOTE, "%s", buf);
1611 1611 break;
1612 1612 case SES_CE_DEBUG6:
1613 1613 if (ses_debug > 6)
1614 1614 cmn_err(CE_NOTE, "%s", buf);
1615 1615 break;
1616 1616 case SES_CE_DEBUG7:
1617 1617 if (ses_debug > 7)
1618 1618 cmn_err(CE_NOTE, "%s", buf);
1619 1619 break;
1620 1620 case SES_CE_DEBUG8:
1621 1621 if (ses_debug > 8)
1622 1622 cmn_err(CE_NOTE, "%s", buf);
1623 1623 break;
1624 1624 case SES_CE_DEBUG9:
1625 1625 if (ses_debug > 9)
1626 1626 cmn_err(CE_NOTE, "%s", buf);
1627 1627 break;
1628 1628 case CE_NOTE:
1629 1629 case CE_WARN:
1630 1630 case CE_PANIC:
1631 1631 cmn_err(level, "%s", buf);
1632 1632 break;
1633 1633 case SES_CE_DEBUG:
1634 1634 default:
1635 1635 cmn_err(CE_NOTE, "%s", buf);
1636 1636 break;
1637 1637 }
1638 1638 return;
1639 1639 }
1640 1640
1641 1641 switch (level) {
1642 1642 case CE_CONT:
1643 1643 case CE_NOTE:
1644 1644 case CE_WARN:
1645 1645 case CE_PANIC:
1646 1646 scsi_log(SES_DEVINFO(ssc), (char *)Snm, level, Str, buf);
1647 1647 break;
1648 1648 case SES_CE_DEBUG1:
1649 1649 if (ses_debug > 1)
1650 1650 scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1651 1651 Str, buf);
1652 1652 break;
1653 1653 case SES_CE_DEBUG2:
1654 1654 if (ses_debug > 2)
1655 1655 scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1656 1656 Str, buf);
1657 1657 break;
1658 1658 case SES_CE_DEBUG3:
1659 1659 if (ses_debug > 3)
1660 1660 scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1661 1661 Str, buf);
1662 1662 break;
1663 1663 case SES_CE_DEBUG4:
1664 1664 if (ses_debug > 4)
1665 1665 scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1666 1666 Str, buf);
1667 1667 break;
1668 1668 case SES_CE_DEBUG5:
1669 1669 if (ses_debug > 5)
1670 1670 scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1671 1671 Str, buf);
1672 1672 break;
1673 1673 case SES_CE_DEBUG6:
1674 1674 if (ses_debug > 6)
1675 1675 scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1676 1676 Str, buf);
1677 1677 break;
1678 1678 case SES_CE_DEBUG7:
1679 1679 if (ses_debug > 7)
1680 1680 scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1681 1681 Str, buf);
1682 1682 break;
1683 1683 case SES_CE_DEBUG8:
1684 1684 if (ses_debug > 8)
1685 1685 scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1686 1686 Str, buf);
1687 1687 break;
1688 1688 case SES_CE_DEBUG9:
1689 1689 if (ses_debug > 9)
1690 1690 scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1691 1691 Str, buf);
1692 1692 break;
1693 1693 case SES_CE_DEBUG:
1694 1694 default:
1695 1695 scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, Str, buf);
1696 1696 break;
1697 1697 }
1698 1698 }
1699 1699 /*
1700 1700 * mode: c
1701 1701 * Local variables:
1702 1702 * c-indent-level: 8
1703 1703 * c-brace-imaginary-offset: 0
1704 1704 * c-brace-offset: -8
1705 1705 * c-argdecl-indent: 8
1706 1706 * c-label-offset: -8
1707 1707 * c-continued-statement-offset: 8
1708 1708 * c-continued-brace-offset: 0
1709 1709 * End:
1710 1710 */
↓ open down ↓ |
1508 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX