--- st.c.orig 2005-06-17 15:48:29.000000000 -0400 +++ st.c 2005-07-22 15:20:06.000000000 -0400 @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static char *verstr = "20050312"; +static char *verstr = "20050706"; #include @@ -215,7 +215,7 @@ static int find_partition(struct scsi_tape *); static int switch_partition(struct scsi_tape *); -static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long); +static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long, int); #include "osst_detect.h" @@ -264,6 +264,29 @@ return tape->disk->disk_name; } +static void st_clear_last_command(struct scsi_tape *STp) +{ + /* clear last command and last sense */ + memset(STp->buffer->cmdstat.last_cmnd,0,MAX_COMMAND_SIZE); + memset(STp->buffer->cmdstat.last_sense,0,SCSI_SENSE_BUFFERSIZE); +} + +static void st_record_last_command(struct scsi_tape *STp, struct scsi_request *SRpnt) +{ + int i; + + st_clear_last_command(STp); + + /* make copy of last SCSI command */ + for(i=0; ibuffer->cmdstat.last_cmnd[i] = SRpnt->sr_cmnd[i]; + } + + /* make copy of last SCSI sense buffer */ + for(i=0; ibuffer->cmdstat.last_sense[i] = SRpnt->sr_sense_buffer[i]; + } +} static void st_analyze_sense(struct scsi_request *SRpnt, struct st_cmdstatus *s) { @@ -539,6 +562,7 @@ if (!SRpnt) return (STp->buffer)->syscall_result; + st_record_last_command(STp,SRpnt); scsi_release_request(SRpnt); SRpnt = NULL; @@ -587,6 +611,8 @@ if (!SRpnt) return (STp->buffer)->syscall_result; + st_record_last_command(STp,SRpnt); + STps = &(STp->ps[STp->partition]); if ((STp->buffer)->syscall_result != 0) { struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; @@ -666,7 +692,7 @@ } } if (!result && backspace > 0) - result = st_int_ioctl(STp, MTBSR, backspace); + result = st_int_ioctl(STp, MTBSR, backspace, 1); } else if (STps->eof == ST_FM_HIT) { if (STps->drv_file >= 0) STps->drv_file++; @@ -700,7 +726,7 @@ } else arg |= STp->block_size; if (set_it && - st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) { + st_int_ioctl(STp, SET_DENS_AND_BLK, arg, 1)) { printk(KERN_WARNING "%s: Can't set default block size to %d bytes and density %x.\n", name, STm->default_blksize, STm->default_density); @@ -786,6 +812,8 @@ break; } + st_record_last_command(STp,SRpnt); + if (cmdstatp->have_sense) { scode = cmdstatp->sense_hdr.sense_key; @@ -919,6 +947,8 @@ goto err_out; } + st_record_last_command(STp,SRpnt); + if (!SRpnt->sr_result && !STp->buffer->cmdstat.have_sense) { STp->max_block = ((STp->buffer)->b_data[1] << 16) | ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3]; @@ -946,6 +976,8 @@ goto err_out; } + st_record_last_command(STp,SRpnt); + if ((STp->buffer)->syscall_result != 0) { DEBC(printk(ST_DEB_MSG "%s: No Mode Sense.\n", name)); STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */ @@ -1022,7 +1054,7 @@ goto err_out; if (STp->default_drvbuffer != 0xff) { - if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer)) + if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer, 1)) printk(KERN_WARNING "%s: Can't set default drive buffering to %d.\n", name, STp->default_drvbuffer); @@ -1173,6 +1205,8 @@ goto out; } + st_record_last_command(STp,SRpnt); + if (STp->buffer->syscall_result == 0 || (cmdstatp->have_sense && !cmdstatp->deferred && (cmdstatp->flags & SENSE_EOM) && @@ -1226,7 +1260,7 @@ out: if (STp->rew_at_close) { - result2 = st_int_ioctl(STp, MTREW, 1); + result2 = st_int_ioctl(STp, MTREW, 1, 1); if (result == 0) result = result2; } @@ -1555,6 +1589,9 @@ retval = STbp->syscall_result; goto out; } + + st_record_last_command(STp,SRpnt); + if (async_write) { STbp->writing = transfer; STp->dirty = !(STbp->writing == @@ -1723,6 +1760,8 @@ if (!SRpnt) return STbp->syscall_result; + st_record_last_command(STp,SRpnt); + STbp->read_pointer = 0; STps->at_sm = 0; @@ -1772,7 +1811,7 @@ printk(KERN_NOTICE "%s: Incorrect block size.\n", name); if (STps->drv_block >= 0) STps->drv_block += blks - transfer + 1; - st_int_ioctl(STp, MTBSR, 1); + st_int_ioctl(STp, MTBSR, 1, 0); return (-EIO); } /* We have some data, deliver it */ @@ -1783,7 +1822,7 @@ name, count, STbp->buffer_bytes)); if (STps->drv_block >= 0) STps->drv_block += 1; - if (st_int_ioctl(STp, MTBSR, 1)) + if (st_int_ioctl(STp, MTBSR, 1, 0)) return (-EIO); } } else if (cmdstatp->flags & SENSE_FMK) { /* FM overrides EOM */ @@ -2160,7 +2199,7 @@ "%s: Drive buffer default set to %x\n", name, STp->default_drvbuffer)); if (STp->ready == ST_READY) - st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer); + st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer, 1); } } else if (code == MT_ST_DEF_COMPRESSION) { if (value == MT_ST_CLEAR_DEFAULT) { @@ -2229,6 +2268,7 @@ if (SRpnt == NULL) return (STp->buffer)->syscall_result; + st_record_last_command(STp,SRpnt); scsi_release_request(SRpnt); return (STp->buffer)->syscall_result; @@ -2260,6 +2300,7 @@ if (SRpnt == NULL) return (STp->buffer)->syscall_result; + st_record_last_command(STp,SRpnt); scsi_release_request(SRpnt); return (STp->buffer)->syscall_result; @@ -2385,6 +2426,7 @@ if (!SRpnt) return (STp->buffer)->syscall_result; + st_record_last_command(STp,SRpnt); retval = (STp->buffer)->syscall_result; scsi_release_request(SRpnt); @@ -2427,7 +2469,7 @@ /* Internal ioctl function */ -static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned long arg) +static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned long arg, int record_last) { int timeout; long ltmp; @@ -2582,7 +2624,7 @@ case MTEOM: if (!STp->fast_mteom) { /* space to the end of tape */ - ioctl_result = st_int_ioctl(STp, MTFSF, 0x7fffff); + ioctl_result = st_int_ioctl(STp, MTFSF, 0x7fffff, 1); fileno = STps->drv_file; if (STps->eof >= ST_EOD_1) return 0; @@ -2685,6 +2727,9 @@ if (!SRpnt) return (STp->buffer)->syscall_result; + if(record_last) + st_record_last_command(STp,SRpnt); + ioctl_result = (STp->buffer)->syscall_result; if (!ioctl_result) { /* SCSI command successful */ @@ -2695,9 +2740,9 @@ STps->at_sm = at_sm; if (cmd_in == MTBSFM) - ioctl_result = st_int_ioctl(STp, MTFSF, 1); + ioctl_result = st_int_ioctl(STp, MTFSF, 1, 1); else if (cmd_in == MTFSFM) - ioctl_result = st_int_ioctl(STp, MTBSF, 1); + ioctl_result = st_int_ioctl(STp, MTBSF, 1, 1); if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { int old_block_size = STp->block_size; @@ -2805,7 +2850,7 @@ STp->use_pf = !STp->use_pf | PF_TESTED; scsi_release_request(SRpnt); SRpnt = NULL; - return st_int_ioctl(STp, cmd_in, arg); + return st_int_ioctl(STp, cmd_in, arg, 1); } } else if (chg_eof) STps->eof = ST_NOEOF; @@ -2849,6 +2894,8 @@ if (!SRpnt) return (STp->buffer)->syscall_result; + st_record_last_command(STp,SRpnt); + if ((STp->buffer)->syscall_result != 0 || (STp->device->scsi_level >= SCSI_2 && ((STp->buffer)->b_data[0] & 4) != 0)) { @@ -2954,6 +3001,8 @@ if (!SRpnt) return (STp->buffer)->syscall_result; + st_record_last_command(STp,SRpnt); + STps->drv_block = STps->drv_file = (-1); STps->eof = ST_NOEOF; if ((STp->buffer)->syscall_result != 0) { @@ -3237,7 +3286,7 @@ (mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || mtc.mt_op == MTSEEK || mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)) { - i = st_int_ioctl(STp, MTWEOF, 1); + i = st_int_ioctl(STp, MTWEOF, 1, 1); if (i < 0) { retval = i; goto out; @@ -3306,7 +3355,7 @@ retval = (-EINVAL); goto out; } - if ((i = st_int_ioctl(STp, MTREW, 0)) < 0 || + if ((i = st_int_ioctl(STp, MTREW, 0, 1)) < 0 || (i = partition_tape(STp, mtc.mt_count)) < 0) { retval = i; goto out; @@ -3355,7 +3404,7 @@ if (mtc.mt_op == MTCOMPRESSION) retval = st_compression(STp, (mtc.mt_count & 1)); else - retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count); + retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count, 1); goto out; } if (!STm->defined) { @@ -3981,6 +4030,11 @@ STm->cdevs[j] = cdev; } + /* copy the per-drive data into each mode so that + we can display it per-mode in sysfs */ + STm->cmdstat = &tpnt->buffer->cmdstat; + + /* create per-mode sysfs entries */ do_create_class_files(tpnt, dev_num, mode); } @@ -4215,6 +4269,94 @@ /* The sysfs simple class interface */ +static ssize_t st_last_cmnd_show(struct class_device *class_dev, char *buf) +{ + struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); + int i; + char last_cmnd_as_string[2*MAX_COMMAND_SIZE+1]; + + /* convert unsigned char array into string */ + for(i=0; icmdstat->last_cmnd[i]); + } + + return snprintf(buf, PAGE_SIZE, "0x%s\n", last_cmnd_as_string); +} +CLASS_DEVICE_ATTR(last_cmnd, S_IRUGO, st_last_cmnd_show, NULL); + +static ssize_t st_last_sense_show(struct class_device *class_dev, char *buf) +{ + struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); + int i; + char last_sense_as_string[2*SCSI_SENSE_BUFFERSIZE+1]; + + /* convert unsigned char array into string */ + for(i=0; icmdstat->last_sense[i]); + } + + return snprintf(buf, PAGE_SIZE, "0x%s\n", last_sense_as_string); +} +CLASS_DEVICE_ATTR(last_sense, S_IRUGO, st_last_sense_show, NULL); + +static ssize_t st_primary_sense_show(struct class_device *class_dev, char *buf) +{ + struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); + struct scsi_sense_hdr sshdr; + + scsi_normalize_sense(STm->cmdstat->last_sense,SCSI_SENSE_BUFFERSIZE,&sshdr); + + return snprintf(buf, PAGE_SIZE, "%s\n", (scsi_sense_key_string(sshdr.sense_key) == NULL)?"":scsi_sense_key_string(sshdr.sense_key)); +} +CLASS_DEVICE_ATTR(primary_sense, S_IRUGO, st_primary_sense_show, NULL); + +static ssize_t st_extended_sense_show(struct class_device *class_dev, char *buf) +{ + struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); + struct scsi_sense_hdr sshdr; + const char *extd_sense_fmt; + int ret; + + scsi_normalize_sense(STm->cmdstat->last_sense,SCSI_SENSE_BUFFERSIZE,&sshdr); + extd_sense_fmt = scsi_extd_sense_format(sshdr.asc, sshdr.ascq); + + if (extd_sense_fmt) { + if (strstr(extd_sense_fmt, "%x")){ + ret = snprintf(buf, PAGE_SIZE, extd_sense_fmt, sshdr.ascq); + /* carefully add trailing newline (there must + be a better way to do this!!) */ + if(ret < PAGE_SIZE){ + strcat(buf,"\n"); + ret++; + } + return ret; + } + else + return snprintf(buf, PAGE_SIZE, "%s\n", extd_sense_fmt); + } else { + if (sshdr.asc >= 0x80) + return snprintf(buf, PAGE_SIZE, "<> ASC=0x%02x ASCQ=0x%02x\n", sshdr.asc,sshdr.ascq); + else if (sshdr.ascq >= 0x80) + return snprintf(buf, PAGE_SIZE, "ASC=0x%02x <> ASCQ=0x%02x\n", sshdr.asc,sshdr.ascq); + else + return snprintf(buf, PAGE_SIZE, "ASC=0x%x ASCQ=0x%x\n", sshdr.asc,sshdr.ascq); + } + + +} +CLASS_DEVICE_ATTR(extended_sense, S_IRUGO, st_extended_sense_show, NULL); + +static ssize_t st_sense_flags_show(struct class_device *class_dev, char *buf) +{ + struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); + return snprintf(buf, PAGE_SIZE,"%s%s%s\n", + (STm->cmdstat->last_sense[2] & SENSE_ILI)?"ILI ":"", + (STm->cmdstat->last_sense[2] & SENSE_FMK)?"FM ":"", + (STm->cmdstat->last_sense[2] & SENSE_EOM)?"EOM ":"" + ); +} +CLASS_DEVICE_ATTR(sense_flags, S_IRUGO, st_sense_flags_show, NULL); + static ssize_t st_defined_show(struct class_device *class_dev, char *buf) { struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); @@ -4296,7 +4438,21 @@ &class_device_attr_default_density); class_device_create_file(st_class_member, &class_device_attr_default_compression); + if (mode == 0 && rew == 0) { + + /* put all per-device params in stN */ + class_device_create_file(st_class_member, + &class_device_attr_last_cmnd); + class_device_create_file(st_class_member, + &class_device_attr_last_sense); + class_device_create_file(st_class_member, + &class_device_attr_primary_sense); + class_device_create_file(st_class_member, + &class_device_attr_extended_sense); + class_device_create_file(st_class_member, + &class_device_attr_sense_flags); + error = sysfs_create_link(&STp->device->sdev_gendev.kobj, &st_class_member->kobj, "tape");