diff -uNr linux-2.4.18.S18.fixed/Documentation/scsi-devs.sh linux-2.4.18.S18.sdmany/Documentation/scsi-devs.sh --- linux-2.4.18.S18.fixed/Documentation/scsi-devs.sh Thu Jan 1 01:00:00 1970 +++ linux-2.4.18.S18.sdmany/Documentation/scsi-devs.sh Fri Jun 14 22:37:11 2002 @@ -0,0 +1,154 @@ +#!/bin/bash +# Script to create SCSI device nodes according to their physical +# address (host controller no,bus/channel,target SCSI ID,unit SCSI LUN) +# using the /proc/scsi/map introduced in Linux 2.4.20pre/2.5.2x +# (c) Kurt Garloff , 2002-06-13 +# License: GNU GPL v2 + +# Settings + +# Target directory for device nodes/links +TDIR=/dev/scsi + +# Make symbolic links or create fresh nodes in $TDIR +# For link mode, the dev nodes will still be made if needed +MODE= + +# In link mode, where is the real /dev dir ? +DEVDIR=.. + +# Ownership and permissions of newly created device nodes +OWNER="root.disk" +PERM="0660" +SDIRPERM="0755" + +# Make scsi disk partitions (0 = off) +SDPART=15 + +# End of settings + +# Options +# -f: Remove all old devs +if test "$1" = "-f"; then + rm -f $TDIR/* + shift +fi +# -l: Make links +if test "$1" = "-l"; then + MODE=LINK + shift +fi + +# Sanitize environment +export LANG=posix +unset IFS +#umask `printf %o $[0777-$PERM]` +PATH=/bin:/usr/bin:/sbin:/usr/sbin + +# Functions +function exit_fail +{ + echo $1 + exit $2 +} + +# Build new scsi name based on oldname (prefix) and +# append host,channel,id,lun numbers that are unique +# and persistent identifiers for the device. +function builddevnm +{ + if test "${5:0:2}" = "sd"; then + NM="sdc$1b$2t${3#0}u${4#0}" + else + NM="${5%%[0-9]*}c$1b$2t${3#0}u${4#0}" + fi +} + +# Make device node +# Parameters filename type maj(hex) min(hex) minadd(dec) +function mk_nod +{ + rm -f $1 + mknod -m $PERM $1 $2 $[0x$3] $[0x$4+$5] + chown $OWNER $1 +} + +# Make device by creating node or symlinking +# Parameters oldname device(tp:maj:min) newname minadd +function mk_dev +{ + IFS=":" + if test "$MODE" = "LINK"; then + if test ! -e $TDIR/$DEVDIR/$1; then + mk_nod $TDIR/$DEVDIR/$1 $2 $4 + fi + ln -sf $DEVDIR/$1 $TDIR/$3 + else + mk_nod $TDIR/$3 $2 $4 + fi + unset IFS +} + +# Make multiple devices in case we do have sd partitions +# Parameters oldname device(tp:maj:min) newname +function mk_devs +{ + mk_dev $1 $2 $3 0 + # Handle partitions + if test "${1:0:2}" = "sd" -a "$SDPART" != "0"; then + #unset IFS + for no in `seq 1 $SDPART`; do + mk_dev $1$no $2 $3p$no $no + done + fi + # Handle nst/nosst + if test "${1:0:2}" = "st" -o "${1:0:4}" = "osst"; then + mk_dev n$1 $2 n$3 128 + fi +} + +# Main() Script +if ! test -e /proc/scsi/map; then + exit_fail "/proc/scsi/map does not exist" 1 +fi +if ! test -d $TDIR; then + mkdir -m $SDIRMODE $TDIR || exit_fail "Failed to create $TDIR" 2 + chown $OWNER $TDIR +fi + +# We might have been called by some sort of hotplug event +# and are only support to add a single device +# Syntax for this is [-l] add host channel id lun +if test "$1" = "add"; then + CMPAGAINST="$2,$3,`printf %02i $4`,`printf %02i $5`" +else + unset CMPAGAINST +fi +# The main processing loop +while read cbtu tp onl sgnm sgdev othnm othdev oothnm oothdev rest; do + # Skip comment line(s) + if test "${cbtu:0:1}" = "#"; then continue; fi + # If we're just dealing with one device, do skip the others + if test ! -z "$CMPAGAINST" -a "$CMPAGAINST" != "$cbtu"; then continue; fi + # now parse line + IFS="," + # Test for validity of sg device + if test "$sgnm" != "sg?"; then + builddevnm $cbtu $sgnm + mk_dev $sgnm $sgdev $NM 0 + fi + # There is possibly a second device + if test ! -z "$othnm" -a ! "$othnm" = "none"; then + IFS="," + builddevnm $cbtu $othnm + mk_devs $othnm $othdev $NM + # Maybe even a third one + if test ! -z "$oothnm" -a ! "$oothnm" = "none"; then + IFS="," + builddevnm $cbtu $oothnm + mk_devs $oothnm $oothdev $NM + fi + fi + unset IFS +done < /proc/scsi/map + diff -uNr linux-2.4.18.S18.fixed/drivers/scsi/hosts.h linux-2.4.18.S18.sdmany/drivers/scsi/hosts.h --- linux-2.4.18.S18.fixed/drivers/scsi/hosts.h Wed Jun 12 11:37:09 2002 +++ linux-2.4.18.S18.sdmany/drivers/scsi/hosts.h Wed Jun 12 11:53:54 2002 @@ -530,6 +530,7 @@ void (*detach)(Scsi_Device *); int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code. Selects command for blkdevs */ + int (*find_kdev)(Scsi_Device *, char*, kdev_t*); /* find back dev. */ }; void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt); diff -uNr linux-2.4.18.S18.fixed/drivers/scsi/osst.c linux-2.4.18.S18.sdmany/drivers/scsi/osst.c --- linux-2.4.18.S18.fixed/drivers/scsi/osst.c Fri Dec 21 18:41:55 2001 +++ linux-2.4.18.S18.sdmany/drivers/scsi/osst.c Wed Jun 12 11:39:47 2002 @@ -156,6 +156,7 @@ static int osst_attach(Scsi_Device *); static int osst_detect(Scsi_Device *); static void osst_detach(Scsi_Device *); +static int osst_find_kdev(Scsi_Device *, char*, kdev_t*); struct Scsi_Device_Template osst_template = { @@ -166,7 +167,8 @@ detect: osst_detect, init: osst_init, attach: osst_attach, - detach: osst_detach + detach: osst_detach, + find_kdev: osst_find_kdev, }; static int osst_int_ioctl(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, unsigned int cmd_in,unsigned long arg); @@ -5417,6 +5419,24 @@ return 0; } +static int osst_find_kdev(Scsi_Device *sdp, char* nm, kdev_t *dev) +{ + int i; + OS_Scsi_Tape *ostp; + + if (sdp && sdp->type == TYPE_TAPE && osst_supports(sdp)) { + for (ostp = os_scsi_tapes[i = 0]; i < osst_template.dev_max; + ostp = os_scsi_tapes[++i]) { + if (ostp && ostp->device == sdp) { + sprintf (nm, "osst%i", i); + *dev = MKDEV(OSST_MAJOR, i); + return 0; + } + } + } + return 1; +} + static int osst_attach(Scsi_Device * SDp) { OS_Scsi_Tape * tpnt; diff -uNr linux-2.4.18.S18.fixed/drivers/scsi/scsi.c linux-2.4.18.S18.sdmany/drivers/scsi/scsi.c --- linux-2.4.18.S18.fixed/drivers/scsi/scsi.c Wed Jun 12 11:37:07 2002 +++ linux-2.4.18.S18.sdmany/drivers/scsi/scsi.c Fri Jun 14 12:49:15 2002 @@ -80,6 +80,7 @@ #ifdef CONFIG_PROC_FS static int scsi_proc_info(char *buffer, char **start, off_t offset, int length); +static int scsi_proc_map (char *buffer, char **start, off_t offset, int length); static void scsi_dump_status(int level); #endif @@ -1554,6 +1555,70 @@ } #ifdef CONFIG_PROC_FS +/* + * Output the mapping of physical devices (contorller,channel.id,lun) + * to devices (sg and other highlevel drivers) to /proc/scsi/map. + * Caveat: No locking is done, so if your scsi config changes during + * reading this file, you may read garbled data. KG, 2002-06-14 + */ +static int scsi_proc_map(char *buffer, char **start, off_t offset, int length) +{ + Scsi_Device *scd; + struct Scsi_Host *HBA_ptr; + int size = 0, len = 0, repeat = 0; + off_t begin = 0; + off_t pos = 0; + + struct Scsi_Device_Template *sg_t; + do { + sg_t = scsi_devicelist; + while (sg_t && !(sg_t->tag && !strcmp(sg_t->tag, "sg"))) + sg_t = sg_t->next; +#ifdef CONFIG_KMOD + if (!repeat && !sg_t) + request_module("sg"); + } while (!repeat++); +#else + } while (0); +#endif + /* + * First, see if there are any attached devices or not. + */ + for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) { + if (HBA_ptr->host_queue != NULL) { + break; + } + } + if (!HBA_ptr) + goto stop_map_output; + + size = sprintf(buffer + len, "# C,B,T,U\tType\tonl\tsg_nm\tsg_dev\tnm\tdev(hex)\n"); + len += size; + pos = begin + len; + + for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) { + for (scd = HBA_ptr->host_queue; scd; scd = scd->next) { + proc_print_scsimap(scd, buffer, &size, len, sg_t); + len += size; + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_map_output; + } + } + + stop_map_output: + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Start slop */ + if (len > length) + len = length; /* Ending slop */ + return (len); +} + static int scsi_proc_info(char *buffer, char **start, off_t offset, int length) { Scsi_Device *scd; @@ -2578,6 +2643,7 @@ static int __init init_scsi(void) { struct proc_dir_entry *generic; + struct proc_dir_entry *map; printk(KERN_INFO "SCSI subsystem driver " REVISION "\n"); @@ -2602,6 +2668,13 @@ return -ENOMEM; } generic->write_proc = proc_scsi_gen_write; + + map = create_proc_info_entry ("scsi/map", 0, 0, scsi_proc_map); + if (!map) { + printk (KERN_ERR "cannot init /proc/scsi/map\n"); + remove_proc_entry("scsi", 0); + return -ENOMEM; + } #endif scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", NULL); @@ -2636,6 +2709,7 @@ #ifdef CONFIG_PROC_FS /* No, we're not here anymore. Don't show the /proc/scsi files. */ + remove_proc_entry ("scsi/map", 0); remove_proc_entry ("scsi/scsi", 0); remove_proc_entry ("scsi", 0); #endif diff -uNr linux-2.4.18.S18.fixed/drivers/scsi/scsi.h linux-2.4.18.S18.sdmany/drivers/scsi/scsi.h --- linux-2.4.18.S18.fixed/drivers/scsi/scsi.h Wed Jun 12 11:37:07 2002 +++ linux-2.4.18.S18.sdmany/drivers/scsi/scsi.h Wed Jun 12 11:53:54 2002 @@ -517,6 +517,8 @@ * Prototypes for functions in scsi_proc.c */ extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int); +extern void proc_print_scsimap(Scsi_Device *, char *, int *, int, + struct Scsi_Device_Template *); extern struct proc_dir_entry *proc_scsi; /* diff -uNr linux-2.4.18.S18.fixed/drivers/scsi/scsi_proc.c linux-2.4.18.S18.sdmany/drivers/scsi/scsi_proc.c --- linux-2.4.18.S18.fixed/drivers/scsi/scsi_proc.c Thu Jun 28 02:10:55 2001 +++ linux-2.4.18.S18.sdmany/drivers/scsi/scsi_proc.c Fri Jun 14 00:30:42 2002 @@ -301,11 +301,66 @@ return; } + + + +void proc_print_scsimap(Scsi_Device *scd, char *buffer, int *size, int len, + struct Scsi_Device_Template *sg_t) +{ + int y, err = 0; + char nm[16]; + kdev_t kdev; + int att = scd->attached; + struct Scsi_Device_Template *sd_t = scsi_devicelist; + + y = sprintf(buffer + len, + "%i,%i,%02i,%02i\t0x%02x\t%i", + scd->host->host_no, scd->channel, scd->id, scd->lun, + scd->type, scd->online); + if (sg_t && sg_t->find_kdev) { + err = sg_t->find_kdev(scd, nm, &kdev); + if (!err) { + y += sprintf(buffer + len + y, + "\t%s\tc:%02x:%02x", nm, MAJOR(kdev), MINOR(kdev)); + --att; + } else { + printk (KERN_ERR "scsimap: sg device not found?!\n"); + y += sprintf(buffer + len + y, + "\tsg?\tc:NN:NN"); + } + } else { + printk (KERN_INFO "scsimap: need sg support to report sg devices\n"); + y += sprintf(buffer + len + y, + "\tsg?\tc:NN:NN"); + } + while (att && sd_t) { + if (sd_t->scsi_type != 0xff && sd_t->find_kdev) { + err = sd_t->find_kdev(scd, nm, &kdev); + if (!err) { + y += sprintf(buffer + len + y, + "\t%s\t%c:%02x:%02x", + nm, (sd_t->blk? 'b': 'c'), + MAJOR(kdev), MINOR(kdev)); + --att; + } + } + sd_t = sd_t->next; + } + + map_out: + y += sprintf(buffer + len + y, "\n"); + *size = y; + return; +} + #else /* if !CONFIG_PROC_FS */ void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len) { } +void proc_print_scsimap(Scsi_Device *scd, char *buffer, int *size, int len) +{ +} #endif /* CONFIG_PROC_FS */ diff -uNr linux-2.4.18.S18.fixed/drivers/scsi/sd.c linux-2.4.18.S18.sdmany/drivers/scsi/sd.c --- linux-2.4.18.S18.fixed/drivers/scsi/sd.c Wed Jun 12 11:37:13 2002 +++ linux-2.4.18.S18.sdmany/drivers/scsi/sd.c Wed Jun 12 11:39:47 2002 @@ -109,6 +109,7 @@ static int sd_detect(Scsi_Device *); static void sd_detach(Scsi_Device *); static int sd_init_command(Scsi_Cmnd *); +static int sd_find_kdev(Scsi_Device*, char*, kdev_t*); static struct Scsi_Device_Template sd_template = { name:"disk", @@ -127,6 +128,7 @@ attach:sd_attach, detach:sd_detach, init_command:sd_init_command, + find_kdev:sd_find_kdev, }; @@ -281,6 +283,23 @@ } } +static int sd_find_kdev(Scsi_Device *sdp, char* nm, kdev_t *dev) +{ + Scsi_Disk *dp; + int i; + + if (sdp && (sdp->type == TYPE_DISK || sdp->type == TYPE_MOD)) { + for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp) { + if (dp->device == sdp) { + sd_devname(i, nm); + *dev = MKDEV_SD(i); + return 0; + } + } + } + return 1; +} + static request_queue_t *sd_find_queue(kdev_t dev) { Scsi_Disk *dpnt; diff -uNr linux-2.4.18.S18.fixed/drivers/scsi/sg.c linux-2.4.18.S18.sdmany/drivers/scsi/sg.c --- linux-2.4.18.S18.fixed/drivers/scsi/sg.c Wed Jun 12 11:37:04 2002 +++ linux-2.4.18.S18.sdmany/drivers/scsi/sg.c Wed Jun 12 15:27:55 2002 @@ -115,6 +115,7 @@ static void sg_finish(void); static int sg_detect(Scsi_Device *); static void sg_detach(Scsi_Device *); +static int sg_find_kdev(Scsi_Device *, char*, kdev_t*); static Scsi_Request * dummy_cmdp; /* only used for sizeof */ @@ -123,6 +124,7 @@ static struct Scsi_Device_Template sg_template = { + name:"generic", tag:"sg", scsi_type:0xff, major:SCSI_GENERIC_MAJOR, @@ -130,7 +132,8 @@ init:sg_init, finish:sg_finish, attach:sg_attach, - detach:sg_detach + detach:sg_detach, + find_kdev:sg_find_kdev }; @@ -2696,6 +2699,36 @@ } #ifdef CONFIG_PROC_FS +static int sg_find_kdev(Scsi_Device* sdp, char *nm, kdev_t *dev) +{ + unsigned long iflags; + int err = 1; + + if (sdp && sg_dev_arr) { + int k; + read_lock_irqsave(&sg_dev_arr_lock, iflags); + for (k = 0; k < sg_template.dev_max; ++k) { + if (sg_dev_arr[k] && sg_dev_arr[k]->device == sdp) { + sprintf (nm, "sg%i", k); + *dev = sg_dev_arr[k]->i_rdev; + err = 0; + break; + } + } + read_unlock_irqrestore(&sg_dev_arr_lock, iflags); + } + return err; +} +#else +/* Not needed without procfs support */ +static int sg_find_kdev(Scsi_Device* sdp, char *nm, kdev_t *dev) +{ + *nm = 0; *kdev = MKDEV(255,255); + return 1; +} +#endif + +#ifdef CONFIG_PROC_FS static struct proc_dir_entry * sg_proc_sgp = NULL; diff -uNr linux-2.4.18.S18.fixed/drivers/scsi/sr.c linux-2.4.18.S18.sdmany/drivers/scsi/sr.c --- linux-2.4.18.S18.fixed/drivers/scsi/sr.c Wed Jun 12 11:37:15 2002 +++ linux-2.4.18.S18.sdmany/drivers/scsi/sr.c Wed Jun 12 11:39:47 2002 @@ -69,6 +69,8 @@ static int sr_init_command(Scsi_Cmnd *); +static int sr_find_kdev(Scsi_Device*, char*, kdev_t*); + static struct Scsi_Device_Template sr_template = { name:"cdrom", @@ -81,7 +83,8 @@ finish:sr_finish, attach:sr_attach, detach:sr_detach, - init_command:sr_init_command + init_command:sr_init_command, + find_kdev:sr_find_kdev, }; Scsi_CD *scsi_CDs; @@ -586,6 +589,22 @@ return 0; } +static int sr_find_kdev(Scsi_Device *sdp, char* nm, kdev_t *dev) +{ + Scsi_CD *srp; + int i; + + if (sdp && (sdp->type == TYPE_ROM || sdp->type == TYPE_WORM)) { + for (srp = scsi_CDs, i = 0; i < sr_template.dev_max; ++i, ++srp) { + if (srp->device == sdp) { + sprintf(nm, "sr%i", i); + *dev = MKDEV(SCSI_CDROM_MAJOR,i); + return 0; + } + } + } + return 1; +} void get_sectorsize(int i) { diff -uNr linux-2.4.18.S18.fixed/drivers/scsi/st.c linux-2.4.18.S18.sdmany/drivers/scsi/st.c --- linux-2.4.18.S18.fixed/drivers/scsi/st.c Mon Feb 25 20:38:04 2002 +++ linux-2.4.18.S18.sdmany/drivers/scsi/st.c Wed Jun 12 11:39:47 2002 @@ -164,6 +164,7 @@ static int st_attach(Scsi_Device *); static int st_detect(Scsi_Device *); static void st_detach(Scsi_Device *); +static int st_find_kdev(Scsi_Device*, char*, kdev_t*); static struct Scsi_Device_Template st_template = { @@ -174,7 +175,8 @@ detect:st_detect, init:st_init, attach:st_attach, - detach:st_detach + detach:st_detach, + find_kdev:st_find_kdev, }; static int st_compression(Scsi_Tape *, int); @@ -3827,6 +3829,23 @@ return 1; } +static int st_find_kdev(Scsi_Device * sdp, char* nm, kdev_t *dev) +{ + int i; + Scsi_Tape *stp; + + if (sdp && sdp->type == TYPE_TAPE && !st_incompatible(sdp)) { + for (stp = scsi_tapes[0], i = 0; i < st_template.dev_max; stp=scsi_tapes[++i]) { + if (stp && stp->device == sdp) { + sprintf(nm, "st%i", i); + *dev = MKDEV (SCSI_TAPE_MAJOR, i); + return 0; + } + } + } + return 1; +} + static int st_registered = 0; /* Driver initialization (not __init because may be called later) */