in ch.c [627:883]
static long ch_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
scsi_changer *ch = file->private_data;
int retval;
void __user *argp = (void __user *)arg;
retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
file->f_flags & O_NDELAY);
if (retval)
return retval;
switch (cmd) {
case CHIOGPARAMS:
{
struct changer_params params;
params.cp_curpicker = 0;
params.cp_npickers = ch->counts[CHET_MT];
params.cp_nslots = ch->counts[CHET_ST];
params.cp_nportals = ch->counts[CHET_IE];
params.cp_ndrives = ch->counts[CHET_DT];
if (copy_to_user(argp, ¶ms, sizeof(params)))
return -EFAULT;
return 0;
}
case CHIOGVPARAMS:
{
struct changer_vendor_params vparams;
memset(&vparams,0,sizeof(vparams));
if (ch->counts[CHET_V1]) {
vparams.cvp_n1 = ch->counts[CHET_V1];
strncpy(vparams.cvp_label1,vendor_labels[0],16);
}
if (ch->counts[CHET_V2]) {
vparams.cvp_n2 = ch->counts[CHET_V2];
strncpy(vparams.cvp_label2,vendor_labels[1],16);
}
if (ch->counts[CHET_V3]) {
vparams.cvp_n3 = ch->counts[CHET_V3];
strncpy(vparams.cvp_label3,vendor_labels[2],16);
}
if (ch->counts[CHET_V4]) {
vparams.cvp_n4 = ch->counts[CHET_V4];
strncpy(vparams.cvp_label4,vendor_labels[3],16);
}
if (copy_to_user(argp, &vparams, sizeof(vparams)))
return -EFAULT;
return 0;
}
case CHIOPOSITION:
{
struct changer_position pos;
if (copy_from_user(&pos, argp, sizeof (pos)))
return -EFAULT;
if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) {
DPRINTK("CHIOPOSITION: invalid parameter\n");
return -EBADSLT;
}
mutex_lock(&ch->lock);
retval = ch_position(ch,0,
ch->firsts[pos.cp_type] + pos.cp_unit,
pos.cp_flags & CP_INVERT);
mutex_unlock(&ch->lock);
return retval;
}
case CHIOMOVE:
{
struct changer_move mv;
if (copy_from_user(&mv, argp, sizeof (mv)))
return -EFAULT;
if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) ||
0 != ch_checkrange(ch, mv.cm_totype, mv.cm_tounit )) {
DPRINTK("CHIOMOVE: invalid parameter\n");
return -EBADSLT;
}
mutex_lock(&ch->lock);
retval = ch_move(ch,0,
ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
ch->firsts[mv.cm_totype] + mv.cm_tounit,
mv.cm_flags & CM_INVERT);
mutex_unlock(&ch->lock);
return retval;
}
case CHIOEXCHANGE:
{
struct changer_exchange mv;
if (copy_from_user(&mv, argp, sizeof (mv)))
return -EFAULT;
if (0 != ch_checkrange(ch, mv.ce_srctype, mv.ce_srcunit ) ||
0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) ||
0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) {
DPRINTK("CHIOEXCHANGE: invalid parameter\n");
return -EBADSLT;
}
mutex_lock(&ch->lock);
retval = ch_exchange
(ch,0,
ch->firsts[mv.ce_srctype] + mv.ce_srcunit,
ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit,
ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit,
mv.ce_flags & CE_INVERT1, mv.ce_flags & CE_INVERT2);
mutex_unlock(&ch->lock);
return retval;
}
case CHIOGSTATUS:
{
struct changer_element_status ces;
if (copy_from_user(&ces, argp, sizeof (ces)))
return -EFAULT;
if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES)
return -EINVAL;
return ch_gstatus(ch, ces.ces_type, ces.ces_data);
}
#ifdef CONFIG_COMPAT
case CHIOGSTATUS32:
{
struct changer_element_status32 ces32;
if (copy_from_user(&ces32, argp, sizeof(ces32)))
return -EFAULT;
if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
return -EINVAL;
return ch_gstatus(ch, ces32.ces_type,
compat_ptr(ces32.ces_data));
}
#endif
case CHIOGELEM:
{
struct changer_get_element cge;
u_char ch_cmd[12];
u_char *buffer;
unsigned int elem;
int result,i;
if (copy_from_user(&cge, argp, sizeof (cge)))
return -EFAULT;
if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit))
return -EINVAL;
elem = ch->firsts[cge.cge_type] + cge.cge_unit;
buffer = kmalloc(512, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
mutex_lock(&ch->lock);
voltag_retry:
memset(ch_cmd, 0, sizeof(ch_cmd));
ch_cmd[0] = READ_ELEMENT_STATUS;
ch_cmd[1] = ((ch->device->lun & 0x7) << 5) |
(ch->voltags ? 0x10 : 0) |
ch_elem_to_typecode(ch,elem);
ch_cmd[2] = (elem >> 8) & 0xff;
ch_cmd[3] = elem & 0xff;
ch_cmd[5] = 1;
ch_cmd[9] = 255;
result = ch_do_scsi(ch, ch_cmd, 12,
buffer, 256, DMA_FROM_DEVICE);
if (!result) {
cge.cge_status = buffer[18];
cge.cge_flags = 0;
if (buffer[18] & CESTATUS_EXCEPT) {
cge.cge_errno = EIO;
}
if (buffer[25] & 0x80) {
cge.cge_flags |= CGE_SRC;
if (buffer[25] & 0x40)
cge.cge_flags |= CGE_INVERT;
elem = (buffer[26]<<8) | buffer[27];
for (i = 0; i < 4; i++) {
if (elem >= ch->firsts[i] &&
elem < ch->firsts[i] + ch->counts[i]) {
cge.cge_srctype = i;
cge.cge_srcunit = elem-ch->firsts[i];
}
}
}
if ((buffer[22] & 0x30) == 0x30) {
cge.cge_flags |= CGE_IDLUN;
cge.cge_id = buffer[23];
cge.cge_lun = buffer[22] & 7;
}
if (buffer[9] & 0x80) {
cge.cge_flags |= CGE_PVOLTAG;
memcpy(cge.cge_pvoltag,buffer+28,36);
}
if (buffer[9] & 0x40) {
cge.cge_flags |= CGE_AVOLTAG;
memcpy(cge.cge_avoltag,buffer+64,36);
}
} else if (ch->voltags) {
ch->voltags = 0;
VPRINTK(KERN_INFO, "device has no volume tag support\n");
goto voltag_retry;
}
kfree(buffer);
mutex_unlock(&ch->lock);
if (copy_to_user(argp, &cge, sizeof (cge)))
return -EFAULT;
return result;
}
case CHIOINITELEM:
{
mutex_lock(&ch->lock);
retval = ch_init_elem(ch);
mutex_unlock(&ch->lock);
return retval;
}
case CHIOSVOLTAG:
{
struct changer_set_voltag csv;
int elem;
if (copy_from_user(&csv, argp, sizeof(csv)))
return -EFAULT;
if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) {
DPRINTK("CHIOSVOLTAG: invalid parameter\n");
return -EBADSLT;
}
elem = ch->firsts[csv.csv_type] + csv.csv_unit;
mutex_lock(&ch->lock);
retval = ch_set_voltag(ch, elem,
csv.csv_flags & CSV_AVOLTAG,
csv.csv_flags & CSV_CLEARTAG,
csv.csv_voltag);
mutex_unlock(&ch->lock);
return retval;
}
default:
return scsi_ioctl(ch->device, file->f_mode, cmd, argp);
}
}