11da177e4SLinus Torvalds 21da177e4SLinus Torvalds #include <linux/blkdev.h> 31da177e4SLinus Torvalds #include <linux/init.h> 41da177e4SLinus Torvalds #include <linux/kernel.h> 51da177e4SLinus Torvalds #include <linux/module.h> 61da177e4SLinus Torvalds #include <linux/moduleparam.h> 71da177e4SLinus Torvalds #include <linux/proc_fs.h> 81da177e4SLinus Torvalds #include <linux/seq_file.h> 95a0e3ad6STejun Heo #include <linux/slab.h> 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds #include <scsi/scsi_device.h> 121da177e4SLinus Torvalds #include <scsi/scsi_devinfo.h> 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include "scsi_priv.h" 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds /* 181da177e4SLinus Torvalds * scsi_dev_info_list: structure to hold black/white listed devices. 191da177e4SLinus Torvalds */ 201da177e4SLinus Torvalds struct scsi_dev_info_list { 211da177e4SLinus Torvalds struct list_head dev_info_list; 221da177e4SLinus Torvalds char vendor[8]; 231da177e4SLinus Torvalds char model[16]; 241da177e4SLinus Torvalds unsigned flags; 251da177e4SLinus Torvalds unsigned compatible; /* for use with scsi_static_device_list entries */ 261da177e4SLinus Torvalds }; 271da177e4SLinus Torvalds 28598fa4b7SJames Bottomley struct scsi_dev_info_list_table { 29598fa4b7SJames Bottomley struct list_head node; /* our node for being on the master list */ 30598fa4b7SJames Bottomley struct list_head scsi_dev_info_list; /* head of dev info list */ 31598fa4b7SJames Bottomley const char *name; /* name of list for /proc (NULL for global) */ 32598fa4b7SJames Bottomley int key; /* unique numeric identifier */ 33598fa4b7SJames Bottomley }; 34598fa4b7SJames Bottomley 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds static const char spaces[] = " "; /* 16 of them */ 371da177e4SLinus Torvalds static unsigned scsi_default_dev_flags; 381da177e4SLinus Torvalds static LIST_HEAD(scsi_dev_info_list); 391da177e4SLinus Torvalds static char scsi_dev_flags[256]; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds /* 421da177e4SLinus Torvalds * scsi_static_device_list: deprecated list of devices that require 431da177e4SLinus Torvalds * settings that differ from the default, includes black-listed (broken) 441da177e4SLinus Torvalds * devices. The entries here are added to the tail of scsi_dev_info_list 451da177e4SLinus Torvalds * via scsi_dev_info_list_init. 461da177e4SLinus Torvalds * 471da177e4SLinus Torvalds * Do not add to this list, use the command line or proc interface to add 481da177e4SLinus Torvalds * to the scsi_dev_info_list. This table will eventually go away. 491da177e4SLinus Torvalds */ 501da177e4SLinus Torvalds static struct { 511da177e4SLinus Torvalds char *vendor; 521da177e4SLinus Torvalds char *model; 531da177e4SLinus Torvalds char *revision; /* revision known to be bad, unused */ 541da177e4SLinus Torvalds unsigned flags; 551da177e4SLinus Torvalds } scsi_static_device_list[] __initdata = { 561da177e4SLinus Torvalds /* 571da177e4SLinus Torvalds * The following devices are known not to tolerate a lun != 0 scan 581da177e4SLinus Torvalds * for one reason or another. Some will respond to all luns, 591da177e4SLinus Torvalds * others will lock up. 601da177e4SLinus Torvalds */ 611da177e4SLinus Torvalds {"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN}, /* locks up */ 621da177e4SLinus Torvalds {"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN}, /* locks up */ 631da177e4SLinus Torvalds {"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN}, /* locks up */ 641da177e4SLinus Torvalds {"DENON", "DRD-25X", "V", BLIST_NOLUN}, /* locks up */ 651da177e4SLinus Torvalds {"HITACHI", "DK312C", "CM81", BLIST_NOLUN}, /* responds to all lun */ 661da177e4SLinus Torvalds {"HITACHI", "DK314C", "CR21", BLIST_NOLUN}, /* responds to all lun */ 67f2536cbdSBrian King {"IBM", "2104-DU3", NULL, BLIST_NOLUN}, /* locks up */ 68f2536cbdSBrian King {"IBM", "2104-TU3", NULL, BLIST_NOLUN}, /* locks up */ 691da177e4SLinus Torvalds {"IMS", "CDD521/10", "2.06", BLIST_NOLUN}, /* locks up */ 701da177e4SLinus Torvalds {"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN}, /* locks up */ 711da177e4SLinus Torvalds {"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN}, /* locks up */ 721da177e4SLinus Torvalds {"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN}, /* locks up */ 731da177e4SLinus Torvalds {"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN}, /* locks up */ 741da177e4SLinus Torvalds {"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN}, /* locks up */ 751da177e4SLinus Torvalds {"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN}, /* responds to all lun */ 761da177e4SLinus Torvalds {"MICROTEK", "ScanMakerIII", "2.30", BLIST_NOLUN}, /* responds to all lun */ 771da177e4SLinus Torvalds {"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},/* locks up */ 781da177e4SLinus Torvalds {"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN}, /* responds to all lun */ 791da177e4SLinus Torvalds {"RODIME", "RO3000S", "2.33", BLIST_NOLUN}, /* locks up */ 801da177e4SLinus Torvalds {"SUN", "SENA", NULL, BLIST_NOLUN}, /* responds to all luns */ 811da177e4SLinus Torvalds /* 821da177e4SLinus Torvalds * The following causes a failed REQUEST SENSE on lun 1 for 831da177e4SLinus Torvalds * aha152x controller, which causes SCSI code to reset bus. 841da177e4SLinus Torvalds */ 851da177e4SLinus Torvalds {"SANYO", "CRD-250S", "1.20", BLIST_NOLUN}, 861da177e4SLinus Torvalds /* 871da177e4SLinus Torvalds * The following causes a failed REQUEST SENSE on lun 1 for 881da177e4SLinus Torvalds * aha152x controller, which causes SCSI code to reset bus. 891da177e4SLinus Torvalds */ 901da177e4SLinus Torvalds {"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN}, 911da177e4SLinus Torvalds {"SEAGATE", "ST296", "921", BLIST_NOLUN}, /* responds to all lun */ 921da177e4SLinus Torvalds {"SEAGATE", "ST1581", "6538", BLIST_NOLUN}, /* responds to all lun */ 931da177e4SLinus Torvalds {"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN}, 941da177e4SLinus Torvalds {"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN}, 951da177e4SLinus Torvalds {"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN}, 961da177e4SLinus Torvalds {"SONY", "CD-ROM CDU-8012", NULL, BLIST_NOLUN}, 971da177e4SLinus Torvalds {"SONY", "SDT-5000", "3.17", BLIST_SELECT_NO_ATN}, 981da177e4SLinus Torvalds {"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN}, /* locks up */ 991da177e4SLinus Torvalds {"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN}, /* locks up */ 1001da177e4SLinus Torvalds /* 1011da177e4SLinus Torvalds * The following causes a failed REQUEST SENSE on lun 1 for 1021da177e4SLinus Torvalds * seagate controller, which causes SCSI code to reset bus. 1031da177e4SLinus Torvalds */ 1041da177e4SLinus Torvalds {"TEAC", "CD-ROM", "1.06", BLIST_NOLUN}, 1051da177e4SLinus Torvalds {"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN}, /* responds to all lun */ 1061da177e4SLinus Torvalds /* 1071da177e4SLinus Torvalds * The following causes a failed REQUEST SENSE on lun 1 for 1081da177e4SLinus Torvalds * seagate controller, which causes SCSI code to reset bus. 1091da177e4SLinus Torvalds */ 1101da177e4SLinus Torvalds {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ 1111da177e4SLinus Torvalds {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ 1121da177e4SLinus Torvalds {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ 1131da177e4SLinus Torvalds {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN}, /* locks up */ 1141da177e4SLinus Torvalds {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all lun */ 1151da177e4SLinus Torvalds {"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN}, /* locks up */ 1161da177e4SLinus Torvalds {"NEC", "D3856", "0009", BLIST_NOLUN}, 1171da177e4SLinus Torvalds {"QUANTUM", "LPS525S", "3110", BLIST_NOLUN}, /* locks up */ 1181da177e4SLinus Torvalds {"QUANTUM", "PD1225S", "3110", BLIST_NOLUN}, /* locks up */ 1191da177e4SLinus Torvalds {"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN}, /* locks up */ 1201da177e4SLinus Torvalds {"RELISYS", "Scorpio", NULL, BLIST_NOLUN}, /* responds to all lun */ 1211da177e4SLinus Torvalds {"SANKYO", "CP525", "6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */ 1221da177e4SLinus Torvalds {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN}, 1231c536315SJames Bottomley {"transtec", "T5008", "0001", BLIST_NOREPORTLUN }, 1241da177e4SLinus Torvalds {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* locks up */ 1251da177e4SLinus Torvalds {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* locks up */ 1261da177e4SLinus Torvalds {"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN}, /* locks up */ 1271da177e4SLinus Torvalds {"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN}, /* locks up */ 1280d7323c8SDave Jones {"", "Scanner", "1.80", BLIST_NOLUN}, /* responds to all lun */ 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds /* 1311da177e4SLinus Torvalds * Other types of devices that have special flags. 1321da177e4SLinus Torvalds * Note that all USB devices should have the BLIST_INQUIRY_36 flag. 1331da177e4SLinus Torvalds */ 1341da177e4SLinus Torvalds {"3PARdata", "VV", NULL, BLIST_REPORTLUN2}, 1351da177e4SLinus Torvalds {"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN}, 1361da177e4SLinus Torvalds {"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN}, 1371da177e4SLinus Torvalds {"AFT PRO", "-IX CF", "0.0>", BLIST_FORCELUN}, 1381da177e4SLinus Torvalds {"BELKIN", "USB 2 HS-CF", "1.95", BLIST_FORCELUN | BLIST_INQUIRY_36}, 13980dc3e06SMatthew Wilcox {"BROWNIE", "1200U3P", NULL, BLIST_NOREPORTLUN}, 14098acfc7eSMatthew Wilcox {"BROWNIE", "1600U3P", NULL, BLIST_NOREPORTLUN}, 1411da177e4SLinus Torvalds {"CANON", "IPUBJD", NULL, BLIST_SPARSELUN}, 1421da177e4SLinus Torvalds {"CBOX3", "USB Storage-SMC", "300A", BLIST_FORCELUN | BLIST_INQUIRY_36}, 1431da177e4SLinus Torvalds {"CMD", "CRA-7280", NULL, BLIST_SPARSELUN}, /* CMD RAID Controller */ 1441da177e4SLinus Torvalds {"CNSI", "G7324", NULL, BLIST_SPARSELUN}, /* Chaparral G7324 RAID */ 1451da177e4SLinus Torvalds {"CNSi", "G8324", NULL, BLIST_SPARSELUN}, /* Chaparral G8324 RAID */ 1464d7db04aSJames Bottomley {"COMPAQ", "ARRAY CONTROLLER", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | 1474d7db04aSJames Bottomley BLIST_MAX_512 | BLIST_REPORTLUN2}, /* Compaq RA4x00 */ 1484d7db04aSJames Bottomley {"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN | BLIST_MAX_512}, /* Compaq RA4x00 */ 1491da177e4SLinus Torvalds {"COMPAQ", "CR3500", NULL, BLIST_FORCELUN}, 1501da177e4SLinus Torvalds {"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, 1511da177e4SLinus Torvalds {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, 1521da177e4SLinus Torvalds {"COMPAQ", "HSV110", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, 1531da177e4SLinus Torvalds {"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN}, 154507caac7SJames Bottomley {"DEC", "HSG80", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, 1551da177e4SLinus Torvalds {"DELL", "PV660F", NULL, BLIST_SPARSELUN}, 1561da177e4SLinus Torvalds {"DELL", "PV660F PSEUDO", NULL, BLIST_SPARSELUN}, 1571da177e4SLinus Torvalds {"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN}, /* Dell PV 530F */ 1581da177e4SLinus Torvalds {"DELL", "PV530F", NULL, BLIST_SPARSELUN}, 1591da177e4SLinus Torvalds {"DELL", "PERCRAID", NULL, BLIST_FORCELUN}, 1601da177e4SLinus Torvalds {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */ 1611da177e4SLinus Torvalds {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */ 1623441afc6SMike Christie {"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 1631da177e4SLinus Torvalds {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, 1641da177e4SLinus Torvalds {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, 16580b1c7bdSakpm@linux-foundation.org {"easyRAID", "16P", NULL, BLIST_NOREPORTLUN}, 16680b1c7bdSakpm@linux-foundation.org {"easyRAID", "X6P", NULL, BLIST_NOREPORTLUN}, 16780b1c7bdSakpm@linux-foundation.org {"easyRAID", "F8", NULL, BLIST_NOREPORTLUN}, 1681da177e4SLinus Torvalds {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 1691da177e4SLinus Torvalds {"Generic", "USB SD Reader", "1.00", BLIST_FORCELUN | BLIST_INQUIRY_36}, 1701da177e4SLinus Torvalds {"Generic", "USB Storage-SMC", "0180", BLIST_FORCELUN | BLIST_INQUIRY_36}, 1711da177e4SLinus Torvalds {"Generic", "USB Storage-SMC", "0207", BLIST_FORCELUN | BLIST_INQUIRY_36}, 172627511e3STakahiro Yasui {"HITACHI", "DF400", "*", BLIST_REPORTLUN2}, 173627511e3STakahiro Yasui {"HITACHI", "DF500", "*", BLIST_REPORTLUN2}, 174627511e3STakahiro Yasui {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_REPORTLUN2}, 175d974e426SMartin K. Petersen {"HITACHI", "HUS1530", "*", BLIST_NO_DIF}, 176627511e3STakahiro Yasui {"HITACHI", "OPEN-", "*", BLIST_REPORTLUN2}, 177f70cfa9bSMike Christie {"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 178f70cfa9bSMike Christie {"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 179f70cfa9bSMike Christie {"HITACHI", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 180f70cfa9bSMike Christie {"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 181f70cfa9bSMike Christie {"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 1821da177e4SLinus Torvalds {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ 1839ba0883cSHannes Reinecke {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */ 1841da177e4SLinus Torvalds {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, 1851da177e4SLinus Torvalds {"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, 1861da177e4SLinus Torvalds {"HP", "C1557A", NULL, BLIST_FORCELUN}, 1871da177e4SLinus Torvalds {"HP", "C3323-300", "4269", BLIST_NOTQ}, 188c3d83368SThomas Bogendoerfer {"HP", "C5713A", NULL, BLIST_NOREPORTLUN}, 189f70cfa9bSMike Christie {"HP", "DF400", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 190f70cfa9bSMike Christie {"HP", "DF500", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 191f70cfa9bSMike Christie {"HP", "DF600", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 192f70cfa9bSMike Christie {"HP", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 193f70cfa9bSMike Christie {"HP", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 194f70cfa9bSMike Christie {"HP", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 195f70cfa9bSMike Christie {"HP", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 196f70cfa9bSMike Christie {"HP", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 1971da177e4SLinus Torvalds {"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN}, 1981da177e4SLinus Torvalds {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 1991da177e4SLinus Torvalds {"IBM", "2105", NULL, BLIST_RETRY_HWERROR}, 2001da177e4SLinus Torvalds {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, 20182103978SWerner Fink {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN}, 2021da177e4SLinus Torvalds {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, 2031da177e4SLinus Torvalds {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, 2041da177e4SLinus Torvalds {"INSITE", "I325VM", NULL, BLIST_KEY}, 20518990455SChristian Sünkenberg {"Intel", "Multi-Flex", NULL, BLIST_NO_RSOC}, 2061da177e4SLinus Torvalds {"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36}, 2071da177e4SLinus Torvalds {"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, 20882c43310SMika Westerberg {"Marvell", "Console", NULL, BLIST_SKIP_VPD_PAGES}, 209fb2d65d2STodd Fujinaka {"Marvell", "91xx Config", "1.01", BLIST_SKIP_VPD_PAGES}, 2101da177e4SLinus Torvalds {"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, 2111da177e4SLinus Torvalds {"MATSHITA", "DMC-LC5", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36}, 2121da177e4SLinus Torvalds {"MATSHITA", "DMC-LC40", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36}, 2131da177e4SLinus Torvalds {"Medion", "Flash XL MMC/SD", "2.6D", BLIST_FORCELUN}, 2141da177e4SLinus Torvalds {"MegaRAID", "LD", NULL, BLIST_FORCELUN}, 2151da177e4SLinus Torvalds {"MICROP", "4110", NULL, BLIST_NOTQ}, 216198a956aSMartin K. Petersen {"MSFT", "Virtual HD", NULL, BLIST_NO_RSOC}, 2171da177e4SLinus Torvalds {"MYLEX", "DACARMRB", "*", BLIST_REPORTLUN2}, 2181da177e4SLinus Torvalds {"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN}, 2191da177e4SLinus Torvalds {"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, 2201da177e4SLinus Torvalds {"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, 2211da177e4SLinus Torvalds {"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, 22212427d99SMike Christie {"NEC", "iStorage", NULL, BLIST_REPORTLUN2}, 223851cde99SHannes Reinecke {"NETAPP", "LUN C-Mode", NULL, BLIST_SYNC_ALUA}, 224851cde99SHannes Reinecke {"NETAPP", "INF-01-00", NULL, BLIST_SYNC_ALUA}, 2251da177e4SLinus Torvalds {"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, 2261da177e4SLinus Torvalds {"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, 2271da177e4SLinus Torvalds {"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, 2281da177e4SLinus Torvalds {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, 2291da177e4SLinus Torvalds {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, 230f4fd20bfSKarl Magnus Kolstoe {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, 2310213436aSJanusz Dziemidowicz {"Promise", "VTrak E610f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC}, 232e0b2e597SEd Lin {"Promise", "", NULL, BLIST_SPARSELUN}, 233fbd83006SEwan D. Milne {"QEMU", "QEMU CD-ROM", NULL, BLIST_SKIP_VPD_PAGES}, 23435e9a9f9SMike Christie {"QNAP", "iSCSI Storage", NULL, BLIST_MAX_1024}, 2359055082fSMike Christie {"SYNOLOGY", "iSCSI Storage", NULL, BLIST_MAX_1024}, 2362ffb45c6SMatthew Wilcox {"QUANTUM", "XP34301", "1071", BLIST_NOTQ}, 2371da177e4SLinus Torvalds {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, 2381da177e4SLinus Torvalds {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN}, 2391da177e4SLinus Torvalds {"SEAGATE", "ST34555N", "0930", BLIST_NOTQ}, /* Chokes on tagged INQUIRY */ 2401da177e4SLinus Torvalds {"SEAGATE", "ST3390N", "9546", BLIST_NOTQ}, 24156f2a801SMartin K. Petersen {"SEAGATE", "ST900MM0006", NULL, BLIST_SKIP_VPD_PAGES}, 2421da177e4SLinus Torvalds {"SGI", "RAID3", "*", BLIST_SPARSELUN}, 2431da177e4SLinus Torvalds {"SGI", "RAID5", "*", BLIST_SPARSELUN}, 2441da177e4SLinus Torvalds {"SGI", "TP9100", "*", BLIST_REPORTLUN2}, 2451da177e4SLinus Torvalds {"SGI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, 24648690405SAnton Blanchard {"IBM", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, 247debf4777SILLES, Marton {"SUN", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, 2484aa312b9SJames Bottomley {"DELL", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, 249*c6b269baSXose Vazquez Perez {"STK", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, 250*c6b269baSXose Vazquez Perez {"NETAPP", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, 251*c6b269baSXose Vazquez Perez {"LSI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, 252*c6b269baSXose Vazquez Perez {"ENGENIO", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, 2531da177e4SLinus Torvalds {"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36}, 2541da177e4SLinus Torvalds {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN}, 2551da177e4SLinus Torvalds {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ 2561da177e4SLinus Torvalds {"ST650211", "CF", NULL, BLIST_RETRY_HWERROR}, 2571da177e4SLinus Torvalds {"SUN", "T300", "*", BLIST_SPARSELUN}, 2581da177e4SLinus Torvalds {"SUN", "T4", "*", BLIST_SPARSELUN}, 2591da177e4SLinus Torvalds {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN}, 2605f619c5bSMike Christie {"Tornado-", "F4", "*", BLIST_NOREPORTLUN}, 2611da177e4SLinus Torvalds {"TOSHIBA", "CDROM", NULL, BLIST_ISROM}, 2621da177e4SLinus Torvalds {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM}, 26382103978SWerner Fink {"Traxdata", "CDR4120", NULL, BLIST_NOLUN}, /* locks up */ 2641da177e4SLinus Torvalds {"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36}, 2651da177e4SLinus Torvalds {"WangDAT", "Model 2600", "01.7", BLIST_SELECT_NO_ATN}, 2661da177e4SLinus Torvalds {"WangDAT", "Model 3200", "02.2", BLIST_SELECT_NO_ATN}, 2671da177e4SLinus Torvalds {"WangDAT", "Model 1300", "02.4", BLIST_SELECT_NO_ATN}, 2681da177e4SLinus Torvalds {"WDC WD25", "00JB-00FUA0", NULL, BLIST_NOREPORTLUN}, 2691da177e4SLinus Torvalds {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 2701da177e4SLinus Torvalds {"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN}, 2711da177e4SLinus Torvalds {"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN}, 2721da177e4SLinus Torvalds { NULL, NULL, NULL, 0 }, 2731da177e4SLinus Torvalds }; 2741da177e4SLinus Torvalds 275598fa4b7SJames Bottomley static struct scsi_dev_info_list_table *scsi_devinfo_lookup_by_key(int key) 276598fa4b7SJames Bottomley { 277598fa4b7SJames Bottomley struct scsi_dev_info_list_table *devinfo_table; 278598fa4b7SJames Bottomley int found = 0; 279598fa4b7SJames Bottomley 280598fa4b7SJames Bottomley list_for_each_entry(devinfo_table, &scsi_dev_info_list, node) 281598fa4b7SJames Bottomley if (devinfo_table->key == key) { 282598fa4b7SJames Bottomley found = 1; 283598fa4b7SJames Bottomley break; 284598fa4b7SJames Bottomley } 285598fa4b7SJames Bottomley if (!found) 286598fa4b7SJames Bottomley return ERR_PTR(-EINVAL); 287598fa4b7SJames Bottomley 288598fa4b7SJames Bottomley return devinfo_table; 289598fa4b7SJames Bottomley } 290598fa4b7SJames Bottomley 2911da177e4SLinus Torvalds /* 2921da177e4SLinus Torvalds * scsi_strcpy_devinfo: called from scsi_dev_info_list_add to copy into 2931da177e4SLinus Torvalds * devinfo vendor and model strings. 2941da177e4SLinus Torvalds */ 2951da177e4SLinus Torvalds static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length, 2961da177e4SLinus Torvalds char *from, int compatible) 2971da177e4SLinus Torvalds { 2981da177e4SLinus Torvalds size_t from_length; 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds from_length = strlen(from); 3011da177e4SLinus Torvalds strncpy(to, from, min(to_length, from_length)); 3021da177e4SLinus Torvalds if (from_length < to_length) { 3031da177e4SLinus Torvalds if (compatible) { 3041da177e4SLinus Torvalds /* 3051da177e4SLinus Torvalds * NUL terminate the string if it is short. 3061da177e4SLinus Torvalds */ 3071da177e4SLinus Torvalds to[from_length] = '\0'; 3081da177e4SLinus Torvalds } else { 3091da177e4SLinus Torvalds /* 3101da177e4SLinus Torvalds * space pad the string if it is short. 3111da177e4SLinus Torvalds */ 3121da177e4SLinus Torvalds strncpy(&to[from_length], spaces, 3131da177e4SLinus Torvalds to_length - from_length); 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds if (from_length > to_length) 3171da177e4SLinus Torvalds printk(KERN_WARNING "%s: %s string '%s' is too long\n", 318cadbd4a5SHarvey Harrison __func__, name, from); 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds /** 322eb44820cSRob Landley * scsi_dev_info_list_add - add one dev_info list entry. 323eb44820cSRob Landley * @compatible: if true, null terminate short strings. Otherwise space pad. 3241da177e4SLinus Torvalds * @vendor: vendor string 3251da177e4SLinus Torvalds * @model: model (product) string 3261da177e4SLinus Torvalds * @strflags: integer string 327eb44820cSRob Landley * @flags: if strflags NULL, use this flag value 3281da177e4SLinus Torvalds * 3291da177e4SLinus Torvalds * Description: 3301da177e4SLinus Torvalds * Create and add one dev_info entry for @vendor, @model, @strflags or 3311da177e4SLinus Torvalds * @flag. If @compatible, add to the tail of the list, do not space 3321da177e4SLinus Torvalds * pad, and set devinfo->compatible. The scsi_static_device_list entries 3331da177e4SLinus Torvalds * are added with @compatible 1 and @clfags NULL. 3341da177e4SLinus Torvalds * 3351da177e4SLinus Torvalds * Returns: 0 OK, -error on failure. 3361da177e4SLinus Torvalds **/ 3371da177e4SLinus Torvalds static int scsi_dev_info_list_add(int compatible, char *vendor, char *model, 3381da177e4SLinus Torvalds char *strflags, int flags) 3391da177e4SLinus Torvalds { 340598fa4b7SJames Bottomley return scsi_dev_info_list_add_keyed(compatible, vendor, model, 341598fa4b7SJames Bottomley strflags, flags, 342598fa4b7SJames Bottomley SCSI_DEVINFO_GLOBAL); 343598fa4b7SJames Bottomley } 344598fa4b7SJames Bottomley 345598fa4b7SJames Bottomley /** 346598fa4b7SJames Bottomley * scsi_dev_info_list_add_keyed - add one dev_info list entry. 347598fa4b7SJames Bottomley * @compatible: if true, null terminate short strings. Otherwise space pad. 348598fa4b7SJames Bottomley * @vendor: vendor string 349598fa4b7SJames Bottomley * @model: model (product) string 350598fa4b7SJames Bottomley * @strflags: integer string 351598fa4b7SJames Bottomley * @flags: if strflags NULL, use this flag value 352598fa4b7SJames Bottomley * @key: specify list to use 353598fa4b7SJames Bottomley * 354598fa4b7SJames Bottomley * Description: 355598fa4b7SJames Bottomley * Create and add one dev_info entry for @vendor, @model, 356598fa4b7SJames Bottomley * @strflags or @flag in list specified by @key. If @compatible, 357598fa4b7SJames Bottomley * add to the tail of the list, do not space pad, and set 358598fa4b7SJames Bottomley * devinfo->compatible. The scsi_static_device_list entries are 359598fa4b7SJames Bottomley * added with @compatible 1 and @clfags NULL. 360598fa4b7SJames Bottomley * 361598fa4b7SJames Bottomley * Returns: 0 OK, -error on failure. 362598fa4b7SJames Bottomley **/ 363598fa4b7SJames Bottomley int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model, 364598fa4b7SJames Bottomley char *strflags, int flags, int key) 365598fa4b7SJames Bottomley { 3661da177e4SLinus Torvalds struct scsi_dev_info_list *devinfo; 367598fa4b7SJames Bottomley struct scsi_dev_info_list_table *devinfo_table = 368598fa4b7SJames Bottomley scsi_devinfo_lookup_by_key(key); 369598fa4b7SJames Bottomley 370598fa4b7SJames Bottomley if (IS_ERR(devinfo_table)) 371598fa4b7SJames Bottomley return PTR_ERR(devinfo_table); 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL); 3741da177e4SLinus Torvalds if (!devinfo) { 375cadbd4a5SHarvey Harrison printk(KERN_ERR "%s: no memory\n", __func__); 3761da177e4SLinus Torvalds return -ENOMEM; 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds scsi_strcpy_devinfo("vendor", devinfo->vendor, sizeof(devinfo->vendor), 3801da177e4SLinus Torvalds vendor, compatible); 3811da177e4SLinus Torvalds scsi_strcpy_devinfo("model", devinfo->model, sizeof(devinfo->model), 3821da177e4SLinus Torvalds model, compatible); 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds if (strflags) 3851da177e4SLinus Torvalds devinfo->flags = simple_strtoul(strflags, NULL, 0); 3861da177e4SLinus Torvalds else 3871da177e4SLinus Torvalds devinfo->flags = flags; 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds devinfo->compatible = compatible; 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds if (compatible) 392598fa4b7SJames Bottomley list_add_tail(&devinfo->dev_info_list, 393598fa4b7SJames Bottomley &devinfo_table->scsi_dev_info_list); 3941da177e4SLinus Torvalds else 395598fa4b7SJames Bottomley list_add(&devinfo->dev_info_list, 396598fa4b7SJames Bottomley &devinfo_table->scsi_dev_info_list); 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds return 0; 3991da177e4SLinus Torvalds } 400598fa4b7SJames Bottomley EXPORT_SYMBOL(scsi_dev_info_list_add_keyed); 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds /** 403c42b3654SAlan Stern * scsi_dev_info_list_find - find a matching dev_info list entry. 40438a039beSPeter Jones * @vendor: vendor string 40538a039beSPeter Jones * @model: model (product) string 40638a039beSPeter Jones * @key: specify list to use 40738a039beSPeter Jones * 40838a039beSPeter Jones * Description: 409c42b3654SAlan Stern * Finds the first dev_info entry matching @vendor, @model 41038a039beSPeter Jones * in list specified by @key. 41138a039beSPeter Jones * 412c42b3654SAlan Stern * Returns: pointer to matching entry, or ERR_PTR on failure. 41338a039beSPeter Jones **/ 414c42b3654SAlan Stern static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor, 415c42b3654SAlan Stern const char *model, int key) 41638a039beSPeter Jones { 417c42b3654SAlan Stern struct scsi_dev_info_list *devinfo; 41838a039beSPeter Jones struct scsi_dev_info_list_table *devinfo_table = 41938a039beSPeter Jones scsi_devinfo_lookup_by_key(key); 420b704f70cSAlan Stern size_t vmax, mmax; 421b704f70cSAlan Stern const char *vskip, *mskip; 42238a039beSPeter Jones 42338a039beSPeter Jones if (IS_ERR(devinfo_table)) 424c42b3654SAlan Stern return (struct scsi_dev_info_list *) devinfo_table; 42538a039beSPeter Jones 426b704f70cSAlan Stern /* Prepare for "compatible" matches */ 427b704f70cSAlan Stern 42838a039beSPeter Jones /* 42938a039beSPeter Jones * XXX why skip leading spaces? If an odd INQUIRY 43038a039beSPeter Jones * value, that should have been part of the 43138a039beSPeter Jones * scsi_static_device_list[] entry, such as " FOO" 43238a039beSPeter Jones * rather than "FOO". Since this code is already 43338a039beSPeter Jones * here, and we don't know what device it is 43438a039beSPeter Jones * trying to work with, leave it as-is. 43538a039beSPeter Jones */ 4365e7ff2caSAlan Stern vmax = sizeof(devinfo->vendor); 437b704f70cSAlan Stern vskip = vendor; 438b704f70cSAlan Stern while (vmax > 0 && *vskip == ' ') { 439b704f70cSAlan Stern vmax--; 440b704f70cSAlan Stern vskip++; 44138a039beSPeter Jones } 442b704f70cSAlan Stern /* Also skip trailing spaces */ 443b704f70cSAlan Stern while (vmax > 0 && vskip[vmax - 1] == ' ') 444b704f70cSAlan Stern --vmax; 445b704f70cSAlan Stern 4465e7ff2caSAlan Stern mmax = sizeof(devinfo->model); 447b704f70cSAlan Stern mskip = model; 448b704f70cSAlan Stern while (mmax > 0 && *mskip == ' ') { 449b704f70cSAlan Stern mmax--; 450b704f70cSAlan Stern mskip++; 451b704f70cSAlan Stern } 452b704f70cSAlan Stern while (mmax > 0 && mskip[mmax - 1] == ' ') 453b704f70cSAlan Stern --mmax; 454b704f70cSAlan Stern 455b704f70cSAlan Stern list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list, 456b704f70cSAlan Stern dev_info_list) { 457b704f70cSAlan Stern if (devinfo->compatible) { 45838a039beSPeter Jones /* 459b704f70cSAlan Stern * Behave like the older version of get_device_flags. 46038a039beSPeter Jones */ 461b704f70cSAlan Stern if (memcmp(devinfo->vendor, vskip, vmax) || 4625e7ff2caSAlan Stern (vmax < sizeof(devinfo->vendor) && 4635e7ff2caSAlan Stern devinfo->vendor[vmax])) 46438a039beSPeter Jones continue; 465b704f70cSAlan Stern if (memcmp(devinfo->model, mskip, mmax) || 4665e7ff2caSAlan Stern (mmax < sizeof(devinfo->model) && 4675e7ff2caSAlan Stern devinfo->model[mmax])) 46838a039beSPeter Jones continue; 469c42b3654SAlan Stern return devinfo; 47038a039beSPeter Jones } else { 47138a039beSPeter Jones if (!memcmp(devinfo->vendor, vendor, 47238a039beSPeter Jones sizeof(devinfo->vendor)) && 47338a039beSPeter Jones !memcmp(devinfo->model, model, 47438a039beSPeter Jones sizeof(devinfo->model))) 475c42b3654SAlan Stern return devinfo; 47638a039beSPeter Jones } 47738a039beSPeter Jones } 47838a039beSPeter Jones 479c42b3654SAlan Stern return ERR_PTR(-ENOENT); 480c42b3654SAlan Stern } 481c42b3654SAlan Stern 482c42b3654SAlan Stern /** 483c42b3654SAlan Stern * scsi_dev_info_list_del_keyed - remove one dev_info list entry. 484c42b3654SAlan Stern * @vendor: vendor string 485c42b3654SAlan Stern * @model: model (product) string 486c42b3654SAlan Stern * @key: specify list to use 487c42b3654SAlan Stern * 488c42b3654SAlan Stern * Description: 489c42b3654SAlan Stern * Remove and destroy one dev_info entry for @vendor, @model 490c42b3654SAlan Stern * in list specified by @key. 491c42b3654SAlan Stern * 492c42b3654SAlan Stern * Returns: 0 OK, -error on failure. 493c42b3654SAlan Stern **/ 494c42b3654SAlan Stern int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key) 495c42b3654SAlan Stern { 496c42b3654SAlan Stern struct scsi_dev_info_list *found; 497c42b3654SAlan Stern 498c42b3654SAlan Stern found = scsi_dev_info_list_find(vendor, model, key); 499c42b3654SAlan Stern if (IS_ERR(found)) 500c42b3654SAlan Stern return PTR_ERR(found); 501c42b3654SAlan Stern 50238a039beSPeter Jones list_del(&found->dev_info_list); 50338a039beSPeter Jones kfree(found); 50438a039beSPeter Jones return 0; 50538a039beSPeter Jones } 50638a039beSPeter Jones EXPORT_SYMBOL(scsi_dev_info_list_del_keyed); 50738a039beSPeter Jones 50838a039beSPeter Jones /** 509eb44820cSRob Landley * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list. 5101da177e4SLinus Torvalds * @dev_list: string of device flags to add 5111da177e4SLinus Torvalds * 5121da177e4SLinus Torvalds * Description: 5131da177e4SLinus Torvalds * Parse dev_list, and add entries to the scsi_dev_info_list. 5141da177e4SLinus Torvalds * dev_list is of the form "vendor:product:flag,vendor:product:flag". 5151da177e4SLinus Torvalds * dev_list is modified via strsep. Can be called for command line 5161da177e4SLinus Torvalds * addition, for proc or mabye a sysfs interface. 5171da177e4SLinus Torvalds * 5181da177e4SLinus Torvalds * Returns: 0 if OK, -error on failure. 5191da177e4SLinus Torvalds **/ 5201da177e4SLinus Torvalds static int scsi_dev_info_list_add_str(char *dev_list) 5211da177e4SLinus Torvalds { 5221da177e4SLinus Torvalds char *vendor, *model, *strflags, *next; 5231da177e4SLinus Torvalds char *next_check; 5241da177e4SLinus Torvalds int res = 0; 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds next = dev_list; 5271da177e4SLinus Torvalds if (next && next[0] == '"') { 5281da177e4SLinus Torvalds /* 5291da177e4SLinus Torvalds * Ignore both the leading and trailing quote. 5301da177e4SLinus Torvalds */ 5311da177e4SLinus Torvalds next++; 5321da177e4SLinus Torvalds next_check = ",\""; 5331da177e4SLinus Torvalds } else { 5341da177e4SLinus Torvalds next_check = ","; 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds /* 5381da177e4SLinus Torvalds * For the leading and trailing '"' case, the for loop comes 5391da177e4SLinus Torvalds * through the last time with vendor[0] == '\0'. 5401da177e4SLinus Torvalds */ 5411da177e4SLinus Torvalds for (vendor = strsep(&next, ":"); vendor && (vendor[0] != '\0') 5421da177e4SLinus Torvalds && (res == 0); vendor = strsep(&next, ":")) { 5431da177e4SLinus Torvalds strflags = NULL; 5441da177e4SLinus Torvalds model = strsep(&next, ":"); 5451da177e4SLinus Torvalds if (model) 5461da177e4SLinus Torvalds strflags = strsep(&next, next_check); 5471da177e4SLinus Torvalds if (!model || !strflags) { 5481da177e4SLinus Torvalds printk(KERN_ERR "%s: bad dev info string '%s' '%s'" 549cadbd4a5SHarvey Harrison " '%s'\n", __func__, vendor, model, 5501da177e4SLinus Torvalds strflags); 5511da177e4SLinus Torvalds res = -EINVAL; 5521da177e4SLinus Torvalds } else 5531da177e4SLinus Torvalds res = scsi_dev_info_list_add(0 /* compatible */, vendor, 5541da177e4SLinus Torvalds model, strflags, 0); 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds return res; 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds /** 560eb44820cSRob Landley * get_device_flags - get device specific flags from the dynamic device list. 561eb44820cSRob Landley * @sdev: &scsi_device to get flags for 5621da177e4SLinus Torvalds * @vendor: vendor name 5631da177e4SLinus Torvalds * @model: model name 5641da177e4SLinus Torvalds * 5651da177e4SLinus Torvalds * Description: 566598fa4b7SJames Bottomley * Search the global scsi_dev_info_list (specified by list zero) 567598fa4b7SJames Bottomley * for an entry matching @vendor and @model, if found, return the 568598fa4b7SJames Bottomley * matching flags value, else return the host or global default 569598fa4b7SJames Bottomley * settings. Called during scan time. 5701da177e4SLinus Torvalds **/ 5717f23e146SJames Bottomley int scsi_get_device_flags(struct scsi_device *sdev, 5727f23e146SJames Bottomley const unsigned char *vendor, 5737f23e146SJames Bottomley const unsigned char *model) 5741da177e4SLinus Torvalds { 575598fa4b7SJames Bottomley return scsi_get_device_flags_keyed(sdev, vendor, model, 576598fa4b7SJames Bottomley SCSI_DEVINFO_GLOBAL); 577598fa4b7SJames Bottomley } 578598fa4b7SJames Bottomley 579598fa4b7SJames Bottomley 580598fa4b7SJames Bottomley /** 5811acf3b06SRandy Dunlap * scsi_get_device_flags_keyed - get device specific flags from the dynamic device list 582598fa4b7SJames Bottomley * @sdev: &scsi_device to get flags for 583598fa4b7SJames Bottomley * @vendor: vendor name 584598fa4b7SJames Bottomley * @model: model name 585598fa4b7SJames Bottomley * @key: list to look up 586598fa4b7SJames Bottomley * 587598fa4b7SJames Bottomley * Description: 588598fa4b7SJames Bottomley * Search the scsi_dev_info_list specified by @key for an entry 589598fa4b7SJames Bottomley * matching @vendor and @model, if found, return the matching 590598fa4b7SJames Bottomley * flags value, else return the host or global default settings. 591598fa4b7SJames Bottomley * Called during scan time. 592598fa4b7SJames Bottomley **/ 593598fa4b7SJames Bottomley int scsi_get_device_flags_keyed(struct scsi_device *sdev, 594598fa4b7SJames Bottomley const unsigned char *vendor, 595598fa4b7SJames Bottomley const unsigned char *model, 596598fa4b7SJames Bottomley int key) 597598fa4b7SJames Bottomley { 5981da177e4SLinus Torvalds struct scsi_dev_info_list *devinfo; 599c42b3654SAlan Stern int err; 6001da177e4SLinus Torvalds 601c42b3654SAlan Stern devinfo = scsi_dev_info_list_find(vendor, model, key); 602c42b3654SAlan Stern if (!IS_ERR(devinfo)) 6031da177e4SLinus Torvalds return devinfo->flags; 604c42b3654SAlan Stern 605c42b3654SAlan Stern err = PTR_ERR(devinfo); 606c42b3654SAlan Stern if (err != -ENOENT) 607c42b3654SAlan Stern return err; 608c42b3654SAlan Stern 609598fa4b7SJames Bottomley /* nothing found, return nothing */ 610598fa4b7SJames Bottomley if (key != SCSI_DEVINFO_GLOBAL) 611598fa4b7SJames Bottomley return 0; 612598fa4b7SJames Bottomley 613598fa4b7SJames Bottomley /* except for the global list, where we have an exception */ 614598fa4b7SJames Bottomley if (sdev->sdev_bflags) 615598fa4b7SJames Bottomley return sdev->sdev_bflags; 616598fa4b7SJames Bottomley 617598fa4b7SJames Bottomley return scsi_default_dev_flags; 6181da177e4SLinus Torvalds } 619598fa4b7SJames Bottomley EXPORT_SYMBOL(scsi_get_device_flags_keyed); 6201da177e4SLinus Torvalds 6211da177e4SLinus Torvalds #ifdef CONFIG_SCSI_PROC_FS 622598fa4b7SJames Bottomley struct double_list { 623598fa4b7SJames Bottomley struct list_head *top; 624598fa4b7SJames Bottomley struct list_head *bottom; 625598fa4b7SJames Bottomley }; 626598fa4b7SJames Bottomley 627352ced8eSAlexey Dobriyan static int devinfo_seq_show(struct seq_file *m, void *v) 6281da177e4SLinus Torvalds { 629598fa4b7SJames Bottomley struct double_list *dl = v; 630598fa4b7SJames Bottomley struct scsi_dev_info_list_table *devinfo_table = 631598fa4b7SJames Bottomley list_entry(dl->top, struct scsi_dev_info_list_table, node); 632352ced8eSAlexey Dobriyan struct scsi_dev_info_list *devinfo = 633598fa4b7SJames Bottomley list_entry(dl->bottom, struct scsi_dev_info_list, 634598fa4b7SJames Bottomley dev_info_list); 635598fa4b7SJames Bottomley 636598fa4b7SJames Bottomley if (devinfo_table->scsi_dev_info_list.next == dl->bottom && 637598fa4b7SJames Bottomley devinfo_table->name) 638598fa4b7SJames Bottomley seq_printf(m, "[%s]:\n", devinfo_table->name); 6391da177e4SLinus Torvalds 640352ced8eSAlexey Dobriyan seq_printf(m, "'%.8s' '%.16s' 0x%x\n", 6411da177e4SLinus Torvalds devinfo->vendor, devinfo->model, devinfo->flags); 642352ced8eSAlexey Dobriyan return 0; 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds 645598fa4b7SJames Bottomley static void *devinfo_seq_start(struct seq_file *m, loff_t *ppos) 646352ced8eSAlexey Dobriyan { 647598fa4b7SJames Bottomley struct double_list *dl = kmalloc(sizeof(*dl), GFP_KERNEL); 648598fa4b7SJames Bottomley loff_t pos = *ppos; 649598fa4b7SJames Bottomley 650598fa4b7SJames Bottomley if (!dl) 651598fa4b7SJames Bottomley return NULL; 652598fa4b7SJames Bottomley 653598fa4b7SJames Bottomley list_for_each(dl->top, &scsi_dev_info_list) { 654598fa4b7SJames Bottomley struct scsi_dev_info_list_table *devinfo_table = 655598fa4b7SJames Bottomley list_entry(dl->top, struct scsi_dev_info_list_table, 656598fa4b7SJames Bottomley node); 657598fa4b7SJames Bottomley list_for_each(dl->bottom, &devinfo_table->scsi_dev_info_list) 658598fa4b7SJames Bottomley if (pos-- == 0) 659598fa4b7SJames Bottomley return dl; 660352ced8eSAlexey Dobriyan } 661352ced8eSAlexey Dobriyan 662598fa4b7SJames Bottomley kfree(dl); 663598fa4b7SJames Bottomley return NULL; 664598fa4b7SJames Bottomley } 665598fa4b7SJames Bottomley 666598fa4b7SJames Bottomley static void *devinfo_seq_next(struct seq_file *m, void *v, loff_t *ppos) 667352ced8eSAlexey Dobriyan { 668598fa4b7SJames Bottomley struct double_list *dl = v; 669598fa4b7SJames Bottomley struct scsi_dev_info_list_table *devinfo_table = 670598fa4b7SJames Bottomley list_entry(dl->top, struct scsi_dev_info_list_table, node); 671598fa4b7SJames Bottomley 672598fa4b7SJames Bottomley ++*ppos; 673598fa4b7SJames Bottomley dl->bottom = dl->bottom->next; 674598fa4b7SJames Bottomley while (&devinfo_table->scsi_dev_info_list == dl->bottom) { 675598fa4b7SJames Bottomley dl->top = dl->top->next; 676598fa4b7SJames Bottomley if (dl->top == &scsi_dev_info_list) { 677598fa4b7SJames Bottomley kfree(dl); 678598fa4b7SJames Bottomley return NULL; 679598fa4b7SJames Bottomley } 680598fa4b7SJames Bottomley devinfo_table = list_entry(dl->top, 681598fa4b7SJames Bottomley struct scsi_dev_info_list_table, 682598fa4b7SJames Bottomley node); 683598fa4b7SJames Bottomley dl->bottom = devinfo_table->scsi_dev_info_list.next; 684598fa4b7SJames Bottomley } 685598fa4b7SJames Bottomley 686598fa4b7SJames Bottomley return dl; 687352ced8eSAlexey Dobriyan } 688352ced8eSAlexey Dobriyan 689352ced8eSAlexey Dobriyan static void devinfo_seq_stop(struct seq_file *m, void *v) 690352ced8eSAlexey Dobriyan { 691598fa4b7SJames Bottomley kfree(v); 692352ced8eSAlexey Dobriyan } 693352ced8eSAlexey Dobriyan 694352ced8eSAlexey Dobriyan static const struct seq_operations scsi_devinfo_seq_ops = { 695352ced8eSAlexey Dobriyan .start = devinfo_seq_start, 696352ced8eSAlexey Dobriyan .next = devinfo_seq_next, 697352ced8eSAlexey Dobriyan .stop = devinfo_seq_stop, 698352ced8eSAlexey Dobriyan .show = devinfo_seq_show, 699352ced8eSAlexey Dobriyan }; 700352ced8eSAlexey Dobriyan 701352ced8eSAlexey Dobriyan static int proc_scsi_devinfo_open(struct inode *inode, struct file *file) 702352ced8eSAlexey Dobriyan { 703352ced8eSAlexey Dobriyan return seq_open(file, &scsi_devinfo_seq_ops); 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds /* 707eb44820cSRob Landley * proc_scsi_dev_info_write - allow additions to scsi_dev_info_list via /proc. 7081da177e4SLinus Torvalds * 709eb44820cSRob Landley * Description: Adds a black/white list entry for vendor and model with an 710eb44820cSRob Landley * integer value of flag to the scsi device info list. 711eb44820cSRob Landley * To use, echo "vendor:model:flag" > /proc/scsi/device_info 7121da177e4SLinus Torvalds */ 713352ced8eSAlexey Dobriyan static ssize_t proc_scsi_devinfo_write(struct file *file, 714352ced8eSAlexey Dobriyan const char __user *buf, 715352ced8eSAlexey Dobriyan size_t length, loff_t *ppos) 7161da177e4SLinus Torvalds { 7171da177e4SLinus Torvalds char *buffer; 718352ced8eSAlexey Dobriyan ssize_t err = length; 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds if (!buf || length>PAGE_SIZE) 7211da177e4SLinus Torvalds return -EINVAL; 7221da177e4SLinus Torvalds if (!(buffer = (char *) __get_free_page(GFP_KERNEL))) 7231da177e4SLinus Torvalds return -ENOMEM; 7241da177e4SLinus Torvalds if (copy_from_user(buffer, buf, length)) { 7251da177e4SLinus Torvalds err =-EFAULT; 7261da177e4SLinus Torvalds goto out; 7271da177e4SLinus Torvalds } 7281da177e4SLinus Torvalds 7291da177e4SLinus Torvalds if (length < PAGE_SIZE) 7301da177e4SLinus Torvalds buffer[length] = '\0'; 7311da177e4SLinus Torvalds else if (buffer[PAGE_SIZE-1]) { 7321da177e4SLinus Torvalds err = -EINVAL; 7331da177e4SLinus Torvalds goto out; 7341da177e4SLinus Torvalds } 7351da177e4SLinus Torvalds 7361da177e4SLinus Torvalds scsi_dev_info_list_add_str(buffer); 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds out: 7391da177e4SLinus Torvalds free_page((unsigned long)buffer); 7401da177e4SLinus Torvalds return err; 7411da177e4SLinus Torvalds } 742352ced8eSAlexey Dobriyan 743352ced8eSAlexey Dobriyan static const struct file_operations scsi_devinfo_proc_fops = { 744352ced8eSAlexey Dobriyan .owner = THIS_MODULE, 745352ced8eSAlexey Dobriyan .open = proc_scsi_devinfo_open, 746352ced8eSAlexey Dobriyan .read = seq_read, 747352ced8eSAlexey Dobriyan .write = proc_scsi_devinfo_write, 748352ced8eSAlexey Dobriyan .llseek = seq_lseek, 749352ced8eSAlexey Dobriyan .release = seq_release, 750352ced8eSAlexey Dobriyan }; 7511da177e4SLinus Torvalds #endif /* CONFIG_SCSI_PROC_FS */ 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0); 7541da177e4SLinus Torvalds MODULE_PARM_DESC(dev_flags, 7551da177e4SLinus Torvalds "Given scsi_dev_flags=vendor:model:flags[,v:m:f] add black/white" 7561da177e4SLinus Torvalds " list entries for vendor and model with an integer value of flags" 7571da177e4SLinus Torvalds " to the scsi device info list"); 7581da177e4SLinus Torvalds 7591da177e4SLinus Torvalds module_param_named(default_dev_flags, scsi_default_dev_flags, int, S_IRUGO|S_IWUSR); 7601da177e4SLinus Torvalds MODULE_PARM_DESC(default_dev_flags, 7611da177e4SLinus Torvalds "scsi default device flag integer value"); 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds /** 7641acf3b06SRandy Dunlap * scsi_exit_devinfo - remove /proc/scsi/device_info & the scsi_dev_info_list 7651da177e4SLinus Torvalds **/ 7661da177e4SLinus Torvalds void scsi_exit_devinfo(void) 7671da177e4SLinus Torvalds { 7681da177e4SLinus Torvalds #ifdef CONFIG_SCSI_PROC_FS 7691da177e4SLinus Torvalds remove_proc_entry("scsi/device_info", NULL); 7701da177e4SLinus Torvalds #endif 7711da177e4SLinus Torvalds 772598fa4b7SJames Bottomley scsi_dev_info_remove_list(SCSI_DEVINFO_GLOBAL); 773598fa4b7SJames Bottomley } 774598fa4b7SJames Bottomley 775598fa4b7SJames Bottomley /** 776598fa4b7SJames Bottomley * scsi_dev_info_add_list - add a new devinfo list 777598fa4b7SJames Bottomley * @key: key of the list to add 778598fa4b7SJames Bottomley * @name: Name of the list to add (for /proc/scsi/device_info) 779598fa4b7SJames Bottomley * 780598fa4b7SJames Bottomley * Adds the requested list, returns zero on success, -EEXIST if the 781598fa4b7SJames Bottomley * key is already registered to a list, or other error on failure. 782598fa4b7SJames Bottomley */ 783598fa4b7SJames Bottomley int scsi_dev_info_add_list(int key, const char *name) 784598fa4b7SJames Bottomley { 785598fa4b7SJames Bottomley struct scsi_dev_info_list_table *devinfo_table = 786598fa4b7SJames Bottomley scsi_devinfo_lookup_by_key(key); 787598fa4b7SJames Bottomley 788598fa4b7SJames Bottomley if (!IS_ERR(devinfo_table)) 789598fa4b7SJames Bottomley /* list already exists */ 790598fa4b7SJames Bottomley return -EEXIST; 791598fa4b7SJames Bottomley 792598fa4b7SJames Bottomley devinfo_table = kmalloc(sizeof(*devinfo_table), GFP_KERNEL); 793598fa4b7SJames Bottomley 794598fa4b7SJames Bottomley if (!devinfo_table) 795598fa4b7SJames Bottomley return -ENOMEM; 796598fa4b7SJames Bottomley 797598fa4b7SJames Bottomley INIT_LIST_HEAD(&devinfo_table->node); 798598fa4b7SJames Bottomley INIT_LIST_HEAD(&devinfo_table->scsi_dev_info_list); 799598fa4b7SJames Bottomley devinfo_table->name = name; 800598fa4b7SJames Bottomley devinfo_table->key = key; 801598fa4b7SJames Bottomley list_add_tail(&devinfo_table->node, &scsi_dev_info_list); 802598fa4b7SJames Bottomley 803598fa4b7SJames Bottomley return 0; 804598fa4b7SJames Bottomley } 805598fa4b7SJames Bottomley EXPORT_SYMBOL(scsi_dev_info_add_list); 806598fa4b7SJames Bottomley 807598fa4b7SJames Bottomley /** 808598fa4b7SJames Bottomley * scsi_dev_info_remove_list - destroy an added devinfo list 809598fa4b7SJames Bottomley * @key: key of the list to destroy 810598fa4b7SJames Bottomley * 811598fa4b7SJames Bottomley * Iterates over the entire list first, freeing all the values, then 812598fa4b7SJames Bottomley * frees the list itself. Returns 0 on success or -EINVAL if the key 813598fa4b7SJames Bottomley * can't be found. 814598fa4b7SJames Bottomley */ 815598fa4b7SJames Bottomley int scsi_dev_info_remove_list(int key) 816598fa4b7SJames Bottomley { 817598fa4b7SJames Bottomley struct list_head *lh, *lh_next; 818598fa4b7SJames Bottomley struct scsi_dev_info_list_table *devinfo_table = 819598fa4b7SJames Bottomley scsi_devinfo_lookup_by_key(key); 820598fa4b7SJames Bottomley 821598fa4b7SJames Bottomley if (IS_ERR(devinfo_table)) 822598fa4b7SJames Bottomley /* no such list */ 823598fa4b7SJames Bottomley return -EINVAL; 824598fa4b7SJames Bottomley 825598fa4b7SJames Bottomley /* remove from the master list */ 826598fa4b7SJames Bottomley list_del(&devinfo_table->node); 827598fa4b7SJames Bottomley 828598fa4b7SJames Bottomley list_for_each_safe(lh, lh_next, &devinfo_table->scsi_dev_info_list) { 829598fa4b7SJames Bottomley struct scsi_dev_info_list *devinfo; 830598fa4b7SJames Bottomley 8311da177e4SLinus Torvalds devinfo = list_entry(lh, struct scsi_dev_info_list, 8321da177e4SLinus Torvalds dev_info_list); 8331da177e4SLinus Torvalds kfree(devinfo); 8341da177e4SLinus Torvalds } 835598fa4b7SJames Bottomley kfree(devinfo_table); 836598fa4b7SJames Bottomley 837598fa4b7SJames Bottomley return 0; 8381da177e4SLinus Torvalds } 839598fa4b7SJames Bottomley EXPORT_SYMBOL(scsi_dev_info_remove_list); 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds /** 842c93ff979SRandy Dunlap * scsi_init_devinfo - set up the dynamic device list. 8431da177e4SLinus Torvalds * 8441da177e4SLinus Torvalds * Description: 845eb44820cSRob Landley * Add command line entries from scsi_dev_flags, then add 8461da177e4SLinus Torvalds * scsi_static_device_list entries to the scsi device info list. 847eb44820cSRob Landley */ 8481da177e4SLinus Torvalds int __init scsi_init_devinfo(void) 8491da177e4SLinus Torvalds { 8501da177e4SLinus Torvalds #ifdef CONFIG_SCSI_PROC_FS 8511da177e4SLinus Torvalds struct proc_dir_entry *p; 8521da177e4SLinus Torvalds #endif 8531da177e4SLinus Torvalds int error, i; 8541da177e4SLinus Torvalds 855598fa4b7SJames Bottomley error = scsi_dev_info_add_list(SCSI_DEVINFO_GLOBAL, NULL); 8561da177e4SLinus Torvalds if (error) 8571da177e4SLinus Torvalds return error; 8581da177e4SLinus Torvalds 859598fa4b7SJames Bottomley error = scsi_dev_info_list_add_str(scsi_dev_flags); 860598fa4b7SJames Bottomley if (error) 861598fa4b7SJames Bottomley goto out; 862598fa4b7SJames Bottomley 8631da177e4SLinus Torvalds for (i = 0; scsi_static_device_list[i].vendor; i++) { 8641da177e4SLinus Torvalds error = scsi_dev_info_list_add(1 /* compatibile */, 8651da177e4SLinus Torvalds scsi_static_device_list[i].vendor, 8661da177e4SLinus Torvalds scsi_static_device_list[i].model, 8671da177e4SLinus Torvalds NULL, 8681da177e4SLinus Torvalds scsi_static_device_list[i].flags); 8691da177e4SLinus Torvalds if (error) 8701da177e4SLinus Torvalds goto out; 8711da177e4SLinus Torvalds } 8721da177e4SLinus Torvalds 8731da177e4SLinus Torvalds #ifdef CONFIG_SCSI_PROC_FS 874352ced8eSAlexey Dobriyan p = proc_create("scsi/device_info", 0, NULL, &scsi_devinfo_proc_fops); 8751da177e4SLinus Torvalds if (!p) { 8761da177e4SLinus Torvalds error = -ENOMEM; 8771da177e4SLinus Torvalds goto out; 8781da177e4SLinus Torvalds } 8791da177e4SLinus Torvalds #endif /* CONFIG_SCSI_PROC_FS */ 8801da177e4SLinus Torvalds 8811da177e4SLinus Torvalds out: 8821da177e4SLinus Torvalds if (error) 8831da177e4SLinus Torvalds scsi_exit_devinfo(); 8841da177e4SLinus Torvalds return error; 8851da177e4SLinus Torvalds } 886