Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cam/scsi/scsi_ch.c
39478 views
1
/*-
2
* SPDX-License-Identifier: (BSD-2-Clause AND BSD-4-Clause)
3
*
4
* Copyright (c) 1997 Justin T. Gibbs.
5
* Copyright (c) 1997, 1998, 1999 Kenneth D. Merry.
6
* All rights reserved.
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, this list of conditions, and the following disclaimer,
13
* without modification, immediately at the beginning of the file.
14
* 2. The name of the author may not be used to endorse or promote products
15
* derived from this software without specific prior written permission.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
/*-
31
* Copyright (c) 1996, 1997 Jason R. Thorpe <[email protected]>
32
* All rights reserved.
33
*
34
* Partially based on an autochanger driver written by Stefan Grefen
35
* and on an autochanger driver written by the Systems Programming Group
36
* at the University of Utah Computer Science Department.
37
*
38
* Redistribution and use in source and binary forms, with or without
39
* modification, are permitted provided that the following conditions
40
* are met:
41
* 1. Redistributions of source code must retain the above copyright
42
* notice, this list of conditions and the following disclaimer.
43
* 2. Redistributions in binary form must reproduce the above copyright
44
* notice, this list of conditions and the following disclaimer in the
45
* documentation and/or other materials provided with the distribution.
46
* 3. All advertising materials mentioning features or use of this software
47
* must display the following acknowledgements:
48
* This product includes software developed by Jason R. Thorpe
49
* for And Communications, http://www.and.com/
50
* 4. The name of the author may not be used to endorse or promote products
51
* derived from this software without specific prior written permission.
52
*
53
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
54
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
55
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
56
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
57
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
58
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
59
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
60
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
61
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63
* SUCH DAMAGE.
64
*
65
* $NetBSD: ch.c,v 1.34 1998/08/31 22:28:06 cgd Exp $
66
*/
67
68
#include <sys/param.h>
69
#include <sys/queue.h>
70
#include <sys/systm.h>
71
#include <sys/kernel.h>
72
#include <sys/types.h>
73
#include <sys/malloc.h>
74
#include <sys/fcntl.h>
75
#include <sys/conf.h>
76
#include <sys/chio.h>
77
#include <sys/errno.h>
78
#include <sys/devicestat.h>
79
80
#include <cam/cam.h>
81
#include <cam/cam_ccb.h>
82
#include <cam/cam_periph.h>
83
#include <cam/cam_xpt_periph.h>
84
#include <cam/cam_debug.h>
85
86
#include <cam/scsi/scsi_all.h>
87
#include <cam/scsi/scsi_message.h>
88
#include <cam/scsi/scsi_ch.h>
89
90
/*
91
* Timeout definitions for various changer related commands. They may
92
* be too short for some devices (especially the timeout for INITIALIZE
93
* ELEMENT STATUS).
94
*/
95
96
static const uint32_t CH_TIMEOUT_MODE_SENSE = 6000;
97
static const uint32_t CH_TIMEOUT_MOVE_MEDIUM = 15 * 60 * 1000;
98
static const uint32_t CH_TIMEOUT_EXCHANGE_MEDIUM = 15 * 60 * 1000;
99
static const uint32_t CH_TIMEOUT_POSITION_TO_ELEMENT = 15 * 60 * 1000;
100
static const uint32_t CH_TIMEOUT_READ_ELEMENT_STATUS = 5 * 60 * 1000;
101
static const uint32_t CH_TIMEOUT_SEND_VOLTAG = 10000;
102
static const uint32_t CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS = 500000;
103
104
typedef enum {
105
CH_FLAG_INVALID = 0x001
106
} ch_flags;
107
108
typedef enum {
109
CH_STATE_PROBE,
110
CH_STATE_NORMAL
111
} ch_state;
112
113
typedef enum {
114
CH_CCB_PROBE
115
} ch_ccb_types;
116
117
typedef enum {
118
CH_Q_NONE = 0x00,
119
CH_Q_NO_DBD = 0x01,
120
CH_Q_NO_DVCID = 0x02
121
} ch_quirks;
122
123
#define CH_Q_BIT_STRING \
124
"\020" \
125
"\001NO_DBD" \
126
"\002NO_DVCID"
127
128
#define ccb_state ppriv_field0
129
#define ccb_bp ppriv_ptr1
130
131
struct scsi_mode_sense_data {
132
struct scsi_mode_header_6 header;
133
struct scsi_mode_blk_desc blk_desc;
134
union {
135
struct page_element_address_assignment ea;
136
struct page_transport_geometry_parameters tg;
137
struct page_device_capabilities cap;
138
} pages;
139
};
140
141
struct ch_softc {
142
ch_flags flags;
143
ch_state state;
144
ch_quirks quirks;
145
struct devstat *device_stats;
146
struct cdev *dev;
147
int open_count;
148
149
int sc_picker; /* current picker */
150
151
/*
152
* The following information is obtained from the
153
* element address assignment page.
154
*/
155
int sc_firsts[CHET_MAX + 1]; /* firsts */
156
int sc_counts[CHET_MAX + 1]; /* counts */
157
158
/*
159
* The following mask defines the legal combinations
160
* of elements for the MOVE MEDIUM command.
161
*/
162
uint8_t sc_movemask[CHET_MAX + 1];
163
164
/*
165
* As above, but for EXCHANGE MEDIUM.
166
*/
167
uint8_t sc_exchangemask[CHET_MAX + 1];
168
169
/*
170
* Quirks; see below. XXX KDM not implemented yet
171
*/
172
int sc_settledelay; /* delay for settle */
173
};
174
175
static d_open_t chopen;
176
static d_close_t chclose;
177
static d_ioctl_t chioctl;
178
static periph_init_t chinit;
179
static periph_ctor_t chregister;
180
static periph_oninv_t choninvalidate;
181
static periph_dtor_t chcleanup;
182
static periph_start_t chstart;
183
static void chasync(void *callback_arg, uint32_t code,
184
struct cam_path *path, void *arg);
185
static void chdone(struct cam_periph *periph,
186
union ccb *done_ccb);
187
static int cherror(union ccb *ccb, uint32_t cam_flags,
188
uint32_t sense_flags);
189
static int chmove(struct cam_periph *periph,
190
struct changer_move *cm);
191
static int chexchange(struct cam_periph *periph,
192
struct changer_exchange *ce);
193
static int chposition(struct cam_periph *periph,
194
struct changer_position *cp);
195
static int chgetelemstatus(struct cam_periph *periph,
196
int scsi_version, u_long cmd,
197
struct changer_element_status_request *csr);
198
static int chsetvoltag(struct cam_periph *periph,
199
struct changer_set_voltag_request *csvr);
200
static int chielem(struct cam_periph *periph,
201
unsigned int timeout);
202
static int chgetparams(struct cam_periph *periph);
203
static int chscsiversion(struct cam_periph *periph);
204
205
static struct periph_driver chdriver =
206
{
207
chinit, "ch",
208
TAILQ_HEAD_INITIALIZER(chdriver.units), /* generation */ 0
209
};
210
211
PERIPHDRIVER_DECLARE(ch, chdriver);
212
213
static struct cdevsw ch_cdevsw = {
214
.d_version = D_VERSION,
215
.d_flags = D_TRACKCLOSE,
216
.d_open = chopen,
217
.d_close = chclose,
218
.d_ioctl = chioctl,
219
.d_name = "ch",
220
};
221
222
static MALLOC_DEFINE(M_SCSICH, "scsi_ch", "scsi_ch buffers");
223
224
static void
225
chinit(void)
226
{
227
cam_status status;
228
229
/*
230
* Install a global async callback. This callback will
231
* receive async callbacks like "new device found".
232
*/
233
status = xpt_register_async(AC_FOUND_DEVICE, chasync, NULL, NULL);
234
235
if (status != CAM_REQ_CMP) {
236
printf("ch: Failed to attach master async callback "
237
"due to status 0x%x!\n", status);
238
}
239
}
240
241
static void
242
chdevgonecb(void *arg)
243
{
244
struct ch_softc *softc;
245
struct cam_periph *periph;
246
struct mtx *mtx;
247
int i;
248
249
periph = (struct cam_periph *)arg;
250
mtx = cam_periph_mtx(periph);
251
mtx_lock(mtx);
252
253
softc = (struct ch_softc *)periph->softc;
254
KASSERT(softc->open_count >= 0, ("Negative open count %d",
255
softc->open_count));
256
257
/*
258
* When we get this callback, we will get no more close calls from
259
* devfs. So if we have any dangling opens, we need to release the
260
* reference held for that particular context.
261
*/
262
for (i = 0; i < softc->open_count; i++)
263
cam_periph_release_locked(periph);
264
265
softc->open_count = 0;
266
267
/*
268
* Release the reference held for the device node, it is gone now.
269
*/
270
cam_periph_release_locked(periph);
271
272
/*
273
* We reference the lock directly here, instead of using
274
* cam_periph_unlock(). The reason is that the final call to
275
* cam_periph_release_locked() above could result in the periph
276
* getting freed. If that is the case, dereferencing the periph
277
* with a cam_periph_unlock() call would cause a page fault.
278
*/
279
mtx_unlock(mtx);
280
}
281
282
static void
283
choninvalidate(struct cam_periph *periph)
284
{
285
struct ch_softc *softc;
286
287
softc = (struct ch_softc *)periph->softc;
288
289
/*
290
* De-register any async callbacks.
291
*/
292
xpt_register_async(0, chasync, periph, periph->path);
293
294
softc->flags |= CH_FLAG_INVALID;
295
296
/*
297
* Tell devfs this device has gone away, and ask for a callback
298
* when it has cleaned up its state.
299
*/
300
destroy_dev_sched_cb(softc->dev, chdevgonecb, periph);
301
}
302
303
static void
304
chcleanup(struct cam_periph *periph)
305
{
306
struct ch_softc *softc;
307
308
softc = (struct ch_softc *)periph->softc;
309
310
devstat_remove_entry(softc->device_stats);
311
312
free(softc, M_DEVBUF);
313
}
314
315
static void
316
chasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
317
{
318
struct cam_periph *periph;
319
320
periph = (struct cam_periph *)callback_arg;
321
322
switch(code) {
323
case AC_FOUND_DEVICE:
324
{
325
struct ccb_getdev *cgd;
326
cam_status status;
327
328
cgd = (struct ccb_getdev *)arg;
329
if (cgd == NULL)
330
break;
331
332
if (cgd->protocol != PROTO_SCSI)
333
break;
334
if (SID_QUAL(&cgd->inq_data) != SID_QUAL_LU_CONNECTED)
335
break;
336
if (SID_TYPE(&cgd->inq_data)!= T_CHANGER)
337
break;
338
339
/*
340
* Allocate a peripheral instance for
341
* this device and start the probe
342
* process.
343
*/
344
status = cam_periph_alloc(chregister, choninvalidate,
345
chcleanup, chstart, "ch",
346
CAM_PERIPH_BIO, path,
347
chasync, AC_FOUND_DEVICE, cgd);
348
349
if (status != CAM_REQ_CMP
350
&& status != CAM_REQ_INPROG)
351
printf("chasync: Unable to probe new device "
352
"due to status 0x%x\n", status);
353
354
break;
355
}
356
default:
357
cam_periph_async(periph, code, path, arg);
358
break;
359
}
360
}
361
362
static cam_status
363
chregister(struct cam_periph *periph, void *arg)
364
{
365
struct ch_softc *softc;
366
struct ccb_getdev *cgd;
367
struct ccb_pathinq cpi;
368
struct make_dev_args args;
369
int error;
370
371
cgd = (struct ccb_getdev *)arg;
372
if (cgd == NULL) {
373
printf("chregister: no getdev CCB, can't register device\n");
374
return(CAM_REQ_CMP_ERR);
375
}
376
377
softc = (struct ch_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
378
379
if (softc == NULL) {
380
printf("chregister: Unable to probe new device. "
381
"Unable to allocate softc\n");
382
return(CAM_REQ_CMP_ERR);
383
}
384
385
bzero(softc, sizeof(*softc));
386
softc->state = CH_STATE_PROBE;
387
periph->softc = softc;
388
softc->quirks = CH_Q_NONE;
389
390
/*
391
* The DVCID and CURDATA bits were not introduced until the SMC
392
* spec. If this device claims SCSI-2 or earlier support, then it
393
* very likely does not support these bits.
394
*/
395
if (cgd->inq_data.version <= SCSI_REV_2)
396
softc->quirks |= CH_Q_NO_DVCID;
397
398
xpt_path_inq(&cpi, periph->path);
399
400
/*
401
* Changers don't have a blocksize, and obviously don't support
402
* tagged queueing.
403
*/
404
cam_periph_unlock(periph);
405
softc->device_stats = devstat_new_entry("ch",
406
periph->unit_number, 0,
407
DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS,
408
SID_TYPE(&cgd->inq_data) |
409
XPORT_DEVSTAT_TYPE(cpi.transport),
410
DEVSTAT_PRIORITY_OTHER);
411
412
/*
413
* Acquire a reference to the periph before we create the devfs
414
* instance for it. We'll release this reference once the devfs
415
* instance has been freed.
416
*/
417
if (cam_periph_acquire(periph) != 0) {
418
xpt_print(periph->path, "%s: lost periph during "
419
"registration!\n", __func__);
420
cam_periph_lock(periph);
421
return (CAM_REQ_CMP_ERR);
422
}
423
424
/* Register the device */
425
make_dev_args_init(&args);
426
args.mda_devsw = &ch_cdevsw;
427
args.mda_unit = periph->unit_number;
428
args.mda_uid = UID_ROOT;
429
args.mda_gid = GID_OPERATOR;
430
args.mda_mode = 0600;
431
args.mda_si_drv1 = periph;
432
error = make_dev_s(&args, &softc->dev, "%s%d", periph->periph_name,
433
periph->unit_number);
434
cam_periph_lock(periph);
435
if (error != 0) {
436
cam_periph_release_locked(periph);
437
return (CAM_REQ_CMP_ERR);
438
}
439
440
/*
441
* Add an async callback so that we get
442
* notified if this device goes away.
443
*/
444
xpt_register_async(AC_LOST_DEVICE, chasync, periph, periph->path);
445
446
/*
447
* Lock this periph until we are setup.
448
* This first call can't block
449
*/
450
(void)cam_periph_hold(periph, PRIBIO);
451
xpt_schedule(periph, CAM_PRIORITY_DEV);
452
453
return(CAM_REQ_CMP);
454
}
455
456
static int
457
chopen(struct cdev *dev, int flags, int fmt, struct thread *td)
458
{
459
struct cam_periph *periph;
460
struct ch_softc *softc;
461
int error;
462
463
periph = (struct cam_periph *)dev->si_drv1;
464
if (cam_periph_acquire(periph) != 0)
465
return (ENXIO);
466
467
softc = (struct ch_softc *)periph->softc;
468
469
cam_periph_lock(periph);
470
471
if (softc->flags & CH_FLAG_INVALID) {
472
cam_periph_release_locked(periph);
473
cam_periph_unlock(periph);
474
return(ENXIO);
475
}
476
477
if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
478
cam_periph_unlock(periph);
479
cam_periph_release(periph);
480
return (error);
481
}
482
483
/*
484
* Load information about this changer device into the softc.
485
*/
486
if ((error = chgetparams(periph)) != 0) {
487
cam_periph_unhold(periph);
488
cam_periph_release_locked(periph);
489
cam_periph_unlock(periph);
490
return(error);
491
}
492
493
cam_periph_unhold(periph);
494
495
softc->open_count++;
496
497
cam_periph_unlock(periph);
498
499
return(error);
500
}
501
502
static int
503
chclose(struct cdev *dev, int flag, int fmt, struct thread *td)
504
{
505
struct cam_periph *periph;
506
struct ch_softc *softc;
507
struct mtx *mtx;
508
509
periph = (struct cam_periph *)dev->si_drv1;
510
mtx = cam_periph_mtx(periph);
511
mtx_lock(mtx);
512
513
softc = (struct ch_softc *)periph->softc;
514
softc->open_count--;
515
516
cam_periph_release_locked(periph);
517
518
/*
519
* We reference the lock directly here, instead of using
520
* cam_periph_unlock(). The reason is that the call to
521
* cam_periph_release_locked() above could result in the periph
522
* getting freed. If that is the case, dereferencing the periph
523
* with a cam_periph_unlock() call would cause a page fault.
524
*
525
* cam_periph_release() avoids this problem using the same method,
526
* but we're manually acquiring and dropping the lock here to
527
* protect the open count and avoid another lock acquisition and
528
* release.
529
*/
530
mtx_unlock(mtx);
531
532
return(0);
533
}
534
535
static void
536
chstart(struct cam_periph *periph, union ccb *start_ccb)
537
{
538
struct ch_softc *softc;
539
540
softc = (struct ch_softc *)periph->softc;
541
542
switch (softc->state) {
543
case CH_STATE_NORMAL:
544
{
545
xpt_release_ccb(start_ccb);
546
break;
547
}
548
case CH_STATE_PROBE:
549
{
550
int mode_buffer_len;
551
void *mode_buffer;
552
553
/*
554
* Include the block descriptor when calculating the mode
555
* buffer length,
556
*/
557
mode_buffer_len = sizeof(struct scsi_mode_header_6) +
558
sizeof(struct scsi_mode_blk_desc) +
559
sizeof(struct page_element_address_assignment);
560
561
mode_buffer = malloc(mode_buffer_len, M_SCSICH, M_NOWAIT);
562
563
if (mode_buffer == NULL) {
564
printf("chstart: couldn't malloc mode sense data\n");
565
break;
566
}
567
bzero(mode_buffer, mode_buffer_len);
568
569
/*
570
* Get the element address assignment page.
571
*/
572
scsi_mode_sense(&start_ccb->csio,
573
/* retries */ 1,
574
/* cbfcnp */ chdone,
575
/* tag_action */ MSG_SIMPLE_Q_TAG,
576
/* dbd */ (softc->quirks & CH_Q_NO_DBD) ?
577
FALSE : TRUE,
578
/* pc */ SMS_PAGE_CTRL_CURRENT,
579
/* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE,
580
/* param_buf */ (uint8_t *)mode_buffer,
581
/* param_len */ mode_buffer_len,
582
/* sense_len */ SSD_FULL_SIZE,
583
/* timeout */ CH_TIMEOUT_MODE_SENSE);
584
585
start_ccb->ccb_h.ccb_bp = NULL;
586
start_ccb->ccb_h.ccb_state = CH_CCB_PROBE;
587
xpt_action(start_ccb);
588
break;
589
}
590
}
591
}
592
593
static void
594
chdone(struct cam_periph *periph, union ccb *done_ccb)
595
{
596
struct ch_softc *softc;
597
struct ccb_scsiio *csio;
598
599
softc = (struct ch_softc *)periph->softc;
600
csio = &done_ccb->csio;
601
602
switch(done_ccb->ccb_h.ccb_state) {
603
case CH_CCB_PROBE:
604
{
605
struct scsi_mode_header_6 *mode_header;
606
struct page_element_address_assignment *ea;
607
char announce_buf[80];
608
609
mode_header = (struct scsi_mode_header_6 *)csio->data_ptr;
610
611
ea = (struct page_element_address_assignment *)
612
find_mode_page_6(mode_header);
613
614
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP){
615
616
softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea);
617
softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte);
618
softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea);
619
softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse);
620
softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea);
621
softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee);
622
softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea);
623
softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte);
624
softc->sc_picker = softc->sc_firsts[CHET_MT];
625
626
#define PLURAL(c) (c) == 1 ? "" : "s"
627
snprintf(announce_buf, sizeof(announce_buf),
628
"%d slot%s, %d drive%s, "
629
"%d picker%s, %d portal%s",
630
softc->sc_counts[CHET_ST],
631
PLURAL(softc->sc_counts[CHET_ST]),
632
softc->sc_counts[CHET_DT],
633
PLURAL(softc->sc_counts[CHET_DT]),
634
softc->sc_counts[CHET_MT],
635
PLURAL(softc->sc_counts[CHET_MT]),
636
softc->sc_counts[CHET_IE],
637
PLURAL(softc->sc_counts[CHET_IE]));
638
#undef PLURAL
639
if (announce_buf[0] != '\0') {
640
xpt_announce_periph(periph, announce_buf);
641
xpt_announce_quirks(periph, softc->quirks,
642
CH_Q_BIT_STRING);
643
}
644
} else {
645
int error;
646
647
error = cherror(done_ccb, CAM_RETRY_SELTO,
648
SF_RETRY_UA | SF_NO_PRINT);
649
/*
650
* Retry any UNIT ATTENTION type errors. They
651
* are expected at boot.
652
*/
653
if (error == ERESTART) {
654
/*
655
* A retry was scheduled, so
656
* just return.
657
*/
658
return;
659
} else if (error != 0) {
660
struct scsi_mode_sense_6 *sms;
661
int frozen, retry_scheduled;
662
663
sms = (struct scsi_mode_sense_6 *)
664
done_ccb->csio.cdb_io.cdb_bytes;
665
frozen = (done_ccb->ccb_h.status &
666
CAM_DEV_QFRZN) != 0;
667
668
/*
669
* Check to see if block descriptors were
670
* disabled. Some devices don't like that.
671
* We're taking advantage of the fact that
672
* the first few bytes of the 6 and 10 byte
673
* mode sense commands are the same. If
674
* block descriptors were disabled, enable
675
* them and re-send the command.
676
*/
677
if ((sms->byte2 & SMS_DBD) != 0 &&
678
(periph->flags & CAM_PERIPH_INVALID) == 0) {
679
sms->byte2 &= ~SMS_DBD;
680
xpt_action(done_ccb);
681
softc->quirks |= CH_Q_NO_DBD;
682
retry_scheduled = 1;
683
} else
684
retry_scheduled = 0;
685
686
/* Don't wedge this device's queue */
687
if (frozen)
688
cam_release_devq(done_ccb->ccb_h.path,
689
/*relsim_flags*/0,
690
/*reduction*/0,
691
/*timeout*/0,
692
/*getcount_only*/0);
693
694
if (retry_scheduled)
695
return;
696
697
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK)
698
== CAM_SCSI_STATUS_ERROR)
699
scsi_sense_print(&done_ccb->csio);
700
else {
701
xpt_print(periph->path,
702
"got CAM status %#x\n",
703
done_ccb->ccb_h.status);
704
}
705
xpt_print(periph->path, "fatal error, failed "
706
"to attach to device\n");
707
708
cam_periph_invalidate(periph);
709
}
710
}
711
softc->state = CH_STATE_NORMAL;
712
free(mode_header, M_SCSICH);
713
/*
714
* Since our peripheral may be invalidated by an error
715
* above or an external event, we must release our CCB
716
* before releasing the probe lock on the peripheral.
717
* The peripheral will only go away once the last lock
718
* is removed, and we need it around for the CCB release
719
* operation.
720
*/
721
xpt_release_ccb(done_ccb);
722
cam_periph_unhold(periph);
723
return;
724
}
725
default:
726
break;
727
}
728
xpt_release_ccb(done_ccb);
729
}
730
731
static int
732
cherror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
733
{
734
735
return (cam_periph_error(ccb, cam_flags, sense_flags));
736
}
737
738
static int
739
chioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
740
{
741
struct cam_periph *periph;
742
struct ch_softc *softc;
743
int error;
744
745
periph = (struct cam_periph *)dev->si_drv1;
746
cam_periph_lock(periph);
747
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering chioctl\n"));
748
749
softc = (struct ch_softc *)periph->softc;
750
751
error = 0;
752
753
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
754
("trying to do ioctl %#lx\n", cmd));
755
756
/*
757
* If this command can change the device's state, we must
758
* have the device open for writing.
759
*/
760
switch (cmd) {
761
case CHIOGPICKER:
762
case CHIOGPARAMS:
763
case OCHIOGSTATUS:
764
case CHIOGSTATUS:
765
break;
766
767
default:
768
if ((flag & FWRITE) == 0) {
769
cam_periph_unlock(periph);
770
return (EBADF);
771
}
772
}
773
774
switch (cmd) {
775
case CHIOMOVE:
776
error = chmove(periph, (struct changer_move *)addr);
777
break;
778
779
case CHIOEXCHANGE:
780
error = chexchange(periph, (struct changer_exchange *)addr);
781
break;
782
783
case CHIOPOSITION:
784
error = chposition(periph, (struct changer_position *)addr);
785
break;
786
787
case CHIOGPICKER:
788
*(int *)addr = softc->sc_picker - softc->sc_firsts[CHET_MT];
789
break;
790
791
case CHIOSPICKER:
792
{
793
int new_picker = *(int *)addr;
794
795
if (new_picker > (softc->sc_counts[CHET_MT] - 1)) {
796
error = EINVAL;
797
break;
798
}
799
softc->sc_picker = softc->sc_firsts[CHET_MT] + new_picker;
800
break;
801
}
802
case CHIOGPARAMS:
803
{
804
struct changer_params *cp = (struct changer_params *)addr;
805
806
cp->cp_npickers = softc->sc_counts[CHET_MT];
807
cp->cp_nslots = softc->sc_counts[CHET_ST];
808
cp->cp_nportals = softc->sc_counts[CHET_IE];
809
cp->cp_ndrives = softc->sc_counts[CHET_DT];
810
break;
811
}
812
case CHIOIELEM:
813
error = chielem(periph, *(unsigned int *)addr);
814
break;
815
816
case OCHIOGSTATUS:
817
{
818
error = chgetelemstatus(periph, SCSI_REV_2, cmd,
819
(struct changer_element_status_request *)addr);
820
break;
821
}
822
823
case CHIOGSTATUS:
824
{
825
int scsi_version;
826
827
scsi_version = chscsiversion(periph);
828
if (scsi_version >= SCSI_REV_0) {
829
error = chgetelemstatus(periph, scsi_version, cmd,
830
(struct changer_element_status_request *)addr);
831
}
832
else { /* unable to determine the SCSI version */
833
cam_periph_unlock(periph);
834
return (ENXIO);
835
}
836
break;
837
}
838
839
case CHIOSETVOLTAG:
840
{
841
error = chsetvoltag(periph,
842
(struct changer_set_voltag_request *) addr);
843
break;
844
}
845
846
/* Implement prevent/allow? */
847
848
default:
849
error = cam_periph_ioctl(periph, cmd, addr, cherror);
850
break;
851
}
852
853
cam_periph_unlock(periph);
854
return (error);
855
}
856
857
static int
858
chmove(struct cam_periph *periph, struct changer_move *cm)
859
{
860
struct ch_softc *softc;
861
uint16_t fromelem, toelem;
862
union ccb *ccb;
863
int error;
864
865
error = 0;
866
softc = (struct ch_softc *)periph->softc;
867
868
/*
869
* Check arguments.
870
*/
871
if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
872
return (EINVAL);
873
if ((cm->cm_fromunit > (softc->sc_counts[cm->cm_fromtype] - 1)) ||
874
(cm->cm_tounit > (softc->sc_counts[cm->cm_totype] - 1)))
875
return (ENODEV);
876
877
/*
878
* Check the request against the changer's capabilities.
879
*/
880
if ((softc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
881
return (ENODEV);
882
883
/*
884
* Calculate the source and destination elements.
885
*/
886
fromelem = softc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
887
toelem = softc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
888
889
ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
890
891
scsi_move_medium(&ccb->csio,
892
/* retries */ 1,
893
/* cbfcnp */ chdone,
894
/* tag_action */ MSG_SIMPLE_Q_TAG,
895
/* tea */ softc->sc_picker,
896
/* src */ fromelem,
897
/* dst */ toelem,
898
/* invert */ (cm->cm_flags & CM_INVERT) ? TRUE : FALSE,
899
/* sense_len */ SSD_FULL_SIZE,
900
/* timeout */ CH_TIMEOUT_MOVE_MEDIUM);
901
902
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO,
903
/*sense_flags*/ SF_RETRY_UA,
904
softc->device_stats);
905
906
xpt_release_ccb(ccb);
907
908
return(error);
909
}
910
911
static int
912
chexchange(struct cam_periph *periph, struct changer_exchange *ce)
913
{
914
struct ch_softc *softc;
915
uint16_t src, dst1, dst2;
916
union ccb *ccb;
917
int error;
918
919
error = 0;
920
softc = (struct ch_softc *)periph->softc;
921
/*
922
* Check arguments.
923
*/
924
if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
925
(ce->ce_sdsttype > CHET_DT))
926
return (EINVAL);
927
if ((ce->ce_srcunit > (softc->sc_counts[ce->ce_srctype] - 1)) ||
928
(ce->ce_fdstunit > (softc->sc_counts[ce->ce_fdsttype] - 1)) ||
929
(ce->ce_sdstunit > (softc->sc_counts[ce->ce_sdsttype] - 1)))
930
return (ENODEV);
931
932
/*
933
* Check the request against the changer's capabilities.
934
*/
935
if (((softc->sc_exchangemask[ce->ce_srctype] &
936
(1 << ce->ce_fdsttype)) == 0) ||
937
((softc->sc_exchangemask[ce->ce_fdsttype] &
938
(1 << ce->ce_sdsttype)) == 0))
939
return (ENODEV);
940
941
/*
942
* Calculate the source and destination elements.
943
*/
944
src = softc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
945
dst1 = softc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
946
dst2 = softc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
947
948
ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
949
950
scsi_exchange_medium(&ccb->csio,
951
/* retries */ 1,
952
/* cbfcnp */ chdone,
953
/* tag_action */ MSG_SIMPLE_Q_TAG,
954
/* tea */ softc->sc_picker,
955
/* src */ src,
956
/* dst1 */ dst1,
957
/* dst2 */ dst2,
958
/* invert1 */ (ce->ce_flags & CE_INVERT1) ?
959
TRUE : FALSE,
960
/* invert2 */ (ce->ce_flags & CE_INVERT2) ?
961
TRUE : FALSE,
962
/* sense_len */ SSD_FULL_SIZE,
963
/* timeout */ CH_TIMEOUT_EXCHANGE_MEDIUM);
964
965
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO,
966
/*sense_flags*/ SF_RETRY_UA,
967
softc->device_stats);
968
969
xpt_release_ccb(ccb);
970
971
return(error);
972
}
973
974
static int
975
chposition(struct cam_periph *periph, struct changer_position *cp)
976
{
977
struct ch_softc *softc;
978
uint16_t dst;
979
union ccb *ccb;
980
int error;
981
982
error = 0;
983
softc = (struct ch_softc *)periph->softc;
984
985
/*
986
* Check arguments.
987
*/
988
if (cp->cp_type > CHET_DT)
989
return (EINVAL);
990
if (cp->cp_unit > (softc->sc_counts[cp->cp_type] - 1))
991
return (ENODEV);
992
993
/*
994
* Calculate the destination element.
995
*/
996
dst = softc->sc_firsts[cp->cp_type] + cp->cp_unit;
997
998
ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
999
1000
scsi_position_to_element(&ccb->csio,
1001
/* retries */ 1,
1002
/* cbfcnp */ chdone,
1003
/* tag_action */ MSG_SIMPLE_Q_TAG,
1004
/* tea */ softc->sc_picker,
1005
/* dst */ dst,
1006
/* invert */ (cp->cp_flags & CP_INVERT) ?
1007
TRUE : FALSE,
1008
/* sense_len */ SSD_FULL_SIZE,
1009
/* timeout */ CH_TIMEOUT_POSITION_TO_ELEMENT);
1010
1011
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1012
/*sense_flags*/ SF_RETRY_UA,
1013
softc->device_stats);
1014
1015
xpt_release_ccb(ccb);
1016
1017
return(error);
1018
}
1019
1020
/*
1021
* Copy a volume tag to a volume_tag struct, converting SCSI byte order
1022
* to host native byte order in the volume serial number. The volume
1023
* label as returned by the changer is transferred to user mode as
1024
* nul-terminated string. Volume labels are truncated at the first
1025
* space, as suggested by SCSI-2.
1026
*/
1027
static void
1028
copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag)
1029
{
1030
int i;
1031
for (i=0; i<CH_VOLTAG_MAXLEN; i++) {
1032
char c = voltag->vif[i];
1033
if (c && c != ' ')
1034
uvoltag->cv_volid[i] = c;
1035
else
1036
break;
1037
}
1038
uvoltag->cv_serial = scsi_2btoul(voltag->vsn);
1039
}
1040
1041
/*
1042
* Copy an element status descriptor to a user-mode
1043
* changer_element_status structure.
1044
*/
1045
static void
1046
copy_element_status(struct ch_softc *softc,
1047
uint16_t flags,
1048
struct read_element_status_descriptor *desc,
1049
struct changer_element_status *ces,
1050
int scsi_version)
1051
{
1052
uint16_t eaddr = scsi_2btoul(desc->eaddr);
1053
uint16_t et;
1054
struct volume_tag *pvol_tag = NULL, *avol_tag = NULL;
1055
struct read_element_status_device_id *devid = NULL;
1056
1057
ces->ces_int_addr = eaddr;
1058
/* set up logical address in element status */
1059
for (et = CHET_MT; et <= CHET_DT; et++) {
1060
if ((softc->sc_firsts[et] <= eaddr)
1061
&& ((softc->sc_firsts[et] + softc->sc_counts[et])
1062
> eaddr)) {
1063
ces->ces_addr = eaddr - softc->sc_firsts[et];
1064
ces->ces_type = et;
1065
break;
1066
}
1067
}
1068
1069
ces->ces_flags = desc->flags1;
1070
1071
ces->ces_sensecode = desc->sense_code;
1072
ces->ces_sensequal = desc->sense_qual;
1073
1074
if (desc->flags2 & READ_ELEMENT_STATUS_INVERT)
1075
ces->ces_flags |= CES_INVERT;
1076
1077
if (desc->flags2 & READ_ELEMENT_STATUS_SVALID) {
1078
eaddr = scsi_2btoul(desc->ssea);
1079
1080
/* convert source address to logical format */
1081
for (et = CHET_MT; et <= CHET_DT; et++) {
1082
if ((softc->sc_firsts[et] <= eaddr)
1083
&& ((softc->sc_firsts[et] + softc->sc_counts[et])
1084
> eaddr)) {
1085
ces->ces_source_addr =
1086
eaddr - softc->sc_firsts[et];
1087
ces->ces_source_type = et;
1088
ces->ces_flags |= CES_SOURCE_VALID;
1089
break;
1090
}
1091
}
1092
1093
if (!(ces->ces_flags & CES_SOURCE_VALID))
1094
printf("ch: warning: could not map element source "
1095
"address %ud to a valid element type\n",
1096
eaddr);
1097
}
1098
1099
/*
1100
* pvoltag and avoltag are common between SCSI-2 and later versions
1101
*/
1102
if (flags & READ_ELEMENT_STATUS_PVOLTAG)
1103
pvol_tag = &desc->voltag_devid.pvoltag;
1104
if (flags & READ_ELEMENT_STATUS_AVOLTAG)
1105
avol_tag = (flags & READ_ELEMENT_STATUS_PVOLTAG) ?
1106
&desc->voltag_devid.voltag[1] :&desc->voltag_devid.pvoltag;
1107
/*
1108
* For SCSI-3 and later, element status can carry designator and
1109
* other information.
1110
*/
1111
if (scsi_version >= SCSI_REV_SPC) {
1112
if ((flags & READ_ELEMENT_STATUS_PVOLTAG) ^
1113
(flags & READ_ELEMENT_STATUS_AVOLTAG))
1114
devid = &desc->voltag_devid.pvol_and_devid.devid;
1115
else if (!(flags & READ_ELEMENT_STATUS_PVOLTAG) &&
1116
!(flags & READ_ELEMENT_STATUS_AVOLTAG))
1117
devid = &desc->voltag_devid.devid;
1118
else /* Have both PVOLTAG and AVOLTAG */
1119
devid = &desc->voltag_devid.vol_tags_and_devid.devid;
1120
}
1121
1122
if (pvol_tag)
1123
copy_voltag(&(ces->ces_pvoltag), pvol_tag);
1124
if (avol_tag)
1125
copy_voltag(&(ces->ces_pvoltag), avol_tag);
1126
if (devid != NULL) {
1127
if (devid->designator_length > 0) {
1128
bcopy((void *)devid->designator,
1129
(void *)ces->ces_designator,
1130
devid->designator_length);
1131
ces->ces_designator_length = devid->designator_length;
1132
/*
1133
* Make sure we are always NUL terminated. The
1134
* This won't matter for the binary code set,
1135
* since the user will only pay attention to the
1136
* length field.
1137
*/
1138
ces->ces_designator[devid->designator_length]= '\0';
1139
}
1140
if (devid->piv_assoc_designator_type &
1141
READ_ELEMENT_STATUS_PIV_SET) {
1142
ces->ces_flags |= CES_PIV;
1143
ces->ces_protocol_id =
1144
READ_ELEMENT_STATUS_PROTOCOL_ID(
1145
devid->prot_code_set);
1146
}
1147
ces->ces_code_set =
1148
READ_ELEMENT_STATUS_CODE_SET(devid->prot_code_set);
1149
ces->ces_assoc = READ_ELEMENT_STATUS_ASSOCIATION(
1150
devid->piv_assoc_designator_type);
1151
ces->ces_designator_type = READ_ELEMENT_STATUS_DESIGNATOR_TYPE(
1152
devid->piv_assoc_designator_type);
1153
} else if (scsi_version > SCSI_REV_2) {
1154
/* SCSI-SPC and No devid, no designator */
1155
ces->ces_designator_length = 0;
1156
ces->ces_designator[0] = '\0';
1157
ces->ces_protocol_id = CES_PROTOCOL_ID_FCP_4;
1158
}
1159
1160
if (scsi_version <= SCSI_REV_2) {
1161
if (desc->dt_or_obsolete.scsi_2.dt_scsi_flags &
1162
READ_ELEMENT_STATUS_DT_IDVALID) {
1163
ces->ces_flags |= CES_SCSIID_VALID;
1164
ces->ces_scsi_id =
1165
desc->dt_or_obsolete.scsi_2.dt_scsi_addr;
1166
}
1167
1168
if (desc->dt_or_obsolete.scsi_2.dt_scsi_addr &
1169
READ_ELEMENT_STATUS_DT_LUVALID) {
1170
ces->ces_flags |= CES_LUN_VALID;
1171
ces->ces_scsi_lun =
1172
desc->dt_or_obsolete.scsi_2.dt_scsi_flags &
1173
READ_ELEMENT_STATUS_DT_LUNMASK;
1174
}
1175
}
1176
}
1177
1178
static int
1179
chgetelemstatus(struct cam_periph *periph, int scsi_version, u_long cmd,
1180
struct changer_element_status_request *cesr)
1181
{
1182
struct read_element_status_header *st_hdr;
1183
struct read_element_status_page_header *pg_hdr;
1184
struct read_element_status_descriptor *desc;
1185
caddr_t data = NULL;
1186
size_t size, desclen;
1187
u_int avail, i;
1188
int curdata, dvcid, sense_flags;
1189
int try_no_dvcid = 0;
1190
struct changer_element_status *user_data = NULL;
1191
struct ch_softc *softc;
1192
union ccb *ccb;
1193
int chet = cesr->cesr_element_type;
1194
int error = 0;
1195
int want_voltags = (cesr->cesr_flags & CESR_VOLTAGS) ? 1 : 0;
1196
1197
softc = (struct ch_softc *)periph->softc;
1198
1199
/* perform argument checking */
1200
1201
/*
1202
* Perform a range check on the cesr_element_{base,count}
1203
* request argument fields.
1204
*/
1205
if ((softc->sc_counts[chet] - cesr->cesr_element_base) <= 0
1206
|| (cesr->cesr_element_base + cesr->cesr_element_count)
1207
> softc->sc_counts[chet])
1208
return (EINVAL);
1209
1210
/*
1211
* Request one descriptor for the given element type. This
1212
* is used to determine the size of the descriptor so that
1213
* we can allocate enough storage for all of them. We assume
1214
* that the first one can fit into 1k.
1215
*/
1216
cam_periph_unlock(periph);
1217
data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK);
1218
1219
cam_periph_lock(periph);
1220
ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
1221
1222
sense_flags = SF_RETRY_UA;
1223
if (softc->quirks & CH_Q_NO_DVCID) {
1224
dvcid = 0;
1225
curdata = 0;
1226
} else {
1227
dvcid = 1;
1228
curdata = 1;
1229
/*
1230
* Don't print anything for an Illegal Request, because
1231
* these flags can cause some changers to complain. We'll
1232
* retry without them if we get an error.
1233
*/
1234
sense_flags |= SF_QUIET_IR;
1235
}
1236
1237
retry_einval:
1238
1239
scsi_read_element_status(&ccb->csio,
1240
/* retries */ 1,
1241
/* cbfcnp */ chdone,
1242
/* tag_action */ MSG_SIMPLE_Q_TAG,
1243
/* voltag */ want_voltags,
1244
/* sea */ softc->sc_firsts[chet],
1245
/* curdata */ curdata,
1246
/* dvcid */ dvcid,
1247
/* count */ 1,
1248
/* data_ptr */ data,
1249
/* dxfer_len */ 1024,
1250
/* sense_len */ SSD_FULL_SIZE,
1251
/* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS);
1252
1253
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1254
/*sense_flags*/ sense_flags,
1255
softc->device_stats);
1256
1257
/*
1258
* An Illegal Request sense key (only used if there is no asc/ascq)
1259
* or 0x24,0x00 for an ASC/ASCQ both map to EINVAL. If dvcid or
1260
* curdata are set (we set both or neither), try turning them off
1261
* and see if the command is successful.
1262
*/
1263
if ((error == EINVAL)
1264
&& (dvcid || curdata)) {
1265
dvcid = 0;
1266
curdata = 0;
1267
error = 0;
1268
/* At this point we want to report any Illegal Request */
1269
sense_flags &= ~SF_QUIET_IR;
1270
try_no_dvcid = 1;
1271
goto retry_einval;
1272
}
1273
1274
/*
1275
* In this case, we tried a read element status with dvcid and
1276
* curdata set, and it failed. We retried without those bits, and
1277
* it succeeded. Suggest to the user that he set a quirk, so we
1278
* don't go through the retry process the first time in the future.
1279
* This should only happen on changers that claim SCSI-3 or higher,
1280
* but don't support these bits.
1281
*/
1282
if ((try_no_dvcid != 0)
1283
&& (error == 0))
1284
softc->quirks |= CH_Q_NO_DVCID;
1285
1286
if (error)
1287
goto done;
1288
cam_periph_unlock(periph);
1289
1290
st_hdr = (struct read_element_status_header *)data;
1291
pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr +
1292
sizeof(struct read_element_status_header));
1293
desclen = scsi_2btoul(pg_hdr->edl);
1294
1295
size = sizeof(struct read_element_status_header) +
1296
sizeof(struct read_element_status_page_header) +
1297
(desclen * cesr->cesr_element_count);
1298
/*
1299
* Reallocate storage for descriptors and get them from the
1300
* device.
1301
*/
1302
free(data, M_DEVBUF);
1303
data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK);
1304
1305
cam_periph_lock(periph);
1306
scsi_read_element_status(&ccb->csio,
1307
/* retries */ 1,
1308
/* cbfcnp */ chdone,
1309
/* tag_action */ MSG_SIMPLE_Q_TAG,
1310
/* voltag */ want_voltags,
1311
/* sea */ softc->sc_firsts[chet]
1312
+ cesr->cesr_element_base,
1313
/* curdata */ curdata,
1314
/* dvcid */ dvcid,
1315
/* count */ cesr->cesr_element_count,
1316
/* data_ptr */ data,
1317
/* dxfer_len */ size,
1318
/* sense_len */ SSD_FULL_SIZE,
1319
/* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS);
1320
1321
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1322
/*sense_flags*/ SF_RETRY_UA,
1323
softc->device_stats);
1324
1325
if (error)
1326
goto done;
1327
cam_periph_unlock(periph);
1328
1329
/*
1330
* Fill in the user status array.
1331
*/
1332
st_hdr = (struct read_element_status_header *)data;
1333
pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr +
1334
sizeof(struct read_element_status_header));
1335
avail = scsi_2btoul(st_hdr->count);
1336
1337
if (avail != cesr->cesr_element_count) {
1338
xpt_print(periph->path,
1339
"warning, READ ELEMENT STATUS avail != count\n");
1340
}
1341
1342
user_data = (struct changer_element_status *)
1343
malloc(avail * sizeof(struct changer_element_status),
1344
M_DEVBUF, M_WAITOK | M_ZERO);
1345
1346
desc = (struct read_element_status_descriptor *)((uintptr_t)data +
1347
sizeof(struct read_element_status_header) +
1348
sizeof(struct read_element_status_page_header));
1349
/*
1350
* Set up the individual element status structures
1351
*/
1352
for (i = 0; i < avail; ++i) {
1353
struct changer_element_status *ces;
1354
1355
/*
1356
* In the changer_element_status structure, fields from
1357
* the beginning to the field of ces_scsi_lun are common
1358
* between SCSI-2 and SCSI-3, while all the rest are new
1359
* from SCSI-3. In order to maintain backward compatibility
1360
* of the chio command, the ces pointer, below, is computed
1361
* such that it lines up with the structure boundary
1362
* corresponding to the SCSI version.
1363
*/
1364
ces = cmd == OCHIOGSTATUS ?
1365
(struct changer_element_status *)
1366
((unsigned char *)user_data + i *
1367
(offsetof(struct changer_element_status,ces_scsi_lun)+1)):
1368
&user_data[i];
1369
1370
copy_element_status(softc, pg_hdr->flags, desc,
1371
ces, scsi_version);
1372
1373
desc = (struct read_element_status_descriptor *)
1374
((unsigned char *)desc + desclen);
1375
}
1376
1377
/* Copy element status structures out to userspace. */
1378
if (cmd == OCHIOGSTATUS)
1379
error = copyout(user_data,
1380
cesr->cesr_element_status,
1381
avail* (offsetof(struct changer_element_status,
1382
ces_scsi_lun) + 1));
1383
else
1384
error = copyout(user_data,
1385
cesr->cesr_element_status,
1386
avail * sizeof(struct changer_element_status));
1387
1388
cam_periph_lock(periph);
1389
1390
done:
1391
xpt_release_ccb(ccb);
1392
1393
if (data != NULL)
1394
free(data, M_DEVBUF);
1395
if (user_data != NULL)
1396
free(user_data, M_DEVBUF);
1397
1398
return (error);
1399
}
1400
1401
static int
1402
chielem(struct cam_periph *periph,
1403
unsigned int timeout)
1404
{
1405
union ccb *ccb;
1406
struct ch_softc *softc;
1407
int error;
1408
1409
if (!timeout) {
1410
timeout = CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS;
1411
} else {
1412
timeout *= 1000;
1413
}
1414
1415
error = 0;
1416
softc = (struct ch_softc *)periph->softc;
1417
1418
ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
1419
1420
scsi_initialize_element_status(&ccb->csio,
1421
/* retries */ 1,
1422
/* cbfcnp */ chdone,
1423
/* tag_action */ MSG_SIMPLE_Q_TAG,
1424
/* sense_len */ SSD_FULL_SIZE,
1425
/* timeout */ timeout);
1426
1427
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1428
/*sense_flags*/ SF_RETRY_UA,
1429
softc->device_stats);
1430
1431
xpt_release_ccb(ccb);
1432
1433
return(error);
1434
}
1435
1436
static int
1437
chsetvoltag(struct cam_periph *periph,
1438
struct changer_set_voltag_request *csvr)
1439
{
1440
union ccb *ccb;
1441
struct ch_softc *softc;
1442
uint16_t ea;
1443
uint8_t sac;
1444
struct scsi_send_volume_tag_parameters ssvtp;
1445
int error;
1446
int i;
1447
1448
error = 0;
1449
softc = (struct ch_softc *)periph->softc;
1450
1451
bzero(&ssvtp, sizeof(ssvtp));
1452
for (i=0; i<sizeof(ssvtp.vitf); i++) {
1453
ssvtp.vitf[i] = ' ';
1454
}
1455
1456
/*
1457
* Check arguments.
1458
*/
1459
if (csvr->csvr_type > CHET_DT)
1460
return EINVAL;
1461
if (csvr->csvr_addr > (softc->sc_counts[csvr->csvr_type] - 1))
1462
return ENODEV;
1463
1464
ea = softc->sc_firsts[csvr->csvr_type] + csvr->csvr_addr;
1465
1466
if (csvr->csvr_flags & CSVR_ALTERNATE) {
1467
switch (csvr->csvr_flags & CSVR_MODE_MASK) {
1468
case CSVR_MODE_SET:
1469
sac = SEND_VOLUME_TAG_ASSERT_ALTERNATE;
1470
break;
1471
case CSVR_MODE_REPLACE:
1472
sac = SEND_VOLUME_TAG_REPLACE_ALTERNATE;
1473
break;
1474
case CSVR_MODE_CLEAR:
1475
sac = SEND_VOLUME_TAG_UNDEFINED_ALTERNATE;
1476
break;
1477
default:
1478
error = EINVAL;
1479
goto out;
1480
}
1481
} else {
1482
switch (csvr->csvr_flags & CSVR_MODE_MASK) {
1483
case CSVR_MODE_SET:
1484
sac = SEND_VOLUME_TAG_ASSERT_PRIMARY;
1485
break;
1486
case CSVR_MODE_REPLACE:
1487
sac = SEND_VOLUME_TAG_REPLACE_PRIMARY;
1488
break;
1489
case CSVR_MODE_CLEAR:
1490
sac = SEND_VOLUME_TAG_UNDEFINED_PRIMARY;
1491
break;
1492
default:
1493
error = EINVAL;
1494
goto out;
1495
}
1496
}
1497
1498
memcpy(ssvtp.vitf, csvr->csvr_voltag.cv_volid,
1499
min(strlen(csvr->csvr_voltag.cv_volid), sizeof(ssvtp.vitf)));
1500
scsi_ulto2b(csvr->csvr_voltag.cv_serial, ssvtp.minvsn);
1501
1502
ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
1503
1504
scsi_send_volume_tag(&ccb->csio,
1505
/* retries */ 1,
1506
/* cbfcnp */ chdone,
1507
/* tag_action */ MSG_SIMPLE_Q_TAG,
1508
/* element_address */ ea,
1509
/* send_action_code */ sac,
1510
/* parameters */ &ssvtp,
1511
/* sense_len */ SSD_FULL_SIZE,
1512
/* timeout */ CH_TIMEOUT_SEND_VOLTAG);
1513
1514
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1515
/*sense_flags*/ SF_RETRY_UA,
1516
softc->device_stats);
1517
1518
xpt_release_ccb(ccb);
1519
1520
out:
1521
return error;
1522
}
1523
1524
static int
1525
chgetparams(struct cam_periph *periph)
1526
{
1527
union ccb *ccb;
1528
struct ch_softc *softc;
1529
void *mode_buffer;
1530
int mode_buffer_len;
1531
struct page_element_address_assignment *ea;
1532
struct page_device_capabilities *cap;
1533
int error, from, dbd;
1534
uint8_t *moves, *exchanges;
1535
1536
error = 0;
1537
1538
softc = (struct ch_softc *)periph->softc;
1539
1540
ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
1541
1542
/*
1543
* The scsi_mode_sense_data structure is just a convenience
1544
* structure that allows us to easily calculate the worst-case
1545
* storage size of the mode sense buffer.
1546
*/
1547
mode_buffer_len = sizeof(struct scsi_mode_sense_data);
1548
1549
mode_buffer = malloc(mode_buffer_len, M_SCSICH, M_NOWAIT);
1550
1551
if (mode_buffer == NULL) {
1552
printf("chgetparams: couldn't malloc mode sense data\n");
1553
xpt_release_ccb(ccb);
1554
return(ENOSPC);
1555
}
1556
1557
bzero(mode_buffer, mode_buffer_len);
1558
1559
if (softc->quirks & CH_Q_NO_DBD)
1560
dbd = FALSE;
1561
else
1562
dbd = TRUE;
1563
1564
/*
1565
* Get the element address assignment page.
1566
*/
1567
scsi_mode_sense(&ccb->csio,
1568
/* retries */ 1,
1569
/* cbfcnp */ chdone,
1570
/* tag_action */ MSG_SIMPLE_Q_TAG,
1571
/* dbd */ dbd,
1572
/* pc */ SMS_PAGE_CTRL_CURRENT,
1573
/* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE,
1574
/* param_buf */ (uint8_t *)mode_buffer,
1575
/* param_len */ mode_buffer_len,
1576
/* sense_len */ SSD_FULL_SIZE,
1577
/* timeout */ CH_TIMEOUT_MODE_SENSE);
1578
1579
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1580
/* sense_flags */ SF_RETRY_UA|SF_NO_PRINT,
1581
softc->device_stats);
1582
1583
if (error) {
1584
if (dbd) {
1585
struct scsi_mode_sense_6 *sms;
1586
1587
sms = (struct scsi_mode_sense_6 *)
1588
ccb->csio.cdb_io.cdb_bytes;
1589
1590
sms->byte2 &= ~SMS_DBD;
1591
error = cam_periph_runccb(ccb, cherror,
1592
/*cam_flags*/ CAM_RETRY_SELTO,
1593
/*sense_flags*/ SF_RETRY_UA,
1594
softc->device_stats);
1595
} else {
1596
/*
1597
* Since we disabled sense printing above, print
1598
* out the sense here since we got an error.
1599
*/
1600
scsi_sense_print(&ccb->csio);
1601
}
1602
1603
if (error) {
1604
xpt_print(periph->path,
1605
"chgetparams: error getting element "
1606
"address page\n");
1607
xpt_release_ccb(ccb);
1608
free(mode_buffer, M_SCSICH);
1609
return(error);
1610
}
1611
}
1612
1613
ea = (struct page_element_address_assignment *)
1614
find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer);
1615
1616
softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea);
1617
softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte);
1618
softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea);
1619
softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse);
1620
softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea);
1621
softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee);
1622
softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea);
1623
softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte);
1624
1625
bzero(mode_buffer, mode_buffer_len);
1626
1627
/*
1628
* Now get the device capabilities page.
1629
*/
1630
scsi_mode_sense(&ccb->csio,
1631
/* retries */ 1,
1632
/* cbfcnp */ chdone,
1633
/* tag_action */ MSG_SIMPLE_Q_TAG,
1634
/* dbd */ dbd,
1635
/* pc */ SMS_PAGE_CTRL_CURRENT,
1636
/* page */ CH_DEVICE_CAP_PAGE,
1637
/* param_buf */ (uint8_t *)mode_buffer,
1638
/* param_len */ mode_buffer_len,
1639
/* sense_len */ SSD_FULL_SIZE,
1640
/* timeout */ CH_TIMEOUT_MODE_SENSE);
1641
1642
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1643
/* sense_flags */ SF_RETRY_UA | SF_NO_PRINT,
1644
softc->device_stats);
1645
1646
if (error) {
1647
if (dbd) {
1648
struct scsi_mode_sense_6 *sms;
1649
1650
sms = (struct scsi_mode_sense_6 *)
1651
ccb->csio.cdb_io.cdb_bytes;
1652
1653
sms->byte2 &= ~SMS_DBD;
1654
error = cam_periph_runccb(ccb, cherror,
1655
/*cam_flags*/ CAM_RETRY_SELTO,
1656
/*sense_flags*/ SF_RETRY_UA,
1657
softc->device_stats);
1658
} else {
1659
/*
1660
* Since we disabled sense printing above, print
1661
* out the sense here since we got an error.
1662
*/
1663
scsi_sense_print(&ccb->csio);
1664
}
1665
1666
if (error) {
1667
xpt_print(periph->path,
1668
"chgetparams: error getting device "
1669
"capabilities page\n");
1670
xpt_release_ccb(ccb);
1671
free(mode_buffer, M_SCSICH);
1672
return(error);
1673
}
1674
}
1675
1676
xpt_release_ccb(ccb);
1677
1678
cap = (struct page_device_capabilities *)
1679
find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer);
1680
1681
bzero(softc->sc_movemask, sizeof(softc->sc_movemask));
1682
bzero(softc->sc_exchangemask, sizeof(softc->sc_exchangemask));
1683
moves = cap->move_from;
1684
exchanges = cap->exchange_with;
1685
for (from = CHET_MT; from <= CHET_MAX; ++from) {
1686
softc->sc_movemask[from] = moves[from];
1687
softc->sc_exchangemask[from] = exchanges[from];
1688
}
1689
1690
free(mode_buffer, M_SCSICH);
1691
1692
return(error);
1693
}
1694
1695
static int
1696
chscsiversion(struct cam_periph *periph)
1697
{
1698
struct scsi_inquiry_data *inq_data;
1699
struct ccb_getdev *cgd;
1700
int dev_scsi_version;
1701
1702
cam_periph_assert(periph, MA_OWNED);
1703
if ((cgd = (struct ccb_getdev *)xpt_alloc_ccb_nowait()) == NULL)
1704
return (-1);
1705
/*
1706
* Get the device information.
1707
*/
1708
xpt_gdev_type(cgd, periph->path);
1709
1710
if (cgd->ccb_h.status != CAM_REQ_CMP) {
1711
xpt_free_ccb((union ccb *)cgd);
1712
return -1;
1713
}
1714
1715
inq_data = &cgd->inq_data;
1716
dev_scsi_version = inq_data->version;
1717
xpt_free_ccb((union ccb *)cgd);
1718
1719
return dev_scsi_version;
1720
}
1721
1722
void
1723
scsi_move_medium(struct ccb_scsiio *csio, uint32_t retries,
1724
void (*cbfcnp)(struct cam_periph *, union ccb *),
1725
uint8_t tag_action, uint32_t tea, uint32_t src,
1726
uint32_t dst, int invert, uint8_t sense_len,
1727
uint32_t timeout)
1728
{
1729
struct scsi_move_medium *scsi_cmd;
1730
1731
scsi_cmd = (struct scsi_move_medium *)&csio->cdb_io.cdb_bytes;
1732
bzero(scsi_cmd, sizeof(*scsi_cmd));
1733
1734
scsi_cmd->opcode = MOVE_MEDIUM;
1735
1736
scsi_ulto2b(tea, scsi_cmd->tea);
1737
scsi_ulto2b(src, scsi_cmd->src);
1738
scsi_ulto2b(dst, scsi_cmd->dst);
1739
1740
if (invert)
1741
scsi_cmd->invert |= MOVE_MEDIUM_INVERT;
1742
1743
cam_fill_csio(csio,
1744
retries,
1745
cbfcnp,
1746
/*flags*/ CAM_DIR_NONE,
1747
tag_action,
1748
/*data_ptr*/ NULL,
1749
/*dxfer_len*/ 0,
1750
sense_len,
1751
sizeof(*scsi_cmd),
1752
timeout);
1753
}
1754
1755
void
1756
scsi_exchange_medium(struct ccb_scsiio *csio, uint32_t retries,
1757
void (*cbfcnp)(struct cam_periph *, union ccb *),
1758
uint8_t tag_action, uint32_t tea, uint32_t src,
1759
uint32_t dst1, uint32_t dst2, int invert1,
1760
int invert2, uint8_t sense_len, uint32_t timeout)
1761
{
1762
struct scsi_exchange_medium *scsi_cmd;
1763
1764
scsi_cmd = (struct scsi_exchange_medium *)&csio->cdb_io.cdb_bytes;
1765
bzero(scsi_cmd, sizeof(*scsi_cmd));
1766
1767
scsi_cmd->opcode = EXCHANGE_MEDIUM;
1768
1769
scsi_ulto2b(tea, scsi_cmd->tea);
1770
scsi_ulto2b(src, scsi_cmd->src);
1771
scsi_ulto2b(dst1, scsi_cmd->fdst);
1772
scsi_ulto2b(dst2, scsi_cmd->sdst);
1773
1774
if (invert1)
1775
scsi_cmd->invert |= EXCHANGE_MEDIUM_INV1;
1776
1777
if (invert2)
1778
scsi_cmd->invert |= EXCHANGE_MEDIUM_INV2;
1779
1780
cam_fill_csio(csio,
1781
retries,
1782
cbfcnp,
1783
/*flags*/ CAM_DIR_NONE,
1784
tag_action,
1785
/*data_ptr*/ NULL,
1786
/*dxfer_len*/ 0,
1787
sense_len,
1788
sizeof(*scsi_cmd),
1789
timeout);
1790
}
1791
1792
void
1793
scsi_position_to_element(struct ccb_scsiio *csio, uint32_t retries,
1794
void (*cbfcnp)(struct cam_periph *, union ccb *),
1795
uint8_t tag_action, uint32_t tea, uint32_t dst,
1796
int invert, uint8_t sense_len, uint32_t timeout)
1797
{
1798
struct scsi_position_to_element *scsi_cmd;
1799
1800
scsi_cmd = (struct scsi_position_to_element *)&csio->cdb_io.cdb_bytes;
1801
bzero(scsi_cmd, sizeof(*scsi_cmd));
1802
1803
scsi_cmd->opcode = POSITION_TO_ELEMENT;
1804
1805
scsi_ulto2b(tea, scsi_cmd->tea);
1806
scsi_ulto2b(dst, scsi_cmd->dst);
1807
1808
if (invert)
1809
scsi_cmd->invert |= POSITION_TO_ELEMENT_INVERT;
1810
1811
cam_fill_csio(csio,
1812
retries,
1813
cbfcnp,
1814
/*flags*/ CAM_DIR_NONE,
1815
tag_action,
1816
/*data_ptr*/ NULL,
1817
/*dxfer_len*/ 0,
1818
sense_len,
1819
sizeof(*scsi_cmd),
1820
timeout);
1821
}
1822
1823
void
1824
scsi_read_element_status(struct ccb_scsiio *csio, uint32_t retries,
1825
void (*cbfcnp)(struct cam_periph *, union ccb *),
1826
uint8_t tag_action, int voltag, uint32_t sea,
1827
int curdata, int dvcid,
1828
uint32_t count, uint8_t *data_ptr,
1829
uint32_t dxfer_len, uint8_t sense_len,
1830
uint32_t timeout)
1831
{
1832
struct scsi_read_element_status *scsi_cmd;
1833
1834
scsi_cmd = (struct scsi_read_element_status *)&csio->cdb_io.cdb_bytes;
1835
bzero(scsi_cmd, sizeof(*scsi_cmd));
1836
1837
scsi_cmd->opcode = READ_ELEMENT_STATUS;
1838
1839
scsi_ulto2b(sea, scsi_cmd->sea);
1840
scsi_ulto2b(count, scsi_cmd->count);
1841
scsi_ulto3b(dxfer_len, scsi_cmd->len);
1842
if (dvcid)
1843
scsi_cmd->flags |= READ_ELEMENT_STATUS_DVCID;
1844
if (curdata)
1845
scsi_cmd->flags |= READ_ELEMENT_STATUS_CURDATA;
1846
1847
if (voltag)
1848
scsi_cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG;
1849
1850
cam_fill_csio(csio,
1851
retries,
1852
cbfcnp,
1853
/*flags*/ CAM_DIR_IN,
1854
tag_action,
1855
data_ptr,
1856
dxfer_len,
1857
sense_len,
1858
sizeof(*scsi_cmd),
1859
timeout);
1860
}
1861
1862
void
1863
scsi_initialize_element_status(struct ccb_scsiio *csio, uint32_t retries,
1864
void (*cbfcnp)(struct cam_periph *, union ccb *),
1865
uint8_t tag_action, uint8_t sense_len,
1866
uint32_t timeout)
1867
{
1868
struct scsi_initialize_element_status *scsi_cmd;
1869
1870
scsi_cmd = (struct scsi_initialize_element_status *)
1871
&csio->cdb_io.cdb_bytes;
1872
bzero(scsi_cmd, sizeof(*scsi_cmd));
1873
1874
scsi_cmd->opcode = INITIALIZE_ELEMENT_STATUS;
1875
1876
cam_fill_csio(csio,
1877
retries,
1878
cbfcnp,
1879
/*flags*/ CAM_DIR_NONE,
1880
tag_action,
1881
/* data_ptr */ NULL,
1882
/* dxfer_len */ 0,
1883
sense_len,
1884
sizeof(*scsi_cmd),
1885
timeout);
1886
}
1887
1888
void
1889
scsi_send_volume_tag(struct ccb_scsiio *csio, uint32_t retries,
1890
void (*cbfcnp)(struct cam_periph *, union ccb *),
1891
uint8_t tag_action,
1892
uint16_t element_address,
1893
uint8_t send_action_code,
1894
struct scsi_send_volume_tag_parameters *parameters,
1895
uint8_t sense_len, uint32_t timeout)
1896
{
1897
struct scsi_send_volume_tag *scsi_cmd;
1898
1899
scsi_cmd = (struct scsi_send_volume_tag *) &csio->cdb_io.cdb_bytes;
1900
bzero(scsi_cmd, sizeof(*scsi_cmd));
1901
1902
scsi_cmd->opcode = SEND_VOLUME_TAG;
1903
scsi_ulto2b(element_address, scsi_cmd->ea);
1904
scsi_cmd->sac = send_action_code;
1905
scsi_ulto2b(sizeof(*parameters), scsi_cmd->pll);
1906
1907
cam_fill_csio(csio,
1908
retries,
1909
cbfcnp,
1910
/*flags*/ CAM_DIR_OUT,
1911
tag_action,
1912
/* data_ptr */ (uint8_t *) parameters,
1913
sizeof(*parameters),
1914
sense_len,
1915
sizeof(*scsi_cmd),
1916
timeout);
1917
}
1918
1919