/* This program issues add-single-device commands to /proc/scsi/scsi for all SCSI hosts found in /proc/scsi/sbp2*?/. It can be used as a stand-alone binary, to be run in initrd, or compiled into other programs (in compliance with the GNU GPL) that may call rescan_scsi_bus(chmax, idmax, lunmax) to scan channels from 0 to chmax, IDs from 0 to idmax, Luns from 0 to lunmax, in all SCSI hosts found in the current directory (that is expected to be /proc/scsi). Copyright (C) 2003 Alexandre Oliva based on the rescan-scsi-bus.sh script by Kurt Garloff This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include /* Variables to determine the ranges to be scanned for each SCSI host. Set from the arguments passed to rescan_scsi_bus(int, int, int). */ static int channel_max, id_max, lun_max; /* Tell /proc/scsi/scsi to attempt to add a device for all combinations of channel, id and lun in the given SCSI host. */ static void add_devices_for_host (int host) { int channel, id, lun; for (channel = 0; channel <= channel_max; channel++) for (id = 0; id <= id_max; id++) for (lun = 0; lun <= lun_max; lun++) { /* This assumes CWD is /proc/scsi. */ FILE *proc_scsi_scsi = fopen ("scsi", "w"); if (! proc_scsi_scsi) return; fprintf (proc_scsi_scsi, "scsi add-single-device %i %i %i %i\n", host, channel, id, lun); fclose (proc_scsi_scsi); } } /* Look for a files whose names are decimal numbers, take them as a SCSI host numbers and scan them. */ static int scan_driver_dir (const struct dirent *entry) { char *endptr; int host; host = strtol (entry->d_name, &endptr, 10); if (*endptr) { #if 0 if (entry->d_name[0] == '.' || strcmp (entry->d_name, "add_map") == 0 || strcmp (entry->d_name, "map") == 0 || strcmp (entry->d_name, "mod_parm") == 0) return 0; if (strcmp (entry->d_name, "status") == 0) { /* FIXME: extract host from a line that looks like: SCSI host number: This file AFAIK is only present in kernel 2.6, that AFAIK doesn't really need rescanning. */ host = ...; } else #endif return 0; } add_devices_for_host (host); return 0; } /* Skipping drivers that make no sense to scan, scan scsi hosts. */ static int rescan_driver_bus (const struct dirent *entry) { struct dirent **namelist; #if 1 /* We only want to rescan sbp2 buses for now. */ if (strncmp (entry->d_name, "sbp2", 4) != 0) return 0; #else if (entry->d_name[0] == '.' || strcmp (entry->d_name, "scsi") == 0 || strcmp (entry->d_name, "sg") == 0 || strcmp (entry->d_name, "dummy") == 0) return 0; #endif scandir (entry->d_name, &namelist, scan_driver_dir, NULL); return 0; } /* Main entry point. CWD must be /proc/scsi. CHMAX, IDMAX and LUNMAX are the maximum numbers to scan in each SCSI host. */ void rescan_scsi_bus(int chmax, int idmax, int lunmax) { struct dirent **namelist; channel_max = chmax; id_max = idmax; lun_max = lunmax; scandir (".", &namelist, rescan_driver_bus, NULL); } #ifdef MAIN int main() { if (chdir ("/proc/scsi")) return 0; rescan_scsi_bus (0, 7, 0); return 0; } #endif