Line data Source code
1 :
2 : #include <linux/blkdev.h>
3 : #include <linux/init.h>
4 : #include <linux/kernel.h>
5 : #include <linux/module.h>
6 : #include <linux/moduleparam.h>
7 : #include <linux/proc_fs.h>
8 : #include <linux/seq_file.h>
9 :
10 : #include <scsi/scsi_device.h>
11 : #include <scsi/scsi_devinfo.h>
12 :
13 : #include "scsi_priv.h"
14 :
15 :
16 : /*
17 : * scsi_dev_info_list: structure to hold black/white listed devices.
18 : */
19 : struct scsi_dev_info_list {
20 : struct list_head dev_info_list;
21 : char vendor[8];
22 : char model[16];
23 : unsigned flags;
24 : unsigned compatible; /* for use with scsi_static_device_list entries */
25 : };
26 1 :
27 : struct scsi_dev_info_list_table {
28 : struct list_head node; /* our node for being on the master list */
29 : struct list_head scsi_dev_info_list; /* head of dev info list */
30 : const char *name; /* name of list for /proc (NULL for global) */
31 : int key; /* unique numeric identifier */
32 : };
33 :
34 :
35 1 : static const char spaces[] = " "; /* 16 of them */
36 1 : static unsigned scsi_default_dev_flags;
37 1 : static LIST_HEAD(scsi_dev_info_list);
38 1 : static char scsi_dev_flags[256];
39 :
40 : /*
41 : * scsi_static_device_list: deprecated list of devices that require
42 : * settings that differ from the default, includes black-listed (broken)
43 : * devices. The entries here are added to the tail of scsi_dev_info_list
44 : * via scsi_dev_info_list_init.
45 : *
46 : * Do not add to this list, use the command line or proc interface to add
47 : * to the scsi_dev_info_list. This table will eventually go away.
48 : */
49 : static struct {
50 : char *vendor;
51 : char *model;
52 : char *revision; /* revision known to be bad, unused */
53 : unsigned flags;
54 2 : } scsi_static_device_list[] __initdata = {
55 : /*
56 : * The following devices are known not to tolerate a lun != 0 scan
57 : * for one reason or another. Some will respond to all luns,
58 : * others will lock up.
59 : */
60 : {"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN}, /* locks up */
61 : {"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN}, /* locks up */
62 : {"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN}, /* locks up */
63 : {"DENON", "DRD-25X", "V", BLIST_NOLUN}, /* locks up */
64 : {"HITACHI", "DK312C", "CM81", BLIST_NOLUN}, /* responds to all lun */
65 : {"HITACHI", "DK314C", "CR21", BLIST_NOLUN}, /* responds to all lun */
66 : {"IBM", "2104-DU3", NULL, BLIST_NOLUN}, /* locks up */
67 : {"IBM", "2104-TU3", NULL, BLIST_NOLUN}, /* locks up */
68 : {"IMS", "CDD521/10", "2.06", BLIST_NOLUN}, /* locks up */
69 : {"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN}, /* locks up */
70 : {"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN}, /* locks up */
71 : {"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN}, /* locks up */
72 : {"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN}, /* locks up */
73 : {"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN}, /* locks up */
74 : {"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN}, /* responds to all lun */
75 : {"MICROTEK", "ScanMakerIII", "2.30", BLIST_NOLUN}, /* responds to all lun */
76 : {"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},/* locks up */
77 : {"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN}, /* responds to all lun */
78 : {"RODIME", "RO3000S", "2.33", BLIST_NOLUN}, /* locks up */
79 : {"SUN", "SENA", NULL, BLIST_NOLUN}, /* responds to all luns */
80 : /*
81 : * The following causes a failed REQUEST SENSE on lun 1 for
82 : * aha152x controller, which causes SCSI code to reset bus.
83 : */
84 : {"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},
85 : /*
86 : * The following causes a failed REQUEST SENSE on lun 1 for
87 : * aha152x controller, which causes SCSI code to reset bus.
88 : */
89 : {"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},
90 : {"SEAGATE", "ST296", "921", BLIST_NOLUN}, /* responds to all lun */
91 : {"SEAGATE", "ST1581", "6538", BLIST_NOLUN}, /* responds to all lun */
92 : {"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN},
93 : {"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN},
94 : {"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN},
95 : {"SONY", "CD-ROM CDU-8012", NULL, BLIST_NOLUN},
96 : {"SONY", "SDT-5000", "3.17", BLIST_SELECT_NO_ATN},
97 : {"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN}, /* locks up */
98 : {"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN}, /* locks up */
99 : /*
100 : * The following causes a failed REQUEST SENSE on lun 1 for
101 : * seagate controller, which causes SCSI code to reset bus.
102 : */
103 : {"TEAC", "CD-ROM", "1.06", BLIST_NOLUN},
104 : {"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN}, /* responds to all lun */
105 : /*
106 : * The following causes a failed REQUEST SENSE on lun 1 for
107 : * seagate controller, which causes SCSI code to reset bus.
108 : */
109 : {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */
110 : {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */
111 : {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */
112 : {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN}, /* locks up */
113 : {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all lun */
114 : {"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN}, /* locks up */
115 : {"NEC", "D3856", "0009", BLIST_NOLUN},
116 : {"QUANTUM", "LPS525S", "3110", BLIST_NOLUN}, /* locks up */
117 : {"QUANTUM", "PD1225S", "3110", BLIST_NOLUN}, /* locks up */
118 : {"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN}, /* locks up */
119 : {"RELISYS", "Scorpio", NULL, BLIST_NOLUN}, /* responds to all lun */
120 : {"SANKYO", "CP525", "6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */
121 : {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},
122 : {"transtec", "T5008", "0001", BLIST_NOREPORTLUN },
123 : {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* locks up */
124 : {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* locks up */
125 : {"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN}, /* locks up */
126 : {"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN}, /* locks up */
127 : {"", "Scanner", "1.80", BLIST_NOLUN}, /* responds to all lun */
128 :
129 : /*
130 : * Other types of devices that have special flags.
131 : * Note that all USB devices should have the BLIST_INQUIRY_36 flag.
132 : */
133 : {"3PARdata", "VV", NULL, BLIST_REPORTLUN2},
134 : {"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN},
135 : {"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN},
136 : {"AFT PRO", "-IX CF", "0.0>", BLIST_FORCELUN},
137 : {"BELKIN", "USB 2 HS-CF", "1.95", BLIST_FORCELUN | BLIST_INQUIRY_36},
138 : {"BROWNIE", "1200U3P", NULL, BLIST_NOREPORTLUN},
139 : {"BROWNIE", "1600U3P", NULL, BLIST_NOREPORTLUN},
140 : {"CANON", "IPUBJD", NULL, BLIST_SPARSELUN},
141 : {"CBOX3", "USB Storage-SMC", "300A", BLIST_FORCELUN | BLIST_INQUIRY_36},
142 : {"CMD", "CRA-7280", NULL, BLIST_SPARSELUN}, /* CMD RAID Controller */
143 : {"CNSI", "G7324", NULL, BLIST_SPARSELUN}, /* Chaparral G7324 RAID */
144 : {"CNSi", "G8324", NULL, BLIST_SPARSELUN}, /* Chaparral G8324 RAID */
145 : {"COMPAQ", "ARRAY CONTROLLER", NULL, BLIST_SPARSELUN | BLIST_LARGELUN |
146 : BLIST_MAX_512 | BLIST_REPORTLUN2}, /* Compaq RA4x00 */
147 : {"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN | BLIST_MAX_512}, /* Compaq RA4x00 */
148 : {"COMPAQ", "CR3500", NULL, BLIST_FORCELUN},
149 : {"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
150 : {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
151 : {"COMPAQ", "HSV110", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD},
152 : {"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN},
153 : {"DEC", "HSG80", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD},
154 : {"DELL", "PV660F", NULL, BLIST_SPARSELUN},
155 : {"DELL", "PV660F PSEUDO", NULL, BLIST_SPARSELUN},
156 : {"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN}, /* Dell PV 530F */
157 : {"DELL", "PV530F", NULL, BLIST_SPARSELUN},
158 : {"DELL", "PERCRAID", NULL, BLIST_FORCELUN},
159 : {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */
160 : {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */
161 : {"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
162 : {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
163 : {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN},
164 : {"easyRAID", "16P", NULL, BLIST_NOREPORTLUN},
165 : {"easyRAID", "X6P", NULL, BLIST_NOREPORTLUN},
166 : {"easyRAID", "F8", NULL, BLIST_NOREPORTLUN},
167 : {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
168 : {"Generic", "USB SD Reader", "1.00", BLIST_FORCELUN | BLIST_INQUIRY_36},
169 : {"Generic", "USB Storage-SMC", "0180", BLIST_FORCELUN | BLIST_INQUIRY_36},
170 : {"Generic", "USB Storage-SMC", "0207", BLIST_FORCELUN | BLIST_INQUIRY_36},
171 : {"HITACHI", "DF400", "*", BLIST_REPORTLUN2},
172 : {"HITACHI", "DF500", "*", BLIST_REPORTLUN2},
173 : {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_REPORTLUN2},
174 : {"HITACHI", "OPEN-", "*", BLIST_REPORTLUN2},
175 : {"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
176 : {"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
177 : {"HITACHI", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
178 : {"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
179 : {"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
180 : {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */
181 : {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */
182 : {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
183 : {"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD},
184 : {"HP", "C1557A", NULL, BLIST_FORCELUN},
185 : {"HP", "C3323-300", "4269", BLIST_NOTQ},
186 : {"HP", "C5713A", NULL, BLIST_NOREPORTLUN},
187 : {"HP", "DF400", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
188 : {"HP", "DF500", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
189 : {"HP", "DF600", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
190 : {"HP", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
191 : {"HP", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
192 : {"HP", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
193 : {"HP", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
194 : {"HP", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
195 : {"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
196 : {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
197 : {"IBM", "2105", NULL, BLIST_RETRY_HWERROR},
198 : {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
199 : {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN},
200 : {"IOMEGA", "Io20S *F", NULL, BLIST_KEY},
201 : {"INSITE", "Floptical F*8I", NULL, BLIST_KEY},
202 : {"INSITE", "I325VM", NULL, BLIST_KEY},
203 : {"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
204 : {"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
205 : {"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
206 : {"MATSHITA", "DMC-LC5", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
207 : {"MATSHITA", "DMC-LC40", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
208 : {"Medion", "Flash XL MMC/SD", "2.6D", BLIST_FORCELUN},
209 : {"MegaRAID", "LD", NULL, BLIST_FORCELUN},
210 : {"MICROP", "4110", NULL, BLIST_NOTQ},
211 : {"MYLEX", "DACARMRB", "*", BLIST_REPORTLUN2},
212 : {"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN},
213 : {"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
214 : {"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
215 : {"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
216 : {"NEC", "iStorage", NULL, BLIST_REPORTLUN2},
217 : {"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
218 : {"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
219 : {"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
220 : {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
221 : {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
222 : {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
223 : {"Promise", "", NULL, BLIST_SPARSELUN},
224 : {"QUANTUM", "XP34301", "1071", BLIST_NOTQ},
225 : {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
226 : {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN},
227 : {"SEAGATE", "ST34555N", "0930", BLIST_NOTQ}, /* Chokes on tagged INQUIRY */
228 : {"SEAGATE", "ST3390N", "9546", BLIST_NOTQ},
229 : {"SGI", "RAID3", "*", BLIST_SPARSELUN},
230 : {"SGI", "RAID5", "*", BLIST_SPARSELUN},
231 : {"SGI", "TP9100", "*", BLIST_REPORTLUN2},
232 : {"SGI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
233 : {"IBM", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
234 : {"SUN", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
235 : {"DELL", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
236 : {"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36},
237 : {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
238 : {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */
239 : {"ST650211", "CF", NULL, BLIST_RETRY_HWERROR},
240 : {"SUN", "T300", "*", BLIST_SPARSELUN},
241 : {"SUN", "T4", "*", BLIST_SPARSELUN},
242 : {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
243 : {"Tornado-", "F4", "*", BLIST_NOREPORTLUN},
244 : {"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
245 : {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
246 : {"Traxdata", "CDR4120", NULL, BLIST_NOLUN}, /* locks up */
247 : {"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36},
248 : {"WangDAT", "Model 2600", "01.7", BLIST_SELECT_NO_ATN},
249 : {"WangDAT", "Model 3200", "02.2", BLIST_SELECT_NO_ATN},
250 : {"WangDAT", "Model 1300", "02.4", BLIST_SELECT_NO_ATN},
251 : {"WDC WD25", "00JB-00FUA0", NULL, BLIST_NOREPORTLUN},
252 : {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
253 : {"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN},
254 : {"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN},
255 : { NULL, NULL, NULL, 0 },
256 : };
257 :
258 : static struct scsi_dev_info_list_table *scsi_devinfo_lookup_by_key(int key)
259 : {
260 139 : struct scsi_dev_info_list_table *devinfo_table;
261 278 : int found = 0;
262 139 :
263 1251 : list_for_each_entry(devinfo_table, &scsi_dev_info_list, node)
264 695 : if (devinfo_table->key == key) {
265 278 : found = 1;
266 139 : break;
267 : }
268 278 : if (!found)
269 556 : return ERR_PTR(-EINVAL);
270 :
271 139 : return devinfo_table;
272 : }
273 :
274 : /*
275 : * scsi_strcpy_devinfo: called from scsi_dev_info_list_add to copy into
276 : * devinfo vendor and model strings.
277 : */
278 : static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length,
279 : char *from, int compatible)
280 : {
281 6 : size_t from_length;
282 6 :
283 12 : from_length = strlen(from);
284 48 : strncpy(to, from, min(to_length, from_length));
285 12 : if (from_length < to_length) {
286 12 : if (compatible) {
287 : /*
288 : * NUL terminate the string if it is short.
289 : */
290 6 : to[from_length] = '\0';
291 : } else {
292 : /*
293 : * space pad the string if it is short.
294 : */
295 6 : strncpy(&to[from_length], spaces,
296 : to_length - from_length);
297 : }
298 : }
299 12 : if (from_length > to_length)
300 6 : printk(KERN_WARNING "%s: %s string '%s' is too long\n",
301 : __func__, name, from);
302 6 : }
303 :
304 : /**
305 : * scsi_dev_info_list_add - add one dev_info list entry.
306 : * @compatible: if true, null terminate short strings. Otherwise space pad.
307 : * @vendor: vendor string
308 : * @model: model (product) string
309 : * @strflags: integer string
310 : * @flags: if strflags NULL, use this flag value
311 : *
312 : * Description:
313 : * Create and add one dev_info entry for @vendor, @model, @strflags or
314 : * @flag. If @compatible, add to the tail of the list, do not space
315 : * pad, and set devinfo->compatible. The scsi_static_device_list entries
316 : * are added with @compatible 1 and @clfags NULL.
317 : *
318 : * Returns: 0 OK, -error on failure.
319 : **/
320 : static int scsi_dev_info_list_add(int compatible, char *vendor, char *model,
321 : char *strflags, int flags)
322 : {
323 21 : return scsi_dev_info_list_add_keyed(compatible, vendor, model,
324 : strflags, flags,
325 : SCSI_DEVINFO_GLOBAL);
326 : }
327 :
328 : /**
329 : * scsi_dev_info_list_add_keyed - add one dev_info list entry.
330 : * @compatible: if true, null terminate short strings. Otherwise space pad.
331 : * @vendor: vendor string
332 : * @model: model (product) string
333 : * @strflags: integer string
334 : * @flags: if strflags NULL, use this flag value
335 : * @key: specify list to use
336 : *
337 : * Description:
338 : * Create and add one dev_info entry for @vendor, @model,
339 : * @strflags or @flag in list specified by @key. If @compatible,
340 : * add to the tail of the list, do not space pad, and set
341 : * devinfo->compatible. The scsi_static_device_list entries are
342 : * added with @compatible 1 and @clfags NULL.
343 : *
344 : * Returns: 0 OK, -error on failure.
345 : **/
346 : int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model,
347 : char *strflags, int flags, int key)
348 : {
349 3 : struct scsi_dev_info_list *devinfo;
350 15 : struct scsi_dev_info_list_table *devinfo_table =
351 3 : scsi_devinfo_lookup_by_key(key);
352 3 :
353 15 : if (IS_ERR(devinfo_table))
354 12 : return PTR_ERR(devinfo_table);
355 3 :
356 9 : devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL);
357 6 : if (!devinfo) {
358 3 : printk(KERN_ERR "%s: no memory\n", __func__);
359 3 : return -ENOMEM;
360 : }
361 :
362 6 : scsi_strcpy_devinfo("vendor", devinfo->vendor, sizeof(devinfo->vendor),
363 : vendor, compatible);
364 6 : scsi_strcpy_devinfo("model", devinfo->model, sizeof(devinfo->model),
365 : model, compatible);
366 :
367 6 : if (strflags)
368 6 : devinfo->flags = simple_strtoul(strflags, NULL, 0);
369 : else
370 3 : devinfo->flags = flags;
371 :
372 3 : devinfo->compatible = compatible;
373 :
374 6 : if (compatible)
375 6 : list_add_tail(&devinfo->dev_info_list,
376 : &devinfo_table->scsi_dev_info_list);
377 : else
378 6 : list_add(&devinfo->dev_info_list,
379 : &devinfo_table->scsi_dev_info_list);
380 :
381 6 : return 0;
382 : }
383 : EXPORT_SYMBOL(scsi_dev_info_list_add_keyed);
384 :
385 : /**
386 : * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list.
387 : * @dev_list: string of device flags to add
388 : *
389 : * Description:
390 : * Parse dev_list, and add entries to the scsi_dev_info_list.
391 : * dev_list is of the form "vendor:product:flag,vendor:product:flag".
392 : * dev_list is modified via strsep. Can be called for command line
393 : * addition, for proc or mabye a sysfs interface.
394 : *
395 : * Returns: 0 if OK, -error on failure.
396 : **/
397 : static int scsi_dev_info_list_add_str(char *dev_list)
398 : {
399 2 : char *vendor, *model, *strflags, *next;
400 2 : char *next_check;
401 4 : int res = 0;
402 2 :
403 4 : next = dev_list;
404 10 : if (next && next[0] == '"') {
405 : /*
406 : * Ignore both the leading and trailing quote.
407 : */
408 2 : next++;
409 2 : next_check = ",\"";
410 : } else {
411 2 : next_check = ",";
412 : }
413 :
414 : /*
415 : * For the leading and trailing '"' case, the for loop comes
416 : * through the last time with vendor[0] == '\0'.
417 : */
418 16 : for (vendor = strsep(&next, ":"); vendor && (vendor[0] != '\0')
419 6 : && (res == 0); vendor = strsep(&next, ":")) {
420 2 : strflags = NULL;
421 8 : model = strsep(&next, ":");
422 4 : if (model)
423 2 : strflags = strsep(&next, next_check);
424 8 : if (!model || !strflags) {
425 2 : printk(KERN_ERR "%s: bad dev info string '%s' '%s'"
426 : " '%s'\n", __func__, vendor, model,
427 : strflags);
428 2 : res = -EINVAL;
429 : } else
430 4 : res = scsi_dev_info_list_add(0 /* compatible */, vendor,
431 : model, strflags, 0);
432 : }
433 2 : return res;
434 : }
435 :
436 : /**
437 : * get_device_flags - get device specific flags from the dynamic device list.
438 : * @sdev: &scsi_device to get flags for
439 : * @vendor: vendor name
440 : * @model: model name
441 : *
442 : * Description:
443 : * Search the global scsi_dev_info_list (specified by list zero)
444 : * for an entry matching @vendor and @model, if found, return the
445 : * matching flags value, else return the host or global default
446 : * settings. Called during scan time.
447 : **/
448 : int scsi_get_device_flags(struct scsi_device *sdev,
449 : const unsigned char *vendor,
450 : const unsigned char *model)
451 128 : {
452 640 : return scsi_get_device_flags_keyed(sdev, vendor, model,
453 : SCSI_DEVINFO_GLOBAL);
454 : }
455 :
456 :
457 : /**
458 : * scsi_get_device_flags_keyed - get device specific flags from the dynamic device list
459 : * @sdev: &scsi_device to get flags for
460 : * @vendor: vendor name
461 : * @model: model name
462 : * @key: list to look up
463 : *
464 : * Description:
465 : * Search the scsi_dev_info_list specified by @key for an entry
466 : * matching @vendor and @model, if found, return the matching
467 : * flags value, else return the host or global default settings.
468 : * Called during scan time.
469 : **/
470 : int scsi_get_device_flags_keyed(struct scsi_device *sdev,
471 : const unsigned char *vendor,
472 : const unsigned char *model,
473 128 : int key)
474 128 : {
475 128 : struct scsi_dev_info_list *devinfo;
476 128 : struct scsi_dev_info_list_table *devinfo_table;
477 128 :
478 512 : devinfo_table = scsi_devinfo_lookup_by_key(key);
479 128 :
480 640 : if (IS_ERR(devinfo_table))
481 512 : return PTR_ERR(devinfo_table);
482 128 :
483 1664 : list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list,
484 640 : dev_info_list) {
485 512 : if (devinfo->compatible) {
486 128 : /*
487 128 : * Behave like the older version of get_device_flags.
488 128 : */
489 128 : size_t max;
490 : /*
491 : * XXX why skip leading spaces? If an odd INQUIRY
492 : * value, that should have been part of the
493 : * scsi_static_device_list[] entry, such as " FOO"
494 : * rather than "FOO". Since this code is already
495 : * here, and we don't know what device it is
496 : * trying to work with, leave it as-is.
497 : */
498 128 : max = 8; /* max length of vendor */
499 640 : while ((max > 0) && *vendor == ' ') {
500 256 : max--;
501 256 : vendor++;
502 128 : }
503 : /*
504 : * XXX removing the following strlen() would be
505 : * good, using it means that for a an entry not in
506 : * the list, we scan every byte of every vendor
507 : * listed in scsi_static_device_list[], and never match
508 : * a single one (and still have to compare at
509 : * least the first byte of each vendor).
510 : */
511 : if (memcmp(devinfo->vendor, vendor,
512 896 : min(max, strlen(devinfo->vendor))))
513 640 : continue;
514 : /*
515 : * Skip spaces again.
516 : */
517 128 : max = 16; /* max length of model */
518 640 : while ((max > 0) && *model == ' ') {
519 256 : max--;
520 256 : model++;
521 128 : }
522 : if (memcmp(devinfo->model, model,
523 1408 : min(max, strlen(devinfo->model))))
524 128 : continue;
525 256 : return devinfo->flags;
526 : } else {
527 768 : if (!memcmp(devinfo->vendor, vendor,
528 : sizeof(devinfo->vendor)) &&
529 : !memcmp(devinfo->model, model,
530 : sizeof(devinfo->model)))
531 256 : return devinfo->flags;
532 : }
533 : }
534 : /* nothing found, return nothing */
535 256 : if (key != SCSI_DEVINFO_GLOBAL)
536 128 : return 0;
537 :
538 : /* except for the global list, where we have an exception */
539 384 : if (sdev->sdev_bflags)
540 256 : return sdev->sdev_bflags;
541 :
542 128 : return scsi_default_dev_flags;
543 : }
544 1 : EXPORT_SYMBOL(scsi_get_device_flags_keyed);
545 :
546 : #ifdef CONFIG_SCSI_PROC_FS
547 : struct double_list {
548 : struct list_head *top;
549 : struct list_head *bottom;
550 : };
551 :
552 : static int devinfo_seq_show(struct seq_file *m, void *v)
553 : {
554 0 : struct double_list *dl = v;
555 0 : struct scsi_dev_info_list_table *devinfo_table =
556 0 : list_entry(dl->top, struct scsi_dev_info_list_table, node);
557 0 : struct scsi_dev_info_list *devinfo =
558 0 : list_entry(dl->bottom, struct scsi_dev_info_list,
559 : dev_info_list);
560 :
561 0 : if (devinfo_table->scsi_dev_info_list.next == dl->bottom &&
562 : devinfo_table->name)
563 0 : seq_printf(m, "[%s]:\n", devinfo_table->name);
564 :
565 0 : seq_printf(m, "'%.8s' '%.16s' 0x%x\n",
566 : devinfo->vendor, devinfo->model, devinfo->flags);
567 0 : return 0;
568 : }
569 :
570 : static void *devinfo_seq_start(struct seq_file *m, loff_t *ppos)
571 : {
572 4 : struct double_list *dl = kmalloc(sizeof(*dl), GFP_KERNEL);
573 2 : loff_t pos = *ppos;
574 1 :
575 3 : if (!dl)
576 2 : return NULL;
577 1 :
578 8 : list_for_each(dl->top, &scsi_dev_info_list) {
579 2 : struct scsi_dev_info_list_table *devinfo_table =
580 4 : list_entry(dl->top, struct scsi_dev_info_list_table,
581 : node);
582 8 : list_for_each(dl->bottom, &devinfo_table->scsi_dev_info_list)
583 6 : if (pos-- == 0)
584 2 : return dl;
585 : }
586 :
587 1 : kfree(dl);
588 1 : return NULL;
589 : }
590 :
591 : static void *devinfo_seq_next(struct seq_file *m, void *v, loff_t *ppos)
592 : {
593 2 : struct double_list *dl = v;
594 1 : struct scsi_dev_info_list_table *devinfo_table =
595 4 : list_entry(dl->top, struct scsi_dev_info_list_table, node);
596 1 :
597 1 : ++*ppos;
598 1 : dl->bottom = dl->bottom->next;
599 4 : while (&devinfo_table->scsi_dev_info_list == dl->bottom) {
600 2 : dl->top = dl->top->next;
601 4 : if (dl->top == &scsi_dev_info_list) {
602 1 : kfree(dl);
603 1 : return NULL;
604 : }
605 3 : devinfo_table = list_entry(dl->top,
606 : struct scsi_dev_info_list_table,
607 : node);
608 1 : dl->bottom = devinfo_table->scsi_dev_info_list.next;
609 1 : }
610 :
611 1 : return dl;
612 : }
613 :
614 : static void devinfo_seq_stop(struct seq_file *m, void *v)
615 : {
616 1 : kfree(v);
617 1 : }
618 :
619 1 : static const struct seq_operations scsi_devinfo_seq_ops = {
620 : .start = devinfo_seq_start,
621 : .next = devinfo_seq_next,
622 : .stop = devinfo_seq_stop,
623 : .show = devinfo_seq_show,
624 : };
625 :
626 : static int proc_scsi_devinfo_open(struct inode *inode, struct file *file)
627 : {
628 4 : return seq_open(file, &scsi_devinfo_seq_ops);
629 : }
630 :
631 : /*
632 : * proc_scsi_dev_info_write - allow additions to scsi_dev_info_list via /proc.
633 : *
634 : * Description: Adds a black/white list entry for vendor and model with an
635 : * integer value of flag to the scsi device info list.
636 : * To use, echo "vendor:model:flag" > /proc/scsi/device_info
637 : */
638 : static ssize_t proc_scsi_devinfo_write(struct file *file,
639 : const char __user *buf,
640 : size_t length, loff_t *ppos)
641 1 : {
642 1 : char *buffer;
643 2 : ssize_t err = length;
644 1 :
645 4 : if (!buf || length>PAGE_SIZE)
646 1 : return -EINVAL;
647 4 : if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
648 1 : return -ENOMEM;
649 5 : if (copy_from_user(buffer, buf, length)) {
650 1 : err =-EFAULT;
651 1 : goto out;
652 : }
653 :
654 2 : if (length < PAGE_SIZE)
655 1 : buffer[length] = '\0';
656 2 : else if (buffer[PAGE_SIZE-1]) {
657 1 : err = -EINVAL;
658 1 : goto out;
659 : }
660 :
661 2 : scsi_dev_info_list_add_str(buffer);
662 :
663 1 : out:
664 2 : free_page((unsigned long)buffer);
665 2 : return err;
666 : }
667 :
668 1 : static const struct file_operations scsi_devinfo_proc_fops = {
669 : .owner = THIS_MODULE,
670 : .open = proc_scsi_devinfo_open,
671 : .read = seq_read,
672 : .write = proc_scsi_devinfo_write,
673 : .llseek = seq_lseek,
674 : .release = seq_release,
675 : };
676 : #endif /* CONFIG_SCSI_PROC_FS */
677 :
678 : module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0);
679 : MODULE_PARM_DESC(dev_flags,
680 : "Given scsi_dev_flags=vendor:model:flags[,v:m:f] add black/white"
681 : " list entries for vendor and model with an integer value of flags"
682 : " to the scsi device info list");
683 :
684 : module_param_named(default_dev_flags, scsi_default_dev_flags, int, S_IRUGO|S_IWUSR);
685 : MODULE_PARM_DESC(default_dev_flags,
686 : "scsi default device flag integer value");
687 :
688 : /**
689 : * scsi_exit_devinfo - remove /proc/scsi/device_info & the scsi_dev_info_list
690 : **/
691 : void scsi_exit_devinfo(void)
692 : {
693 : #ifdef CONFIG_SCSI_PROC_FS
694 7 : remove_proc_entry("scsi/device_info", NULL);
695 : #endif
696 :
697 21 : scsi_dev_info_remove_list(SCSI_DEVINFO_GLOBAL);
698 7 : }
699 :
700 : /**
701 : * scsi_dev_info_add_list - add a new devinfo list
702 : * @key: key of the list to add
703 : * @name: Name of the list to add (for /proc/scsi/device_info)
704 : *
705 : * Adds the requested list, returns zero on success, -EEXIST if the
706 : * key is already registered to a list, or other error on failure.
707 : */
708 : int scsi_dev_info_add_list(int key, const char *name)
709 : {
710 5 : struct scsi_dev_info_list_table *devinfo_table =
711 1 : scsi_devinfo_lookup_by_key(key);
712 1 :
713 5 : if (!IS_ERR(devinfo_table))
714 : /* list already exists */
715 1 : return -EEXIST;
716 :
717 3 : devinfo_table = kmalloc(sizeof(*devinfo_table), GFP_KERNEL);
718 :
719 2 : if (!devinfo_table)
720 1 : return -ENOMEM;
721 :
722 2 : INIT_LIST_HEAD(&devinfo_table->node);
723 2 : INIT_LIST_HEAD(&devinfo_table->scsi_dev_info_list);
724 1 : devinfo_table->name = name;
725 1 : devinfo_table->key = key;
726 2 : list_add_tail(&devinfo_table->node, &scsi_dev_info_list);
727 :
728 1 : return 0;
729 : }
730 : EXPORT_SYMBOL(scsi_dev_info_add_list);
731 :
732 : /**
733 : * scsi_dev_info_remove_list - destroy an added devinfo list
734 : * @key: key of the list to destroy
735 : *
736 : * Iterates over the entire list first, freeing all the values, then
737 : * frees the list itself. Returns 0 on success or -EINVAL if the key
738 : * can't be found.
739 : */
740 : int scsi_dev_info_remove_list(int key)
741 : {
742 7 : struct list_head *lh, *lh_next;
743 35 : struct scsi_dev_info_list_table *devinfo_table =
744 7 : scsi_devinfo_lookup_by_key(key);
745 7 :
746 35 : if (IS_ERR(devinfo_table))
747 7 : /* no such list */
748 14 : return -EINVAL;
749 :
750 : /* remove from the master list */
751 14 : list_del(&devinfo_table->node);
752 :
753 49 : list_for_each_safe(lh, lh_next, &devinfo_table->scsi_dev_info_list) {
754 7 : struct scsi_dev_info_list *devinfo;
755 14 :
756 14 : devinfo = list_entry(lh, struct scsi_dev_info_list,
757 : dev_info_list);
758 7 : kfree(devinfo);
759 : }
760 7 : kfree(devinfo_table);
761 :
762 7 : return 0;
763 : }
764 : EXPORT_SYMBOL(scsi_dev_info_remove_list);
765 :
766 : /**
767 : * scsi_init_devinfo - set up the dynamic device list.
768 : *
769 : * Description:
770 : * Add command line entries from scsi_dev_flags, then add
771 : * scsi_static_device_list entries to the scsi device info list.
772 : */
773 : int __init scsi_init_devinfo(void)
774 : {
775 1 : #ifdef CONFIG_SCSI_PROC_FS
776 1 : struct proc_dir_entry *p;
777 1 : #endif
778 : int error, i;
779 :
780 4 : error = scsi_dev_info_add_list(SCSI_DEVINFO_GLOBAL, NULL);
781 2 : if (error)
782 1 : return error;
783 :
784 2 : error = scsi_dev_info_list_add_str(scsi_dev_flags);
785 2 : if (error)
786 1 : goto out;
787 :
788 5 : for (i = 0; scsi_static_device_list[i].vendor; i++) {
789 4 : error = scsi_dev_info_list_add(1 /* compatibile */,
790 1 : scsi_static_device_list[i].vendor,
791 : scsi_static_device_list[i].model,
792 : NULL,
793 : scsi_static_device_list[i].flags);
794 2 : if (error)
795 1 : goto out;
796 : }
797 :
798 : #ifdef CONFIG_SCSI_PROC_FS
799 2 : p = proc_create("scsi/device_info", 0, NULL, &scsi_devinfo_proc_fops);
800 2 : if (!p) {
801 1 : error = -ENOMEM;
802 1 : goto out;
803 : }
804 : #endif /* CONFIG_SCSI_PROC_FS */
805 :
806 1 : out:
807 6 : if (error)
808 6 : scsi_exit_devinfo();
809 4 : return error;
810 : }
|