Blame view

drivers/scsi/scsi_transport_spi.c 43.8 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /* 
   *  Parallel SCSI (SPI) transport specific attributes exported to sysfs.
   *
   *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
   *  Copyright (c) 2004, 2005 James Bottomley <James.Bottomley@SteelEye.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
   */
  #include <linux/ctype.h>
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/workqueue.h>
949bf7975   James Bottomley   [SCSI] fix comman...
12
  #include <linux/blkdev.h>
d158d2616   Jes Sorensen   [SCSI] sem2mutex:...
13
  #include <linux/mutex.h>
9f9a73b6f   Randy Dunlap   [SCSI] scsi_trans...
14
  #include <linux/sysfs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/slab.h>
203f8c250   Bart Van Assche   block, scsi: Fix ...
16
  #include <linux/suspend.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
  #include <scsi/scsi.h>
  #include "scsi_priv.h"
  #include <scsi/scsi_device.h>
  #include <scsi/scsi_host.h>
33aa687db   James Bottomley   [SCSI] convert SP...
21
  #include <scsi/scsi_cmnd.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include <scsi/scsi_eh.h>
506686333   Christoph Hellwig   scsi: remove abus...
23
  #include <scsi/scsi_tcq.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  #include <scsi/scsi_transport.h>
  #include <scsi/scsi_transport_spi.h>
d872ebe45   James Bottomley   [SCSI] add missin...
26
  #define SPI_NUM_ATTRS 14	/* increase this if you add attributes */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
  #define SPI_OTHER_ATTRS 1	/* Increase this if you add "always
  				 * on" attributes */
  #define SPI_HOST_ATTRS	1
  
  #define SPI_MAX_ECHO_BUFFER_SIZE	4096
949bf7975   James Bottomley   [SCSI] fix comman...
32
33
34
35
  #define DV_LOOPS	3
  #define DV_TIMEOUT	(10*HZ)
  #define DV_RETRIES	3	/* should only need at most 
  				 * two cc/ua clears */
a9e0edb68   James Bottomley   scsi_transport_sp...
36
37
  /* Our blacklist flags */
  enum {
093b8886f   Bart Van Assche   scsi: core: Use b...
38
  	SPI_BLIST_NOIUS = (__force blist_flags_t)0x1,
a9e0edb68   James Bottomley   scsi_transport_sp...
39
40
41
42
43
44
  };
  
  /* blacklist table, modelled on scsi_devinfo.c */
  static struct {
  	char *vendor;
  	char *model;
093b8886f   Bart Van Assche   scsi: core: Use b...
45
  	blist_flags_t flags;
a9e0edb68   James Bottomley   scsi_transport_sp...
46
47
48
49
50
  } spi_static_device_list[] __initdata = {
  	{"HP", "Ultrium 3-SCSI", SPI_BLIST_NOIUS },
  	{"IBM", "ULTRIUM-TD3", SPI_BLIST_NOIUS },
  	{NULL, NULL, 0}
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  /* Private data accessors (keep these out of the header file) */
dfdc58ba3   James Bottomley   [SCSI] SPI transp...
52
  #define spi_dv_in_progress(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_in_progress)
d158d2616   Jes Sorensen   [SCSI] sem2mutex:...
53
  #define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
57
  
  struct spi_internal {
  	struct scsi_transport_template t;
  	struct spi_function_template *f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  };
  
  #define to_spi_internal(tmpl)	container_of(tmpl, struct spi_internal, t)
  
  static const int ppr_to_ps[] = {
  	/* The PPR values 0-6 are reserved, fill them in when
  	 * the committee defines them */
  	-1,			/* 0x00 */
  	-1,			/* 0x01 */
  	-1,			/* 0x02 */
  	-1,			/* 0x03 */
  	-1,			/* 0x04 */
  	-1,			/* 0x05 */
  	-1,			/* 0x06 */
  	 3125,			/* 0x07 */
  	 6250,			/* 0x08 */
  	12500,			/* 0x09 */
  	25000,			/* 0x0a */
  	30300,			/* 0x0b */
  	50000,			/* 0x0c */
  };
  /* The PPR values at which you calculate the period in ns by multiplying
   * by 4 */
  #define SPI_STATIC_PPR	0x0c
  
  static int sprint_frac(char *dest, int value, int denom)
  {
  	int frac = value % denom;
  	int result = sprintf(dest, "%d", value / denom);
  
  	if (frac == 0)
  		return result;
  	dest[result++] = '.';
  
  	do {
  		denom /= 10;
  		sprintf(dest + result, "%d", frac / denom);
  		result++;
  		frac %= denom;
  	} while (frac);
  
  	dest[result++] = '\0';
  	return result;
  }
33aa687db   James Bottomley   [SCSI] convert SP...
102
103
104
105
  static int spi_execute(struct scsi_device *sdev, const void *cmd,
  		       enum dma_data_direction dir,
  		       void *buffer, unsigned bufflen,
  		       struct scsi_sense_hdr *sshdr)
949bf7975   James Bottomley   [SCSI] fix comman...
106
  {
33aa687db   James Bottomley   [SCSI] convert SP...
107
108
  	int i, result;
  	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
76aaf87b4   Christoph Hellwig   scsi: merge __scs...
109
110
111
112
  	struct scsi_sense_hdr sshdr_tmp;
  
  	if (!sshdr)
  		sshdr = &sshdr_tmp;
949bf7975   James Bottomley   [SCSI] fix comman...
113
114
  
  	for(i = 0; i < DV_RETRIES; i++) {
76aaf87b4   Christoph Hellwig   scsi: merge __scs...
115
116
  		result = scsi_execute(sdev, cmd, dir, buffer, bufflen, sense,
  				      sshdr, DV_TIMEOUT, /* retries */ 1,
6000a368c   Mike Christie   [SCSI] block: sep...
117
118
  				      REQ_FAILFAST_DEV |
  				      REQ_FAILFAST_TRANSPORT |
f4f4e47e4   FUJITA Tomonori   [SCSI] add residu...
119
  				      REQ_FAILFAST_DRIVER,
76aaf87b4   Christoph Hellwig   scsi: merge __scs...
120
  				      0, NULL);
c65be1a63   Johannes Thumshirn   scsi: core: check...
121
  		if (driver_byte(result) != DRIVER_SENSE ||
76aaf87b4   Christoph Hellwig   scsi: merge __scs...
122
123
  		    sshdr->sense_key != UNIT_ATTENTION)
  			break;
949bf7975   James Bottomley   [SCSI] fix comman...
124
  	}
33aa687db   James Bottomley   [SCSI] convert SP...
125
  	return result;
949bf7975   James Bottomley   [SCSI] fix comman...
126
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
133
134
135
136
137
138
139
  static struct {
  	enum spi_signal_type	value;
  	char			*name;
  } signal_types[] = {
  	{ SPI_SIGNAL_UNKNOWN, "unknown" },
  	{ SPI_SIGNAL_SE, "SE" },
  	{ SPI_SIGNAL_LVD, "LVD" },
  	{ SPI_SIGNAL_HVD, "HVD" },
  };
  
  static inline const char *spi_signal_to_string(enum spi_signal_type type)
  {
  	int i;
6391a1137   Tobias Klauser   [SCSI] drivers/sc...
140
  	for (i = 0; i < ARRAY_SIZE(signal_types); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
146
147
148
  		if (type == signal_types[i].value)
  			return signal_types[i].name;
  	}
  	return NULL;
  }
  static inline enum spi_signal_type spi_signal_to_value(const char *name)
  {
  	int i, len;
6391a1137   Tobias Klauser   [SCSI] drivers/sc...
149
  	for (i = 0; i < ARRAY_SIZE(signal_types); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
154
155
156
157
  		len =  strlen(signal_types[i].name);
  		if (strncmp(name, signal_types[i].name, len) == 0 &&
  		    (name[len] == '
  ' || name[len] == '\0'))
  			return signal_types[i].value;
  	}
  	return SPI_SIGNAL_UNKNOWN;
  }
d0a7e5740   James Bottomley   [SCSI] correct tr...
158
  static int spi_host_setup(struct transport_container *tc, struct device *dev,
ee959b00c   Tony Jones   SCSI: convert str...
159
  			  struct device *cdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
163
164
165
166
  {
  	struct Scsi_Host *shost = dev_to_shost(dev);
  
  	spi_signalling(shost) = SPI_SIGNAL_UNKNOWN;
  
  	return 0;
  }
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
167
168
  static int spi_host_configure(struct transport_container *tc,
  			      struct device *dev,
ee959b00c   Tony Jones   SCSI: convert str...
169
  			      struct device *cdev);
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
170

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
174
  static DECLARE_TRANSPORT_CLASS(spi_host_class,
  			       "spi_host",
  			       spi_host_setup,
  			       NULL,
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
175
  			       spi_host_configure);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
179
180
  
  static int spi_host_match(struct attribute_container *cont,
  			  struct device *dev)
  {
  	struct Scsi_Host *shost;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
187
188
  
  	if (!scsi_is_host_device(dev))
  		return 0;
  
  	shost = dev_to_shost(dev);
  	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
  	    != &spi_host_class.class)
  		return 0;
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
189
  	return &shost->transportt->host_attrs.ac == cont;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  }
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
191
192
  static int spi_target_configure(struct transport_container *tc,
  				struct device *dev,
ee959b00c   Tony Jones   SCSI: convert str...
193
  				struct device *cdev);
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
194

d0a7e5740   James Bottomley   [SCSI] correct tr...
195
196
  static int spi_device_configure(struct transport_container *tc,
  				struct device *dev,
ee959b00c   Tony Jones   SCSI: convert str...
197
  				struct device *cdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
  {
  	struct scsi_device *sdev = to_scsi_device(dev);
  	struct scsi_target *starget = sdev->sdev_target;
093b8886f   Bart Van Assche   scsi: core: Use b...
201
202
203
204
205
  	blist_flags_t bflags;
  
  	bflags = scsi_get_device_flags_keyed(sdev, &sdev->inquiry[8],
  					     &sdev->inquiry[16],
  					     SCSI_DEVINFO_SPI);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
208
209
210
211
212
213
214
  
  	/* Populate the target capability fields with the values
  	 * gleaned from the device inquiry */
  
  	spi_support_sync(starget) = scsi_device_sync(sdev);
  	spi_support_wide(starget) = scsi_device_wide(sdev);
  	spi_support_dt(starget) = scsi_device_dt(sdev);
  	spi_support_dt_only(starget) = scsi_device_dt_only(sdev);
  	spi_support_ius(starget) = scsi_device_ius(sdev);
a9e0edb68   James Bottomley   scsi_transport_sp...
215
216
217
218
219
  	if (bflags & SPI_BLIST_NOIUS) {
  		dev_info(dev, "Information Units disabled by blacklist
  ");
  		spi_support_ius(starget) = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
223
  	spi_support_qas(starget) = scsi_device_qas(sdev);
  
  	return 0;
  }
d0a7e5740   James Bottomley   [SCSI] correct tr...
224
225
  static int spi_setup_transport_attrs(struct transport_container *tc,
  				     struct device *dev,
ee959b00c   Tony Jones   SCSI: convert str...
226
  				     struct device *cdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
  {
  	struct scsi_target *starget = to_scsi_target(dev);
  
  	spi_period(starget) = -1;	/* illegal value */
62a861297   James Bottomley   [SCSI] implement ...
231
  	spi_min_period(starget) = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  	spi_offset(starget) = 0;	/* async */
62a861297   James Bottomley   [SCSI] implement ...
233
  	spi_max_offset(starget) = 255;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  	spi_width(starget) = 0;	/* narrow */
62a861297   James Bottomley   [SCSI] implement ...
235
  	spi_max_width(starget) = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
  	spi_iu(starget) = 0;	/* no IU */
ea4431906   James Bottomley   [SCSI] aic79xx: m...
237
  	spi_max_iu(starget) = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
  	spi_dt(starget) = 0;	/* ST */
  	spi_qas(starget) = 0;
ea4431906   James Bottomley   [SCSI] aic79xx: m...
240
  	spi_max_qas(starget) = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
244
  	spi_wr_flow(starget) = 0;
  	spi_rd_strm(starget) = 0;
  	spi_rti(starget) = 0;
  	spi_pcomp_en(starget) = 0;
d872ebe45   James Bottomley   [SCSI] add missin...
245
  	spi_hold_mcs(starget) = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  	spi_dv_pending(starget) = 0;
dfdc58ba3   James Bottomley   [SCSI] SPI transp...
247
  	spi_dv_in_progress(starget) = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  	spi_initial_dv(starget) = 0;
d158d2616   Jes Sorensen   [SCSI] sem2mutex:...
249
  	mutex_init(&spi_dv_mutex(starget));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
  
  	return 0;
  }
62a861297   James Bottomley   [SCSI] implement ...
253
254
255
  #define spi_transport_show_simple(field, format_string)			\
  									\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
256
257
  show_spi_transport_##field(struct device *dev, 			\
  			   struct device_attribute *attr, char *buf)	\
62a861297   James Bottomley   [SCSI] implement ...
258
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
259
  	struct scsi_target *starget = transport_class_to_starget(dev);	\
62a861297   James Bottomley   [SCSI] implement ...
260
261
262
263
264
265
266
267
268
  	struct spi_transport_attrs *tp;					\
  									\
  	tp = (struct spi_transport_attrs *)&starget->starget_data;	\
  	return snprintf(buf, 20, format_string, tp->field);		\
  }
  
  #define spi_transport_store_simple(field, format_string)		\
  									\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
269
270
271
  store_spi_transport_##field(struct device *dev, 			\
  			    struct device_attribute *attr, 		\
  			    const char *buf, size_t count)		\
62a861297   James Bottomley   [SCSI] implement ...
272
273
  {									\
  	int val;							\
ee959b00c   Tony Jones   SCSI: convert str...
274
  	struct scsi_target *starget = transport_class_to_starget(dev);	\
62a861297   James Bottomley   [SCSI] implement ...
275
276
277
278
279
280
281
  	struct spi_transport_attrs *tp;					\
  									\
  	tp = (struct spi_transport_attrs *)&starget->starget_data;	\
  	val = simple_strtoul(buf, NULL, 0);				\
  	tp->field = val;						\
  	return count;							\
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
  #define spi_transport_show_function(field, format_string)		\
  									\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
285
286
  show_spi_transport_##field(struct device *dev, 			\
  			   struct device_attribute *attr, char *buf)	\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
288
  	struct scsi_target *starget = transport_class_to_starget(dev);	\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
295
296
297
298
299
  	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
  	struct spi_transport_attrs *tp;					\
  	struct spi_internal *i = to_spi_internal(shost->transportt);	\
  	tp = (struct spi_transport_attrs *)&starget->starget_data;	\
  	if (i->f->get_##field)						\
  		i->f->get_##field(starget);				\
  	return snprintf(buf, 20, format_string, tp->field);		\
  }
  
  #define spi_transport_store_function(field, format_string)		\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
300
301
302
  store_spi_transport_##field(struct device *dev, 			\
  			    struct device_attribute *attr,		\
  			    const char *buf, size_t count)		\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
  {									\
  	int val;							\
ee959b00c   Tony Jones   SCSI: convert str...
305
  	struct scsi_target *starget = transport_class_to_starget(dev);	\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
  	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
  	struct spi_internal *i = to_spi_internal(shost->transportt);	\
  									\
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
309
310
  	if (!i->f->set_##field)						\
  		return -EINVAL;						\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
  	val = simple_strtoul(buf, NULL, 0);				\
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
312
  	i->f->set_##field(starget, val);				\
62a861297   James Bottomley   [SCSI] implement ...
313
314
315
316
317
  	return count;							\
  }
  
  #define spi_transport_store_max(field, format_string)			\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
318
319
320
  store_spi_transport_##field(struct device *dev, 			\
  			    struct device_attribute *attr,		\
  			    const char *buf, size_t count)		\
62a861297   James Bottomley   [SCSI] implement ...
321
322
  {									\
  	int val;							\
ee959b00c   Tony Jones   SCSI: convert str...
323
  	struct scsi_target *starget = transport_class_to_starget(dev);	\
62a861297   James Bottomley   [SCSI] implement ...
324
325
326
327
328
  	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
  	struct spi_internal *i = to_spi_internal(shost->transportt);	\
  	struct spi_transport_attrs *tp					\
  		= (struct spi_transport_attrs *)&starget->starget_data;	\
  									\
806ffec1a   Tom Rix   scsi: scsi_transp...
329
  	if (!i->f->set_##field)						\
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
330
  		return -EINVAL;						\
62a861297   James Bottomley   [SCSI] implement ...
331
332
333
  	val = simple_strtoul(buf, NULL, 0);				\
  	if (val > tp->max_##field)					\
  		val = tp->max_##field;					\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
338
339
340
  	i->f->set_##field(starget, val);				\
  	return count;							\
  }
  
  #define spi_transport_rd_attr(field, format_string)			\
  	spi_transport_show_function(field, format_string)		\
  	spi_transport_store_function(field, format_string)		\
ee959b00c   Tony Jones   SCSI: convert str...
341
342
343
  static DEVICE_ATTR(field, S_IRUGO,				\
  		   show_spi_transport_##field,			\
  		   store_spi_transport_##field);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344

62a861297   James Bottomley   [SCSI] implement ...
345
346
347
  #define spi_transport_simple_attr(field, format_string)			\
  	spi_transport_show_simple(field, format_string)			\
  	spi_transport_store_simple(field, format_string)		\
ee959b00c   Tony Jones   SCSI: convert str...
348
349
350
  static DEVICE_ATTR(field, S_IRUGO,				\
  		   show_spi_transport_##field,			\
  		   store_spi_transport_##field);
62a861297   James Bottomley   [SCSI] implement ...
351
352
353
354
355
  
  #define spi_transport_max_attr(field, format_string)			\
  	spi_transport_show_function(field, format_string)		\
  	spi_transport_store_max(field, format_string)			\
  	spi_transport_simple_attr(max_##field, format_string)		\
ee959b00c   Tony Jones   SCSI: convert str...
356
357
358
  static DEVICE_ATTR(field, S_IRUGO,				\
  		   show_spi_transport_##field,			\
  		   store_spi_transport_##field);
62a861297   James Bottomley   [SCSI] implement ...
359

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  /* The Parallel SCSI Tranport Attributes: */
62a861297   James Bottomley   [SCSI] implement ...
361
362
363
364
  spi_transport_max_attr(offset, "%d
  ");
  spi_transport_max_attr(width, "%d
  ");
ea4431906   James Bottomley   [SCSI] aic79xx: m...
365
366
  spi_transport_max_attr(iu, "%d
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
  spi_transport_rd_attr(dt, "%d
  ");
ea4431906   James Bottomley   [SCSI] aic79xx: m...
369
370
  spi_transport_max_attr(qas, "%d
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
375
376
377
378
  spi_transport_rd_attr(wr_flow, "%d
  ");
  spi_transport_rd_attr(rd_strm, "%d
  ");
  spi_transport_rd_attr(rti, "%d
  ");
  spi_transport_rd_attr(pcomp_en, "%d
  ");
d872ebe45   James Bottomley   [SCSI] add missin...
379
380
  spi_transport_rd_attr(hold_mcs, "%d
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381

e8bac9e06   James Bottomley   [SCSI] scsi_trans...
382
383
  /* we only care about the first child device that's a real SCSI device
   * so we return 1 to terminate the iteration when we find it */
9a881f166   Greg Kroah-Hartman   [PATCH] use devic...
384
385
  static int child_iter(struct device *dev, void *data)
  {
e8bac9e06   James Bottomley   [SCSI] scsi_trans...
386
387
  	if (!scsi_is_sdev_device(dev))
  		return 0;
9a881f166   Greg Kroah-Hartman   [PATCH] use devic...
388

e8bac9e06   James Bottomley   [SCSI] scsi_trans...
389
  	spi_dv_device(to_scsi_device(dev));
9a881f166   Greg Kroah-Hartman   [PATCH] use devic...
390
391
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
393
394
  store_spi_revalidate(struct device *dev, struct device_attribute *attr,
  		     const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
  {
ee959b00c   Tony Jones   SCSI: convert str...
396
  	struct scsi_target *starget = transport_class_to_starget(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397

9a881f166   Greg Kroah-Hartman   [PATCH] use devic...
398
  	device_for_each_child(&starget->dev, NULL, child_iter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
  	return count;
  }
ee959b00c   Tony Jones   SCSI: convert str...
401
  static DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
403
404
  
  /* Translate the period into ns according to the current spec
   * for SDTR/PPR messages */
ef72582e7   Matthew Wilcox   [SCSI] Add PPR su...
405
  static int period_to_str(char *buf, int period)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  	int len, picosec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408

62a861297   James Bottomley   [SCSI] implement ...
409
  	if (period < 0 || period > 0xff) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
  		picosec = -1;
62a861297   James Bottomley   [SCSI] implement ...
411
412
  	} else if (period <= SPI_STATIC_PPR) {
  		picosec = ppr_to_ps[period];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
  	} else {
62a861297   James Bottomley   [SCSI] implement ...
414
  		picosec = period * 4000;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
419
420
421
  	}
  
  	if (picosec == -1) {
  		len = sprintf(buf, "reserved");
  	} else {
  		len = sprint_frac(buf, picosec, 1000);
  	}
ef72582e7   Matthew Wilcox   [SCSI] Add PPR su...
422
423
424
425
  	return len;
  }
  
  static ssize_t
ea697e456   Matthew Wilcox   [SCSI] unused sho...
426
  show_spi_transport_period_helper(char *buf, int period)
ef72582e7   Matthew Wilcox   [SCSI] Add PPR su...
427
428
  {
  	int len = period_to_str(buf, period);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
433
434
435
  	buf[len++] = '
  ';
  	buf[len] = '\0';
  	return len;
  }
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
436
  store_spi_transport_period_helper(struct device *dev, const char *buf,
62a861297   James Bottomley   [SCSI] implement ...
437
  				  size_t count, int *periodp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  	int j, picosec, period = -1;
  	char *endp;
  
  	picosec = simple_strtoul(buf, &endp, 10) * 1000;
  	if (*endp == '.') {
  		int mult = 100;
  		do {
  			endp++;
  			if (!isdigit(*endp))
  				break;
  			picosec += (*endp - '0') * mult;
  			mult /= 10;
  		} while (mult > 0);
  	}
  
  	for (j = 0; j <= SPI_STATIC_PPR; j++) {
  		if (ppr_to_ps[j] < picosec)
  			continue;
  		period = j;
  		break;
  	}
  
  	if (period == -1)
  		period = picosec / 4000;
  
  	if (period > 0xff)
  		period = 0xff;
62a861297   James Bottomley   [SCSI] implement ...
466
  	*periodp = period;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
  
  	return count;
  }
62a861297   James Bottomley   [SCSI] implement ...
470
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
471
472
  show_spi_transport_period(struct device *dev,
  			  struct device_attribute *attr, char *buf)
62a861297   James Bottomley   [SCSI] implement ...
473
  {
ee959b00c   Tony Jones   SCSI: convert str...
474
  	struct scsi_target *starget = transport_class_to_starget(dev);
62a861297   James Bottomley   [SCSI] implement ...
475
476
477
478
479
480
481
  	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
  	struct spi_internal *i = to_spi_internal(shost->transportt);
  	struct spi_transport_attrs *tp =
  		(struct spi_transport_attrs *)&starget->starget_data;
  
  	if (i->f->get_period)
  		i->f->get_period(starget);
ea697e456   Matthew Wilcox   [SCSI] unused sho...
482
  	return show_spi_transport_period_helper(buf, tp->period);
62a861297   James Bottomley   [SCSI] implement ...
483
484
485
  }
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
486
487
  store_spi_transport_period(struct device *cdev, struct device_attribute *attr,
  			   const char *buf, size_t count)
62a861297   James Bottomley   [SCSI] implement ...
488
489
490
491
492
493
494
  {
  	struct scsi_target *starget = transport_class_to_starget(cdev);
  	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
  	struct spi_internal *i = to_spi_internal(shost->transportt);
  	struct spi_transport_attrs *tp =
  		(struct spi_transport_attrs *)&starget->starget_data;
  	int period, retval;
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
495
496
  	if (!i->f->set_period)
  		return -EINVAL;
62a861297   James Bottomley   [SCSI] implement ...
497
498
499
500
501
502
503
504
505
  	retval = store_spi_transport_period_helper(cdev, buf, count, &period);
  
  	if (period < tp->min_period)
  		period = tp->min_period;
  
  	i->f->set_period(starget, period);
  
  	return retval;
  }
ee959b00c   Tony Jones   SCSI: convert str...
506
507
508
  static DEVICE_ATTR(period, S_IRUGO,
  		   show_spi_transport_period,
  		   store_spi_transport_period);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509

62a861297   James Bottomley   [SCSI] implement ...
510
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
511
512
  show_spi_transport_min_period(struct device *cdev,
  			      struct device_attribute *attr, char *buf)
62a861297   James Bottomley   [SCSI] implement ...
513
514
  {
  	struct scsi_target *starget = transport_class_to_starget(cdev);
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
515
516
  	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
  	struct spi_internal *i = to_spi_internal(shost->transportt);
62a861297   James Bottomley   [SCSI] implement ...
517
518
  	struct spi_transport_attrs *tp =
  		(struct spi_transport_attrs *)&starget->starget_data;
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
519
520
  	if (!i->f->set_period)
  		return -EINVAL;
ea697e456   Matthew Wilcox   [SCSI] unused sho...
521
  	return show_spi_transport_period_helper(buf, tp->min_period);
62a861297   James Bottomley   [SCSI] implement ...
522
523
524
  }
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
525
526
527
  store_spi_transport_min_period(struct device *cdev,
  			       struct device_attribute *attr,
  			       const char *buf, size_t count)
62a861297   James Bottomley   [SCSI] implement ...
528
529
530
531
532
533
534
535
  {
  	struct scsi_target *starget = transport_class_to_starget(cdev);
  	struct spi_transport_attrs *tp =
  		(struct spi_transport_attrs *)&starget->starget_data;
  
  	return store_spi_transport_period_helper(cdev, buf, count,
  						 &tp->min_period);
  }
ee959b00c   Tony Jones   SCSI: convert str...
536
537
538
  static DEVICE_ATTR(min_period, S_IRUGO,
  		   show_spi_transport_min_period,
  		   store_spi_transport_min_period);
62a861297   James Bottomley   [SCSI] implement ...
539

ee959b00c   Tony Jones   SCSI: convert str...
540
541
542
  static ssize_t show_spi_host_signalling(struct device *cdev,
  					struct device_attribute *attr,
  					char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
546
547
548
549
550
551
552
  {
  	struct Scsi_Host *shost = transport_class_to_shost(cdev);
  	struct spi_internal *i = to_spi_internal(shost->transportt);
  
  	if (i->f->get_signalling)
  		i->f->get_signalling(shost);
  
  	return sprintf(buf, "%s
  ", spi_signal_to_string(spi_signalling(shost)));
  }
ee959b00c   Tony Jones   SCSI: convert str...
553
554
  static ssize_t store_spi_host_signalling(struct device *dev,
  					 struct device_attribute *attr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
  					 const char *buf, size_t count)
  {
ee959b00c   Tony Jones   SCSI: convert str...
557
  	struct Scsi_Host *shost = transport_class_to_shost(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
  	struct spi_internal *i = to_spi_internal(shost->transportt);
  	enum spi_signal_type type = spi_signal_to_value(buf);
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
560
561
  	if (!i->f->set_signalling)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
565
566
  	if (type != SPI_SIGNAL_UNKNOWN)
  		i->f->set_signalling(shost, type);
  
  	return count;
  }
ee959b00c   Tony Jones   SCSI: convert str...
567
568
569
  static DEVICE_ATTR(signalling, S_IRUGO,
  		   show_spi_host_signalling,
  		   store_spi_host_signalling);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570

0ac2377b6   Hannes Reinecke   [SCSI] scsi_trans...
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
  static ssize_t show_spi_host_width(struct device *cdev,
  				      struct device_attribute *attr,
  				      char *buf)
  {
  	struct Scsi_Host *shost = transport_class_to_shost(cdev);
  
  	return sprintf(buf, "%s
  ", shost->max_id == 16 ? "wide" : "narrow");
  }
  static DEVICE_ATTR(host_width, S_IRUGO,
  		   show_spi_host_width, NULL);
  
  static ssize_t show_spi_host_hba_id(struct device *cdev,
  				    struct device_attribute *attr,
  				    char *buf)
  {
  	struct Scsi_Host *shost = transport_class_to_shost(cdev);
  
  	return sprintf(buf, "%d
  ", shost->this_id);
  }
  static DEVICE_ATTR(hba_id, S_IRUGO,
  		   show_spi_host_hba_id, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
  #define DV_SET(x, y)			\
  	if(i->f->set_##x)		\
  		i->f->set_##x(sdev->sdev_target, y)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
599
600
601
602
603
604
605
606
  enum spi_compare_returns {
  	SPI_COMPARE_SUCCESS,
  	SPI_COMPARE_FAILURE,
  	SPI_COMPARE_SKIP_TEST,
  };
  
  
  /* This is for read/write Domain Validation:  If the device supports
   * an echo buffer, we do read/write tests to it */
  static enum spi_compare_returns
33aa687db   James Bottomley   [SCSI] convert SP...
607
  spi_dv_device_echo_buffer(struct scsi_device *sdev, u8 *buffer,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
  			  u8 *ptr, const int retries)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
  	int len = ptr - buffer;
33aa687db   James Bottomley   [SCSI] convert SP...
611
  	int j, k, r, result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
  	unsigned int pattern = 0x0000ffff;
33aa687db   James Bottomley   [SCSI] convert SP...
613
  	struct scsi_sense_hdr sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
  
  	const char spi_write_buffer[] = {
  		WRITE_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0
  	};
  	const char spi_read_buffer[] = {
  		READ_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0
  	};
  
  	/* set up the pattern buffer.  Doesn't matter if we spill
  	 * slightly beyond since that's where the read buffer is */
  	for (j = 0; j < len; ) {
  
  		/* fill the buffer with counting (test a) */
  		for ( ; j < min(len, 32); j++)
  			buffer[j] = j;
  		k = j;
  		/* fill the buffer with alternating words of 0x0 and
  		 * 0xffff (test b) */
  		for ( ; j < min(len, k + 32); j += 2) {
  			u16 *word = (u16 *)&buffer[j];
  			
  			*word = (j & 0x02) ? 0x0000 : 0xffff;
  		}
  		k = j;
  		/* fill with crosstalk (alternating 0x5555 0xaaa)
                   * (test c) */
  		for ( ; j < min(len, k + 32); j += 2) {
  			u16 *word = (u16 *)&buffer[j];
  
  			*word = (j & 0x02) ? 0x5555 : 0xaaaa;
  		}
  		k = j;
  		/* fill with shifting bits (test d) */
  		for ( ; j < min(len, k + 32); j += 4) {
  			u32 *word = (unsigned int *)&buffer[j];
  			u32 roll = (pattern & 0x80000000) ? 1 : 0;
  			
  			*word = pattern;
  			pattern = (pattern << 1) | roll;
  		}
  		/* don't bother with random data (test e) */
  	}
  
  	for (r = 0; r < retries; r++) {
33aa687db   James Bottomley   [SCSI] convert SP...
658
659
660
  		result = spi_execute(sdev, spi_write_buffer, DMA_TO_DEVICE,
  				     buffer, len, &sshdr);
  		if(result || !scsi_device_online(sdev)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
  
  			scsi_device_set_state(sdev, SDEV_QUIESCE);
33aa687db   James Bottomley   [SCSI] convert SP...
663
  			if (scsi_sense_valid(&sshdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
668
669
670
671
672
  			    && sshdr.sense_key == ILLEGAL_REQUEST
  			    /* INVALID FIELD IN CDB */
  			    && sshdr.asc == 0x24 && sshdr.ascq == 0x00)
  				/* This would mean that the drive lied
  				 * to us about supporting an echo
  				 * buffer (unfortunately some Western
  				 * Digital drives do precisely this)
  				 */
  				return SPI_COMPARE_SKIP_TEST;
9ccfc756a   James Bottomley   [SCSI] move the m...
673
674
  			sdev_printk(KERN_ERR, sdev, "Write Buffer failure %x
  ", result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
677
678
  			return SPI_COMPARE_FAILURE;
  		}
  
  		memset(ptr, 0, len);
33aa687db   James Bottomley   [SCSI] convert SP...
679
680
  		spi_execute(sdev, spi_read_buffer, DMA_FROM_DEVICE,
  			    ptr, len, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
684
685
686
687
688
689
690
691
  		scsi_device_set_state(sdev, SDEV_QUIESCE);
  
  		if (memcmp(buffer, ptr, len) != 0)
  			return SPI_COMPARE_FAILURE;
  	}
  	return SPI_COMPARE_SUCCESS;
  }
  
  /* This is for the simplest form of Domain Validation: a read test
   * on the inquiry data from the device */
  static enum spi_compare_returns
33aa687db   James Bottomley   [SCSI] convert SP...
692
  spi_dv_device_compare_inquiry(struct scsi_device *sdev, u8 *buffer,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
  			      u8 *ptr, const int retries)
  {
33aa687db   James Bottomley   [SCSI] convert SP...
695
696
  	int r, result;
  	const int len = sdev->inquiry_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
699
700
701
  	const char spi_inquiry[] = {
  		INQUIRY, 0, 0, 0, len, 0
  	};
  
  	for (r = 0; r < retries; r++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
  		memset(ptr, 0, len);
33aa687db   James Bottomley   [SCSI] convert SP...
703
704
  		result = spi_execute(sdev, spi_inquiry, DMA_FROM_DEVICE,
  				     ptr, len, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
  		
33aa687db   James Bottomley   [SCSI] convert SP...
706
  		if(result || !scsi_device_online(sdev)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
  			scsi_device_set_state(sdev, SDEV_QUIESCE);
  			return SPI_COMPARE_FAILURE;
  		}
  
  		/* If we don't have the inquiry data already, the
  		 * first read gets it */
  		if (ptr == buffer) {
  			ptr += len;
  			--r;
  			continue;
  		}
  
  		if (memcmp(buffer, ptr, len) != 0)
  			/* failure */
  			return SPI_COMPARE_FAILURE;
  	}
  	return SPI_COMPARE_SUCCESS;
  }
  
  static enum spi_compare_returns
33aa687db   James Bottomley   [SCSI] convert SP...
727
  spi_dv_retrain(struct scsi_device *sdev, u8 *buffer, u8 *ptr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
  	       enum spi_compare_returns 
33aa687db   James Bottomley   [SCSI] convert SP...
729
  	       (*compare_fn)(struct scsi_device *, u8 *, u8 *, int))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  {
33aa687db   James Bottomley   [SCSI] convert SP...
731
  	struct spi_internal *i = to_spi_internal(sdev->host->transportt);
9a8bc9b84   James Bottomley   [SCSI] update spi...
732
  	struct scsi_target *starget = sdev->sdev_target;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
735
736
737
738
  	int period = 0, prevperiod = 0; 
  	enum spi_compare_returns retval;
  
  
  	for (;;) {
  		int newperiod;
33aa687db   James Bottomley   [SCSI] convert SP...
739
  		retval = compare_fn(sdev, buffer, ptr, DV_LOOPS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
743
744
745
  
  		if (retval == SPI_COMPARE_SUCCESS
  		    || retval == SPI_COMPARE_SKIP_TEST)
  			break;
  
  		/* OK, retrain, fallback */
9a8bc9b84   James Bottomley   [SCSI] update spi...
746
747
748
749
  		if (i->f->get_iu)
  			i->f->get_iu(starget);
  		if (i->f->get_qas)
  			i->f->get_qas(starget);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
  		if (i->f->get_period)
  			i->f->get_period(sdev->sdev_target);
9a8bc9b84   James Bottomley   [SCSI] update spi...
752
753
754
755
756
  
  		/* Here's the fallback sequence; first try turning off
  		 * IU, then QAS (if we can control them), then finally
  		 * fall down the periods */
  		if (i->f->set_iu && spi_iu(starget)) {
804ff603d   Masanari Iida   [SCSI] Fix printk...
757
758
  			starget_printk(KERN_ERR, starget, "Domain Validation Disabling Information Units
  ");
9a8bc9b84   James Bottomley   [SCSI] update spi...
759
760
  			DV_SET(iu, 0);
  		} else if (i->f->set_qas && spi_qas(starget)) {
804ff603d   Masanari Iida   [SCSI] Fix printk...
761
762
  			starget_printk(KERN_ERR, starget, "Domain Validation Disabling Quick Arbitration and Selection
  ");
9a8bc9b84   James Bottomley   [SCSI] update spi...
763
764
765
766
767
768
769
770
771
772
773
  			DV_SET(qas, 0);
  		} else {
  			newperiod = spi_period(starget);
  			period = newperiod > period ? newperiod : period;
  			if (period < 0x0d)
  				period++;
  			else
  				period += period >> 1;
  
  			if (unlikely(period > 0xff || period == prevperiod)) {
  				/* Total failure; set to async and return */
9ccfc756a   James Bottomley   [SCSI] move the m...
774
775
  				starget_printk(KERN_ERR, starget, "Domain Validation Failure, dropping back to Asynchronous
  ");
9a8bc9b84   James Bottomley   [SCSI] update spi...
776
777
778
  				DV_SET(offset, 0);
  				return SPI_COMPARE_FAILURE;
  			}
9ccfc756a   James Bottomley   [SCSI] move the m...
779
780
  			starget_printk(KERN_ERR, starget, "Domain Validation detected failure, dropping back
  ");
9a8bc9b84   James Bottomley   [SCSI] update spi...
781
782
  			DV_SET(period, period);
  			prevperiod = period;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
786
787
788
  	}
  	return retval;
  }
  
  static int
33aa687db   James Bottomley   [SCSI] convert SP...
789
  spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
  {
33aa687db   James Bottomley   [SCSI] convert SP...
791
  	int l, result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
796
797
  
  	/* first off do a test unit ready.  This can error out 
  	 * because of reservations or some other reason.  If it
  	 * fails, the device won't let us write to the echo buffer
  	 * so just return failure */
  	
c62f40bfb   Colin Ian King   scsi: scsi_transp...
798
  	static const char spi_test_unit_ready[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
  		TEST_UNIT_READY, 0, 0, 0, 0, 0
  	};
c62f40bfb   Colin Ian King   scsi: scsi_transp...
801
  	static const char spi_read_buffer_descriptor[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
804
805
  		READ_BUFFER, 0x0b, 0, 0, 0, 0, 0, 0, 4, 0
  	};
  
  	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
808
809
810
811
  	/* We send a set of three TURs to clear any outstanding 
  	 * unit attention conditions if they exist (Otherwise the
  	 * buffer tests won't be happy).  If the TUR still fails
  	 * (reservation conflict, device not ready, etc) just
  	 * skip the write tests */
  	for (l = 0; ; l++) {
33aa687db   James Bottomley   [SCSI] convert SP...
812
813
  		result = spi_execute(sdev, spi_test_unit_ready, DMA_NONE, 
  				     NULL, 0, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814

33aa687db   James Bottomley   [SCSI] convert SP...
815
  		if(result) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
819
820
821
822
  			if(l >= 3)
  				return 0;
  		} else {
  			/* TUR succeeded */
  			break;
  		}
  	}
33aa687db   James Bottomley   [SCSI] convert SP...
823
824
  	result = spi_execute(sdev, spi_read_buffer_descriptor, 
  			     DMA_FROM_DEVICE, buffer, 4, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825

33aa687db   James Bottomley   [SCSI] convert SP...
826
  	if (result)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
829
830
831
832
833
  		/* Device has no echo buffer */
  		return 0;
  
  	return buffer[3] + ((buffer[2] & 0x1f) << 8);
  }
  
  static void
33aa687db   James Bottomley   [SCSI] convert SP...
834
  spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
  {
33aa687db   James Bottomley   [SCSI] convert SP...
836
  	struct spi_internal *i = to_spi_internal(sdev->host->transportt);
62a861297   James Bottomley   [SCSI] implement ...
837
  	struct scsi_target *starget = sdev->sdev_target;
60eef2570   James Bottomley   [SCSI] spi transp...
838
  	struct Scsi_Host *shost = sdev->host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  	int len = sdev->inquiry_len;
2302827c9   James Bottomley   [SCSI] scsi_trans...
840
841
  	int min_period = spi_min_period(starget);
  	int max_width = spi_max_width(starget);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
843
844
  	/* first set us up for narrow async */
  	DV_SET(offset, 0);
  	DV_SET(width, 0);
2302827c9   James Bottomley   [SCSI] scsi_trans...
845

33aa687db   James Bottomley   [SCSI] convert SP...
846
  	if (spi_dv_device_compare_inquiry(sdev, buffer, buffer, DV_LOOPS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
  	    != SPI_COMPARE_SUCCESS) {
9ccfc756a   James Bottomley   [SCSI] move the m...
848
849
  		starget_printk(KERN_ERR, starget, "Domain Validation Initial Inquiry Failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
851
852
  		/* FIXME: should probably offline the device here? */
  		return;
  	}
9872b81cf   James Bottomley   scsi_transport_sp...
853
  	if (!spi_support_wide(starget)) {
2302827c9   James Bottomley   [SCSI] scsi_trans...
854
855
856
  		spi_max_width(starget) = 0;
  		max_width = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
  	/* test width */
2302827c9   James Bottomley   [SCSI] scsi_trans...
858
  	if (i->f->set_width && max_width) {
9a8bc9b84   James Bottomley   [SCSI] update spi...
859
  		i->f->set_width(starget, 1);
62a861297   James Bottomley   [SCSI] implement ...
860

33aa687db   James Bottomley   [SCSI] convert SP...
861
  		if (spi_dv_device_compare_inquiry(sdev, buffer,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
863
864
  						   buffer + len,
  						   DV_LOOPS)
  		    != SPI_COMPARE_SUCCESS) {
9ccfc756a   James Bottomley   [SCSI] move the m...
865
866
  			starget_printk(KERN_ERR, starget, "Wide Transfers Fail
  ");
9a8bc9b84   James Bottomley   [SCSI] update spi...
867
  			i->f->set_width(starget, 0);
2302827c9   James Bottomley   [SCSI] scsi_trans...
868
869
870
871
872
  			/* Make sure we don't force wide back on by asking
  			 * for a transfer period that requires it */
  			max_width = 0;
  			if (min_period < 10)
  				min_period = 10;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
874
875
876
877
878
879
  		}
  	}
  
  	if (!i->f->set_period)
  		return;
  
  	/* device can't handle synchronous */
9872b81cf   James Bottomley   scsi_transport_sp...
880
  	if (!spi_support_sync(starget) && !spi_support_dt(starget))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881
  		return;
349cd7cfe   James Bottomley   [SCSI] SPI DV: be...
882
883
884
885
  	/* len == -1 is the signal that we need to ascertain the
  	 * presence of an echo buffer before trying to use it.  len ==
  	 * 0 means we don't have an echo buffer */
  	len = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
887
888
889
  
   retry:
  
  	/* now set up to the maximum */
62a861297   James Bottomley   [SCSI] implement ...
890
  	DV_SET(offset, spi_max_offset(starget));
2302827c9   James Bottomley   [SCSI] scsi_trans...
891
  	DV_SET(period, min_period);
9a8bc9b84   James Bottomley   [SCSI] update spi...
892
893
  	/* try QAS requests; this should be harmless to set if the
  	 * target supports it */
9872b81cf   James Bottomley   scsi_transport_sp...
894
  	if (spi_support_qas(starget) && spi_max_qas(starget)) {
eb1dd68bc   James Bottomley   [SCSI] SPI transp...
895
  		DV_SET(qas, 1);
dfdc58ba3   James Bottomley   [SCSI] SPI transp...
896
897
898
  	} else {
  		DV_SET(qas, 0);
  	}
9872b81cf   James Bottomley   scsi_transport_sp...
899
900
  	if (spi_support_ius(starget) && spi_max_iu(starget) &&
  	    min_period < 9) {
dfdc58ba3   James Bottomley   [SCSI] SPI transp...
901
  		/* This u320 (or u640). Set IU transfers */
eb1dd68bc   James Bottomley   [SCSI] SPI transp...
902
  		DV_SET(iu, 1);
dfdc58ba3   James Bottomley   [SCSI] SPI transp...
903
  		/* Then set the optional parameters */
9a8bc9b84   James Bottomley   [SCSI] update spi...
904
905
906
  		DV_SET(rd_strm, 1);
  		DV_SET(wr_flow, 1);
  		DV_SET(rti, 1);
2302827c9   James Bottomley   [SCSI] scsi_trans...
907
  		if (min_period == 8)
9a8bc9b84   James Bottomley   [SCSI] update spi...
908
  			DV_SET(pcomp_en, 1);
dfdc58ba3   James Bottomley   [SCSI] SPI transp...
909
910
  	} else {
  		DV_SET(iu, 0);
9a8bc9b84   James Bottomley   [SCSI] update spi...
911
  	}
dfdc58ba3   James Bottomley   [SCSI] SPI transp...
912

60eef2570   James Bottomley   [SCSI] spi transp...
913
914
915
916
917
918
  	/* now that we've done all this, actually check the bus
  	 * signal type (if known).  Some devices are stupid on
  	 * a SE bus and still claim they can try LVD only settings */
  	if (i->f->get_signalling)
  		i->f->get_signalling(shost);
  	if (spi_signalling(shost) == SPI_SIGNAL_SE ||
dfdc58ba3   James Bottomley   [SCSI] SPI transp...
919
  	    spi_signalling(shost) == SPI_SIGNAL_HVD ||
9872b81cf   James Bottomley   scsi_transport_sp...
920
  	    !spi_support_dt(starget)) {
60eef2570   James Bottomley   [SCSI] spi transp...
921
  		DV_SET(dt, 0);
dfdc58ba3   James Bottomley   [SCSI] SPI transp...
922
923
924
  	} else {
  		DV_SET(dt, 1);
  	}
2302827c9   James Bottomley   [SCSI] scsi_trans...
925
926
927
  	/* set width last because it will pull all the other
  	 * parameters down to required values */
  	DV_SET(width, max_width);
349cd7cfe   James Bottomley   [SCSI] SPI DV: be...
928
929
930
931
932
933
934
935
936
937
938
939
940
941
  	/* Do the read only INQUIRY tests */
  	spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len,
  		       spi_dv_device_compare_inquiry);
  	/* See if we actually managed to negotiate and sustain DT */
  	if (i->f->get_dt)
  		i->f->get_dt(starget);
  
  	/* see if the device has an echo buffer.  If it does we can do
  	 * the SPI pattern write tests.  Because of some broken
  	 * devices, we *only* try this on a device that has actually
  	 * negotiated DT */
  
  	if (len == -1 && spi_dt(starget))
  		len = spi_dv_device_get_echo_buffer(sdev, buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942

349cd7cfe   James Bottomley   [SCSI] SPI DV: be...
943
  	if (len <= 0) {
9ccfc756a   James Bottomley   [SCSI] move the m...
944
945
  		starget_printk(KERN_INFO, starget, "Domain Validation skipping write tests
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
948
949
  		return;
  	}
  
  	if (len > SPI_MAX_ECHO_BUFFER_SIZE) {
9ccfc756a   James Bottomley   [SCSI] move the m...
950
951
  		starget_printk(KERN_WARNING, starget, "Echo buffer size %d is too big, trimming to %d
  ", len, SPI_MAX_ECHO_BUFFER_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
  		len = SPI_MAX_ECHO_BUFFER_SIZE;
  	}
33aa687db   James Bottomley   [SCSI] convert SP...
954
  	if (spi_dv_retrain(sdev, buffer, buffer + len,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
  			   spi_dv_device_echo_buffer)
  	    == SPI_COMPARE_SKIP_TEST) {
  		/* OK, the stupid drive can't do a write echo buffer
  		 * test after all, fall back to the read tests */
  		len = 0;
  		goto retry;
  	}
  }
  
  
  /**	spi_dv_device - Do Domain Validation on the device
   *	@sdev:		scsi device to validate
   *
   *	Performs the domain validation on the given device in the
   *	current execution thread.  Since DV operations may sleep,
   *	the current thread must have user context.  Also no SCSI
   *	related locks that would deadlock I/O issued by the DV may
   *	be held.
   */
  void
  spi_dv_device(struct scsi_device *sdev)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
978
979
  	struct scsi_target *starget = sdev->sdev_target;
  	u8 *buffer;
  	const int len = SPI_MAX_ECHO_BUFFER_SIZE*2;
203f8c250   Bart Van Assche   block, scsi: Fix ...
980
981
982
983
984
985
986
  	/*
  	 * Because this function and the power management code both call
  	 * scsi_device_quiesce(), it is not safe to perform domain validation
  	 * while suspend or resume is in progress. Hence the
  	 * lock/unlock_system_sleep() calls.
  	 */
  	lock_system_sleep();
89a342ca6   Mike Maslenkin   [SCSI] scsi_trans...
987
  	if (unlikely(spi_dv_in_progress(starget)))
203f8c250   Bart Van Assche   block, scsi: Fix ...
988
  		goto unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989

89a342ca6   Mike Maslenkin   [SCSI] scsi_trans...
990
  	if (unlikely(scsi_device_get(sdev)))
203f8c250   Bart Van Assche   block, scsi: Fix ...
991
  		goto unlock;
dfdc58ba3   James Bottomley   [SCSI] SPI transp...
992
  	spi_dv_in_progress(starget) = 1;
24669f75a   Jes Sorensen   [SCSI] SCSI core ...
993
  	buffer = kzalloc(len, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
995
996
  
  	if (unlikely(!buffer))
  		goto out_put;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
999
1000
1001
1002
1003
1004
  	/* We need to verify that the actual device will quiesce; the
  	 * later target quiesce is just a nice to have */
  	if (unlikely(scsi_device_quiesce(sdev)))
  		goto out_free;
  
  	scsi_target_quiesce(starget);
  
  	spi_dv_pending(starget) = 1;
d158d2616   Jes Sorensen   [SCSI] sem2mutex:...
1005
  	mutex_lock(&spi_dv_mutex(starget));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006

9ccfc756a   James Bottomley   [SCSI] move the m...
1007
1008
  	starget_printk(KERN_INFO, starget, "Beginning Domain Validation
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009

33aa687db   James Bottomley   [SCSI] convert SP...
1010
  	spi_dv_device_internal(sdev, buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011

9ccfc756a   James Bottomley   [SCSI] move the m...
1012
1013
  	starget_printk(KERN_INFO, starget, "Ending Domain Validation
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014

d158d2616   Jes Sorensen   [SCSI] sem2mutex:...
1015
  	mutex_unlock(&spi_dv_mutex(starget));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
1017
1018
1019
1020
1021
1022
1023
1024
  	spi_dv_pending(starget) = 0;
  
  	scsi_target_resume(starget);
  
  	spi_initial_dv(starget) = 1;
  
   out_free:
  	kfree(buffer);
   out_put:
dfdc58ba3   James Bottomley   [SCSI] SPI transp...
1025
  	spi_dv_in_progress(starget) = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026
  	scsi_device_put(sdev);
203f8c250   Bart Van Assche   block, scsi: Fix ...
1027
1028
  unlock:
  	unlock_system_sleep();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
1030
1031
1032
1033
1034
1035
1036
1037
  }
  EXPORT_SYMBOL(spi_dv_device);
  
  struct work_queue_wrapper {
  	struct work_struct	work;
  	struct scsi_device	*sdev;
  };
  
  static void
c4028958b   David Howells   WorkStruct: make ...
1038
  spi_dv_device_work_wrapper(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
  {
c4028958b   David Howells   WorkStruct: make ...
1040
1041
  	struct work_queue_wrapper *wqw =
  		container_of(work, struct work_queue_wrapper, work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
  	struct scsi_device *sdev = wqw->sdev;
  
  	kfree(wqw);
  	spi_dv_device(sdev);
  	spi_dv_pending(sdev->sdev_target) = 0;
  	scsi_device_put(sdev);
  }
  
  
  /**
   *	spi_schedule_dv_device - schedule domain validation to occur on the device
   *	@sdev:	The device to validate
   *
   *	Identical to spi_dv_device() above, except that the DV will be
   *	scheduled to occur in a workqueue later.  All memory allocations
   *	are atomic, so may be called from any context including those holding
   *	SCSI locks.
   */
  void
  spi_schedule_dv_device(struct scsi_device *sdev)
  {
  	struct work_queue_wrapper *wqw =
  		kmalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC);
  
  	if (unlikely(!wqw))
  		return;
  
  	if (unlikely(spi_dv_pending(sdev->sdev_target))) {
  		kfree(wqw);
  		return;
  	}
  	/* Set pending early (dv_device doesn't check it, only sets it) */
  	spi_dv_pending(sdev->sdev_target) = 1;
  	if (unlikely(scsi_device_get(sdev))) {
  		kfree(wqw);
  		spi_dv_pending(sdev->sdev_target) = 0;
  		return;
  	}
c4028958b   David Howells   WorkStruct: make ...
1080
  	INIT_WORK(&wqw->work, spi_dv_device_work_wrapper);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  	wqw->sdev = sdev;
  
  	schedule_work(&wqw->work);
  }
  EXPORT_SYMBOL(spi_schedule_dv_device);
  
  /**
   * spi_display_xfer_agreement - Print the current target transfer agreement
   * @starget: The target for which to display the agreement
   *
   * Each SPI port is required to maintain a transfer agreement for each
   * other port on the bus.  This function prints a one-line summary of
   * the current agreement; more detailed information is available in sysfs.
   */
  void spi_display_xfer_agreement(struct scsi_target *starget)
  {
  	struct spi_transport_attrs *tp;
  	tp = (struct spi_transport_attrs *)&starget->starget_data;
  
  	if (tp->offset > 0 && tp->period > 0) {
  		unsigned int picosec, kb100;
  		char *scsi = "FAST-?";
  		char tmp[8];
  
  		if (tp->period <= SPI_STATIC_PPR) {
  			picosec = ppr_to_ps[tp->period];
  			switch (tp->period) {
  				case  7: scsi = "FAST-320"; break;
  				case  8: scsi = "FAST-160"; break;
  				case  9: scsi = "FAST-80"; break;
  				case 10:
  				case 11: scsi = "FAST-40"; break;
  				case 12: scsi = "FAST-20"; break;
  			}
  		} else {
  			picosec = tp->period * 4000;
  			if (tp->period < 25)
  				scsi = "FAST-20";
  			else if (tp->period < 50)
  				scsi = "FAST-10";
  			else
  				scsi = "FAST-5";
  		}
  
  		kb100 = (10000000 + picosec / 2) / picosec;
  		if (tp->width)
  			kb100 *= 2;
  		sprint_frac(tmp, picosec, 1000);
  
  		dev_info(&starget->dev,
d872ebe45   James Bottomley   [SCSI] add missin...
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
  			 "%s %sSCSI %d.%d MB/s %s%s%s%s%s%s%s%s (%s ns, offset %d)
  ",
  			 scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10,
  			 tp->dt ? "DT" : "ST",
  			 tp->iu ? " IU" : "",
  			 tp->qas  ? " QAS" : "",
  			 tp->rd_strm ? " RDSTRM" : "",
  			 tp->rti ? " RTI" : "",
  			 tp->wr_flow ? " WRFLOW" : "",
  			 tp->pcomp_en ? " PCOMP" : "",
  			 tp->hold_mcs ? " HMCS" : "",
  			 tmp, tp->offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
  	} else {
493ff4ee7   Matthew Wilcox   [SCSI] Delete tra...
1144
1145
  		dev_info(&starget->dev, "%sasynchronous
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
1147
1148
1149
  				tp->width ? "wide " : "");
  	}
  }
  EXPORT_SYMBOL(spi_display_xfer_agreement);
6ea3c0b2d   Matthew Wilcox   [SCSI] Add spi_po...
1150
1151
1152
1153
1154
1155
1156
1157
  int spi_populate_width_msg(unsigned char *msg, int width)
  {
  	msg[0] = EXTENDED_MESSAGE;
  	msg[1] = 2;
  	msg[2] = EXTENDED_WDTR;
  	msg[3] = width;
  	return 4;
  }
38e14f895   James Bottomley   [SCSI] Add EXPORT...
1158
  EXPORT_SYMBOL_GPL(spi_populate_width_msg);
6ea3c0b2d   Matthew Wilcox   [SCSI] Add spi_po...
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
  
  int spi_populate_sync_msg(unsigned char *msg, int period, int offset)
  {
  	msg[0] = EXTENDED_MESSAGE;
  	msg[1] = 3;
  	msg[2] = EXTENDED_SDTR;
  	msg[3] = period;
  	msg[4] = offset;
  	return 5;
  }
38e14f895   James Bottomley   [SCSI] Add EXPORT...
1169
  EXPORT_SYMBOL_GPL(spi_populate_sync_msg);
6ea3c0b2d   Matthew Wilcox   [SCSI] Add spi_po...
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
  
  int spi_populate_ppr_msg(unsigned char *msg, int period, int offset,
  		int width, int options)
  {
  	msg[0] = EXTENDED_MESSAGE;
  	msg[1] = 6;
  	msg[2] = EXTENDED_PPR;
  	msg[3] = period;
  	msg[4] = 0;
  	msg[5] = offset;
  	msg[6] = width;
  	msg[7] = options;
  	return 8;
  }
38e14f895   James Bottomley   [SCSI] Add EXPORT...
1184
  EXPORT_SYMBOL_GPL(spi_populate_ppr_msg);
6ea3c0b2d   Matthew Wilcox   [SCSI] Add spi_po...
1185

506686333   Christoph Hellwig   scsi: remove abus...
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
  /**
   * spi_populate_tag_msg - place a tag message in a buffer
   * @msg:	pointer to the area to place the tag
   * @cmd:	pointer to the scsi command for the tag
   *
   * Notes:
   *	designed to create the correct type of tag message for the 
   *	particular request.  Returns the size of the tag message.
   *	May return 0 if TCQ is disabled for this device.
   **/
  int spi_populate_tag_msg(unsigned char *msg, struct scsi_cmnd *cmd)
  {
          if (cmd->flags & SCMD_TAGGED) {
68d81f400   Christoph Hellwig   scsi: remove MSG_...
1199
  		*msg++ = SIMPLE_QUEUE_TAG;
506686333   Christoph Hellwig   scsi: remove abus...
1200
1201
1202
1203
1204
1205
1206
          	*msg++ = cmd->request->tag;
          	return 2;
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(spi_populate_tag_msg);
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1207
1208
  #ifdef CONFIG_SCSI_CONSTANTS
  static const char * const one_byte_msgs[] = {
72df0ebf9   Matthew Wilcox   [SCSI] Missing na...
1209
  /* 0x00 */ "Task Complete", NULL /* Extended Message */, "Save Pointers",
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1210
  /* 0x03 */ "Restore Pointers", "Disconnect", "Initiator Error", 
72df0ebf9   Matthew Wilcox   [SCSI] Missing na...
1211
  /* 0x06 */ "Abort Task Set", "Message Reject", "Nop", "Message Parity Error",
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1212
  /* 0x0a */ "Linked Command Complete", "Linked Command Complete w/flag",
72df0ebf9   Matthew Wilcox   [SCSI] Missing na...
1213
1214
1215
1216
  /* 0x0c */ "Target Reset", "Abort Task", "Clear Task Set", 
  /* 0x0f */ "Initiate Recovery", "Release Recovery",
  /* 0x11 */ "Terminate Process", "Continue Task", "Target Transfer Disable",
  /* 0x14 */ NULL, NULL, "Clear ACA", "LUN Reset"
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1217
  };
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1218
1219
  
  static const char * const two_byte_msgs[] = {
479721538   Matthew Wilcox   [SCSI] Fix printi...
1220
  /* 0x20 */ "Simple Queue Tag", "Head of Queue Tag", "Ordered Queue Tag",
72df0ebf9   Matthew Wilcox   [SCSI] Missing na...
1221
  /* 0x23 */ "Ignore Wide Residue", "ACA"
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1222
  };
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1223
1224
1225
  
  static const char * const extended_msgs[] = {
  /* 0x00 */ "Modify Data Pointer", "Synchronous Data Transfer Request",
ef72582e7   Matthew Wilcox   [SCSI] Add PPR su...
1226
  /* 0x02 */ "SCSI-I Extended Identify", "Wide Data Transfer Request",
fc25307d0   Matthew Wilcox   [SCSI] Improve me...
1227
  /* 0x04 */ "Parallel Protocol Request", "Modify Bidirectional Data Pointer"
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1228
  };
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1229

bdd70f2ce   Adrian Bunk   [SCSI] scsi_trans...
1230
  static void print_nego(const unsigned char *msg, int per, int off, int width)
ef72582e7   Matthew Wilcox   [SCSI] Add PPR su...
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
  {
  	if (per) {
  		char buf[20];
  		period_to_str(buf, msg[per]);
  		printk("period = %s ns ", buf);
  	}
  
  	if (off)
  		printk("offset = %d ", msg[off]);
  	if (width)
  		printk("width = %d ", 8 << msg[width]);
  }
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1243

fc25307d0   Matthew Wilcox   [SCSI] Improve me...
1244
1245
1246
1247
1248
1249
  static void print_ptr(const unsigned char *msg, int msb, const char *desc)
  {
  	int ptr = (msg[msb] << 24) | (msg[msb+1] << 16) | (msg[msb+2] << 8) |
  			msg[msb+3];
  	printk("%s = %d ", desc, ptr);
  }
1abfd3701   Matthew Wilcox   [SCSI] Rename scs...
1250
  int spi_print_msg(const unsigned char *msg)
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1251
  {
72df0ebf9   Matthew Wilcox   [SCSI] Missing na...
1252
  	int len = 1, i;
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1253
  	if (msg[0] == EXTENDED_MESSAGE) {
fc25307d0   Matthew Wilcox   [SCSI] Improve me...
1254
1255
1256
  		len = 2 + msg[1];
  		if (len == 2)
  			len += 256;
b32aaffcd   Matthew Wilcox   [SCSI] Use ARRAY_...
1257
  		if (msg[2] < ARRAY_SIZE(extended_msgs))
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1258
1259
1260
1261
1262
1263
  			printk ("%s ", extended_msgs[msg[2]]); 
  		else 
  			printk ("Extended Message, reserved code (0x%02x) ",
  				(int) msg[2]);
  		switch (msg[2]) {
  		case EXTENDED_MODIFY_DATA_POINTER:
fc25307d0   Matthew Wilcox   [SCSI] Improve me...
1264
  			print_ptr(msg, 3, "pointer");
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1265
1266
  			break;
  		case EXTENDED_SDTR:
ef72582e7   Matthew Wilcox   [SCSI] Add PPR su...
1267
  			print_nego(msg, 3, 4, 0);
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1268
1269
  			break;
  		case EXTENDED_WDTR:
ef72582e7   Matthew Wilcox   [SCSI] Add PPR su...
1270
1271
1272
1273
  			print_nego(msg, 0, 0, 3);
  			break;
  		case EXTENDED_PPR:
  			print_nego(msg, 3, 5, 6);
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1274
  			break;
fc25307d0   Matthew Wilcox   [SCSI] Improve me...
1275
1276
1277
1278
  		case EXTENDED_MODIFY_BIDI_DATA_PTR:
  			print_ptr(msg, 3, "out");
  			print_ptr(msg, 7, "in");
  			break;
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
  		default:
  		for (i = 2; i < len; ++i) 
  			printk("%02x ", msg[i]);
  		}
  	/* Identify */
  	} else if (msg[0] & 0x80) {
  		printk("Identify disconnect %sallowed %s %d ",
  			(msg[0] & 0x40) ? "" : "not ",
  			(msg[0] & 0x20) ? "target routine" : "lun",
  			msg[0] & 0x7);
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1289
1290
  	/* Normal One byte */
  	} else if (msg[0] < 0x1f) {
72df0ebf9   Matthew Wilcox   [SCSI] Missing na...
1291
  		if (msg[0] < ARRAY_SIZE(one_byte_msgs) && one_byte_msgs[msg[0]])
e24d873d2   Matthew Wilcox   [SCSI] Make spi_p...
1292
  			printk("%s ", one_byte_msgs[msg[0]]);
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1293
1294
  		else
  			printk("reserved (%02x) ", msg[0]);
72df0ebf9   Matthew Wilcox   [SCSI] Missing na...
1295
1296
  	} else if (msg[0] == 0x55) {
  		printk("QAS Request ");
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1297
1298
  	/* Two byte */
  	} else if (msg[0] <= 0x2f) {
b32aaffcd   Matthew Wilcox   [SCSI] Use ARRAY_...
1299
  		if ((msg[0] - 0x20) < ARRAY_SIZE(two_byte_msgs))
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1300
1301
1302
1303
1304
1305
1306
  			printk("%s %02x ", two_byte_msgs[msg[0] - 0x20], 
  				msg[1]);
  		else 
  			printk("reserved two byte (%02x %02x) ", 
  				msg[0], msg[1]);
  		len = 2;
  	} else 
e24d873d2   Matthew Wilcox   [SCSI] Make spi_p...
1307
  		printk("reserved ");
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1308
1309
  	return len;
  }
1abfd3701   Matthew Wilcox   [SCSI] Rename scs...
1310
  EXPORT_SYMBOL(spi_print_msg);
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1311
1312
  
  #else  /* ifndef CONFIG_SCSI_CONSTANTS */
1abfd3701   Matthew Wilcox   [SCSI] Rename scs...
1313
  int spi_print_msg(const unsigned char *msg)
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1314
  {
72df0ebf9   Matthew Wilcox   [SCSI] Missing na...
1315
  	int len = 1, i;
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1316
1317
  
  	if (msg[0] == EXTENDED_MESSAGE) {
fc25307d0   Matthew Wilcox   [SCSI] Improve me...
1318
1319
1320
  		len = 2 + msg[1];
  		if (len == 2)
  			len += 256;
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1321
1322
1323
1324
1325
  		for (i = 0; i < len; ++i)
  			printk("%02x ", msg[i]);
  	/* Identify */
  	} else if (msg[0] & 0x80) {
  		printk("%02x ", msg[0]);
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1326
  	/* Normal One byte */
597705aa7   James Bottomley   [SCSI] fix minor ...
1327
  	} else if ((msg[0] < 0x1f) || (msg[0] == 0x55)) {
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1328
  		printk("%02x ", msg[0]);
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1329
1330
1331
1332
1333
1334
1335
1336
  	/* Two byte */
  	} else if (msg[0] <= 0x2f) {
  		printk("%02x %02x", msg[0], msg[1]);
  		len = 2;
  	} else 
  		printk("%02x ", msg[0]);
  	return len;
  }
1abfd3701   Matthew Wilcox   [SCSI] Rename scs...
1337
  EXPORT_SYMBOL(spi_print_msg);
410ca5c7c   Matthew Wilcox   [SCSI] Move scsi_...
1338
  #endif /* ! CONFIG_SCSI_CONSTANTS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
1340
1341
1342
1343
  static int spi_device_match(struct attribute_container *cont,
  			    struct device *dev)
  {
  	struct scsi_device *sdev;
  	struct Scsi_Host *shost;
10c1b8898   James Bottomley   [SCSI] add abilit...
1344
  	struct spi_internal *i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
  
  	if (!scsi_is_sdev_device(dev))
  		return 0;
  
  	sdev = to_scsi_device(dev);
  	shost = sdev->host;
  	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
  	    != &spi_host_class.class)
  		return 0;
  	/* Note: this class has no device attributes, so it has
  	 * no per-HBA allocation and thus we don't need to distinguish
  	 * the attribute containers for the device */
10c1b8898   James Bottomley   [SCSI] add abilit...
1357
1358
1359
  	i = to_spi_internal(shost->transportt);
  	if (i->f->deny_binding && i->f->deny_binding(sdev->sdev_target))
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360
1361
1362
1363
1364
1365
1366
  	return 1;
  }
  
  static int spi_target_match(struct attribute_container *cont,
  			    struct device *dev)
  {
  	struct Scsi_Host *shost;
10c1b8898   James Bottomley   [SCSI] add abilit...
1367
  	struct scsi_target *starget;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
  	struct spi_internal *i;
  
  	if (!scsi_is_target_device(dev))
  		return 0;
  
  	shost = dev_to_shost(dev->parent);
  	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
  	    != &spi_host_class.class)
  		return 0;
  
  	i = to_spi_internal(shost->transportt);
10c1b8898   James Bottomley   [SCSI] add abilit...
1379
1380
1381
1382
  	starget = to_scsi_target(dev);
  
  	if (i->f->deny_binding && i->f->deny_binding(starget))
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
1384
1385
1386
1387
1388
1389
  	return &i->t.target_attrs.ac == cont;
  }
  
  static DECLARE_TRANSPORT_CLASS(spi_transport_class,
  			       "spi_transport",
  			       spi_setup_transport_attrs,
  			       NULL,
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1390
  			       spi_target_configure);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1391
1392
1393
1394
  
  static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class,
  				    spi_device_match,
  				    spi_device_configure);
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1395
  static struct attribute *host_attributes[] = {
ee959b00c   Tony Jones   SCSI: convert str...
1396
  	&dev_attr_signalling.attr,
0ac2377b6   Hannes Reinecke   [SCSI] scsi_trans...
1397
1398
  	&dev_attr_host_width.attr,
  	&dev_attr_hba_id.attr,
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1399
1400
1401
1402
1403
1404
1405
1406
1407
  	NULL
  };
  
  static struct attribute_group host_attribute_group = {
  	.attrs = host_attributes,
  };
  
  static int spi_host_configure(struct transport_container *tc,
  			      struct device *dev,
ee959b00c   Tony Jones   SCSI: convert str...
1408
  			      struct device *cdev)
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1409
1410
1411
1412
  {
  	struct kobject *kobj = &cdev->kobj;
  	struct Scsi_Host *shost = transport_class_to_shost(cdev);
  	struct spi_internal *si = to_spi_internal(shost->transportt);
ee959b00c   Tony Jones   SCSI: convert str...
1413
  	struct attribute *attr = &dev_attr_signalling.attr;
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
  	int rc = 0;
  
  	if (si->f->set_signalling)
  		rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR);
  
  	return rc;
  }
  
  /* returns true if we should be showing the variable.  Also
   * overloads the return by setting 1<<1 if the attribute should
   * be writeable */
  #define TARGET_ATTRIBUTE_HELPER(name) \
352f6bb42   James Bottomley   [SCSI] scsi_trans...
1426
1427
  	(si->f->show_##name ? S_IRUGO : 0) | \
  	(si->f->set_##name ? S_IWUSR : 0)
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1428

587a1f165   Al Viro   switch ->is_visib...
1429
  static umode_t target_attribute_is_visible(struct kobject *kobj,
352f6bb42   James Bottomley   [SCSI] scsi_trans...
1430
  					  struct attribute *attr, int i)
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1431
  {
ee959b00c   Tony Jones   SCSI: convert str...
1432
  	struct device *cdev = container_of(kobj, struct device, kobj);
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1433
1434
1435
  	struct scsi_target *starget = transport_class_to_starget(cdev);
  	struct Scsi_Host *shost = transport_class_to_shost(cdev);
  	struct spi_internal *si = to_spi_internal(shost->transportt);
ee959b00c   Tony Jones   SCSI: convert str...
1436
  	if (attr == &dev_attr_period.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1437
1438
  	    spi_support_sync(starget))
  		return TARGET_ATTRIBUTE_HELPER(period);
ee959b00c   Tony Jones   SCSI: convert str...
1439
  	else if (attr == &dev_attr_min_period.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1440
1441
  		 spi_support_sync(starget))
  		return TARGET_ATTRIBUTE_HELPER(period);
ee959b00c   Tony Jones   SCSI: convert str...
1442
  	else if (attr == &dev_attr_offset.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1443
1444
  		 spi_support_sync(starget))
  		return TARGET_ATTRIBUTE_HELPER(offset);
ee959b00c   Tony Jones   SCSI: convert str...
1445
  	else if (attr == &dev_attr_max_offset.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1446
1447
  		 spi_support_sync(starget))
  		return TARGET_ATTRIBUTE_HELPER(offset);
ee959b00c   Tony Jones   SCSI: convert str...
1448
  	else if (attr == &dev_attr_width.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1449
1450
  		 spi_support_wide(starget))
  		return TARGET_ATTRIBUTE_HELPER(width);
ee959b00c   Tony Jones   SCSI: convert str...
1451
  	else if (attr == &dev_attr_max_width.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1452
1453
  		 spi_support_wide(starget))
  		return TARGET_ATTRIBUTE_HELPER(width);
ee959b00c   Tony Jones   SCSI: convert str...
1454
  	else if (attr == &dev_attr_iu.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1455
1456
  		 spi_support_ius(starget))
  		return TARGET_ATTRIBUTE_HELPER(iu);
ea4431906   James Bottomley   [SCSI] aic79xx: m...
1457
1458
1459
  	else if (attr == &dev_attr_max_iu.attr &&
  		 spi_support_ius(starget))
  		return TARGET_ATTRIBUTE_HELPER(iu);
ee959b00c   Tony Jones   SCSI: convert str...
1460
  	else if (attr == &dev_attr_dt.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1461
1462
  		 spi_support_dt(starget))
  		return TARGET_ATTRIBUTE_HELPER(dt);
ee959b00c   Tony Jones   SCSI: convert str...
1463
  	else if (attr == &dev_attr_qas.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1464
1465
  		 spi_support_qas(starget))
  		return TARGET_ATTRIBUTE_HELPER(qas);
ea4431906   James Bottomley   [SCSI] aic79xx: m...
1466
1467
1468
  	else if (attr == &dev_attr_max_qas.attr &&
  		 spi_support_qas(starget))
  		return TARGET_ATTRIBUTE_HELPER(qas);
ee959b00c   Tony Jones   SCSI: convert str...
1469
  	else if (attr == &dev_attr_wr_flow.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1470
1471
  		 spi_support_ius(starget))
  		return TARGET_ATTRIBUTE_HELPER(wr_flow);
ee959b00c   Tony Jones   SCSI: convert str...
1472
  	else if (attr == &dev_attr_rd_strm.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1473
1474
  		 spi_support_ius(starget))
  		return TARGET_ATTRIBUTE_HELPER(rd_strm);
ee959b00c   Tony Jones   SCSI: convert str...
1475
  	else if (attr == &dev_attr_rti.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1476
1477
  		 spi_support_ius(starget))
  		return TARGET_ATTRIBUTE_HELPER(rti);
ee959b00c   Tony Jones   SCSI: convert str...
1478
  	else if (attr == &dev_attr_pcomp_en.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1479
1480
  		 spi_support_ius(starget))
  		return TARGET_ATTRIBUTE_HELPER(pcomp_en);
ee959b00c   Tony Jones   SCSI: convert str...
1481
  	else if (attr == &dev_attr_hold_mcs.attr &&
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1482
1483
  		 spi_support_ius(starget))
  		return TARGET_ATTRIBUTE_HELPER(hold_mcs);
ee959b00c   Tony Jones   SCSI: convert str...
1484
  	else if (attr == &dev_attr_revalidate.attr)
352f6bb42   James Bottomley   [SCSI] scsi_trans...
1485
  		return S_IWUSR;
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1486
1487
1488
1489
1490
  
  	return 0;
  }
  
  static struct attribute *target_attributes[] = {
ee959b00c   Tony Jones   SCSI: convert str...
1491
1492
1493
1494
1495
1496
1497
  	&dev_attr_period.attr,
  	&dev_attr_min_period.attr,
  	&dev_attr_offset.attr,
  	&dev_attr_max_offset.attr,
  	&dev_attr_width.attr,
  	&dev_attr_max_width.attr,
  	&dev_attr_iu.attr,
ea4431906   James Bottomley   [SCSI] aic79xx: m...
1498
  	&dev_attr_max_iu.attr,
ee959b00c   Tony Jones   SCSI: convert str...
1499
1500
  	&dev_attr_dt.attr,
  	&dev_attr_qas.attr,
ea4431906   James Bottomley   [SCSI] aic79xx: m...
1501
  	&dev_attr_max_qas.attr,
ee959b00c   Tony Jones   SCSI: convert str...
1502
1503
1504
1505
1506
1507
  	&dev_attr_wr_flow.attr,
  	&dev_attr_rd_strm.attr,
  	&dev_attr_rti.attr,
  	&dev_attr_pcomp_en.attr,
  	&dev_attr_hold_mcs.attr,
  	&dev_attr_revalidate.attr,
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
  	NULL
  };
  
  static struct attribute_group target_attribute_group = {
  	.attrs = target_attributes,
  	.is_visible = target_attribute_is_visible,
  };
  
  static int spi_target_configure(struct transport_container *tc,
  				struct device *dev,
ee959b00c   Tony Jones   SCSI: convert str...
1518
  				struct device *cdev)
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1519
1520
  {
  	struct kobject *kobj = &cdev->kobj;
352f6bb42   James Bottomley   [SCSI] scsi_trans...
1521
1522
1523
  
  	/* force an update based on parameters read from the device */
  	sysfs_update_group(kobj, &target_attribute_group);
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1524
1525
1526
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1527
1528
1529
  struct scsi_transport_template *
  spi_attach_transport(struct spi_function_template *ft)
  {
24669f75a   Jes Sorensen   [SCSI] SCSI core ...
1530
1531
  	struct spi_internal *i = kzalloc(sizeof(struct spi_internal),
  					 GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1532
1533
  	if (unlikely(!i))
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1534
  	i->t.target_attrs.ac.class = &spi_transport_class.class;
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1535
  	i->t.target_attrs.ac.grp = &target_attribute_group;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1536
1537
1538
1539
  	i->t.target_attrs.ac.match = spi_target_match;
  	transport_container_register(&i->t.target_attrs);
  	i->t.target_size = sizeof(struct spi_transport_attrs);
  	i->t.host_attrs.ac.class = &spi_host_class.class;
9b161a4d3   James Bottomley   [SCSI] scsi_trans...
1540
  	i->t.host_attrs.ac.grp = &host_attribute_group;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1541
1542
1543
1544
  	i->t.host_attrs.ac.match = spi_host_match;
  	transport_container_register(&i->t.host_attrs);
  	i->t.host_size = sizeof(struct spi_host_attrs);
  	i->f = ft;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
  	return &i->t;
  }
  EXPORT_SYMBOL(spi_attach_transport);
  
  void spi_release_transport(struct scsi_transport_template *t)
  {
  	struct spi_internal *i = to_spi_internal(t);
  
  	transport_container_unregister(&i->t.target_attrs);
  	transport_container_unregister(&i->t.host_attrs);
  
  	kfree(i);
  }
  EXPORT_SYMBOL(spi_release_transport);
  
  static __init int spi_transport_init(void)
  {
a9e0edb68   James Bottomley   scsi_transport_sp...
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
  	int error = scsi_dev_info_add_list(SCSI_DEVINFO_SPI,
  					   "SCSI Parallel Transport Class");
  	if (!error) {
  		int i;
  
  		for (i = 0; spi_static_device_list[i].vendor; i++)
  			scsi_dev_info_list_add_keyed(1,	/* compatible */
  						     spi_static_device_list[i].vendor,
  						     spi_static_device_list[i].model,
  						     NULL,
  						     spi_static_device_list[i].flags,
  						     SCSI_DEVINFO_SPI);
  	}
  
  	error = transport_class_register(&spi_transport_class);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
  	if (error)
  		return error;
  	error = anon_transport_class_register(&spi_device_class);
  	return transport_class_register(&spi_host_class);
  }
  
  static void __exit spi_transport_exit(void)
  {
  	transport_class_unregister(&spi_transport_class);
  	anon_transport_class_unregister(&spi_device_class);
  	transport_class_unregister(&spi_host_class);
a9e0edb68   James Bottomley   scsi_transport_sp...
1588
  	scsi_dev_info_remove_list(SCSI_DEVINFO_SPI);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1589
1590
1591
1592
1593
1594
1595
1596
  }
  
  MODULE_AUTHOR("Martin Hicks");
  MODULE_DESCRIPTION("SPI Transport Attributes");
  MODULE_LICENSE("GPL");
  
  module_init(spi_transport_init);
  module_exit(spi_transport_exit);