aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2008-07-17 19:53:03 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-07-26 15:14:51 -0400
commitb6ff1b14cdf4b4cb5403f3af2c3272f7e609a241 (patch)
treed3a8231c0c4f6c647a8546dcea4659c19ea33949 /drivers/scsi
parent4c05ae52fcb0e27a2ee4a16d1f31f8c547fd4886 (diff)
[SCSI] scsi_dh: Update EMC handler
This patch converts the EMC device handler to use a proper state machine. We now also parse the extended INQUIRY information to determine if long trespass commands are supported. And we're now using the long trespass command correctly. And finally there's now an check at init time to refuse to attach to devices not supporting EMC-specific VPD pages. Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c547
1 files changed, 372 insertions, 175 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index bf0a389c52d8..aa46b131b20e 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -25,28 +25,31 @@
25#include <scsi/scsi_dh.h> 25#include <scsi/scsi_dh.h>
26#include <scsi/scsi_device.h> 26#include <scsi/scsi_device.h>
27 27
28#define CLARIION_NAME "emc_clariion" 28#define CLARIION_NAME "emc"
29 29
30#define CLARIION_TRESPASS_PAGE 0x22 30#define CLARIION_TRESPASS_PAGE 0x22
31#define CLARIION_BUFFER_SIZE 0x80 31#define CLARIION_BUFFER_SIZE 0xFC
32#define CLARIION_TIMEOUT (60 * HZ) 32#define CLARIION_TIMEOUT (60 * HZ)
33#define CLARIION_RETRIES 3 33#define CLARIION_RETRIES 3
34#define CLARIION_UNBOUND_LU -1 34#define CLARIION_UNBOUND_LU -1
35#define CLARIION_SP_A 0
36#define CLARIION_SP_B 1
35 37
36static unsigned char long_trespass[] = { 38/* Flags */
37 0, 0, 0, 0, 39#define CLARIION_SHORT_TRESPASS 1
38 CLARIION_TRESPASS_PAGE, /* Page code */ 40#define CLARIION_HONOR_RESERVATIONS 2
39 0x09, /* Page length - 2 */
40 0x81, /* Trespass code + Honor reservation bit */
41 0xff, 0xff, /* Trespass target */
42 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */
43};
44 41
45static unsigned char long_trespass_hr[] = { 42/* LUN states */
46 0, 0, 0, 0, 43#define CLARIION_LUN_UNINITIALIZED -1
44#define CLARIION_LUN_UNBOUND 0
45#define CLARIION_LUN_BOUND 1
46#define CLARIION_LUN_OWNED 2
47
48static unsigned char long_trespass[] = {
49 0, 0, 0, 0, 0, 0, 0, 0,
47 CLARIION_TRESPASS_PAGE, /* Page code */ 50 CLARIION_TRESPASS_PAGE, /* Page code */
48 0x09, /* Page length - 2 */ 51 0x09, /* Page length - 2 */
49 0x01, /* Trespass code + Honor reservation bit */ 52 0x01, /* Trespass code */
50 0xff, 0xff, /* Trespass target */ 53 0xff, 0xff, /* Trespass target */
51 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ 54 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */
52}; 55};
@@ -55,39 +58,56 @@ static unsigned char short_trespass[] = {
55 0, 0, 0, 0, 58 0, 0, 0, 0,
56 CLARIION_TRESPASS_PAGE, /* Page code */ 59 CLARIION_TRESPASS_PAGE, /* Page code */
57 0x02, /* Page length - 2 */ 60 0x02, /* Page length - 2 */
58 0x81, /* Trespass code + Honor reservation bit */ 61 0x01, /* Trespass code */
59 0xff, /* Trespass target */ 62 0xff, /* Trespass target */
60}; 63};
61 64
62static unsigned char short_trespass_hr[] = { 65static const char * lun_state[] =
63 0, 0, 0, 0, 66{
64 CLARIION_TRESPASS_PAGE, /* Page code */ 67 "not bound",
65 0x02, /* Page length - 2 */ 68 "bound",
66 0x01, /* Trespass code + Honor reservation bit */ 69 "owned",
67 0xff, /* Trespass target */
68}; 70};
69 71
70struct clariion_dh_data { 72struct clariion_dh_data {
71 /* 73 /*
74 * Flags:
75 * CLARIION_SHORT_TRESPASS
72 * Use short trespass command (FC-series) or the long version 76 * Use short trespass command (FC-series) or the long version
73 * (default for AX/CX CLARiiON arrays). 77 * (default for AX/CX CLARiiON arrays).
74 */ 78 *
75 unsigned short_trespass; 79 * CLARIION_HONOR_RESERVATIONS
76 /*
77 * Whether or not (default) to honor SCSI reservations when 80 * Whether or not (default) to honor SCSI reservations when
78 * initiating a switch-over. 81 * initiating a switch-over.
79 */ 82 */
80 unsigned hr; 83 unsigned flags;
81 /* I/O buffer for both MODE_SELECT and INQUIRY commands. */ 84 /*
85 * I/O buffer for both MODE_SELECT and INQUIRY commands.
86 */
82 char buffer[CLARIION_BUFFER_SIZE]; 87 char buffer[CLARIION_BUFFER_SIZE];
83 /* 88 /*
84 * SCSI sense buffer for commands -- assumes serial issuance 89 * SCSI sense buffer for commands -- assumes serial issuance
85 * and completion sequence of all commands for same multipath. 90 * and completion sequence of all commands for same multipath.
86 */ 91 */
87 unsigned char sense[SCSI_SENSE_BUFFERSIZE]; 92 unsigned char sense[SCSI_SENSE_BUFFERSIZE];
88 /* which SP (A=0,B=1,UNBOUND=-1) is dflt SP for path's mapped dev */ 93 unsigned int senselen;
94 /*
95 * LUN state
96 */
97 int lun_state;
98 /*
99 * SP Port number
100 */
101 int port;
102 /*
103 * which SP (A=0,B=1,UNBOUND=-1) is the default SP for this
104 * path's mapped LUN
105 */
89 int default_sp; 106 int default_sp;
90 /* which SP (A=0,B=1,UNBOUND=-1) is active for path's mapped dev */ 107 /*
108 * which SP (A=0,B=1,UNBOUND=-1) is the active SP for this
109 * path's mapped LUN
110 */
91 int current_sp; 111 int current_sp;
92}; 112};
93 113
@@ -102,19 +122,16 @@ static inline struct clariion_dh_data
102/* 122/*
103 * Parse MODE_SELECT cmd reply. 123 * Parse MODE_SELECT cmd reply.
104 */ 124 */
105static int trespass_endio(struct scsi_device *sdev, int result) 125static int trespass_endio(struct scsi_device *sdev, char *sense)
106{ 126{
107 int err = SCSI_DH_OK; 127 int err = SCSI_DH_IO;
108 struct scsi_sense_hdr sshdr; 128 struct scsi_sense_hdr sshdr;
109 struct clariion_dh_data *csdev = get_clariion_data(sdev);
110 char *sense = csdev->sense;
111 129
112 if (status_byte(result) == CHECK_CONDITION && 130 if (!scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) {
113 scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { 131 sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, "
114 sdev_printk(KERN_ERR, sdev, "Found valid sense data 0x%2x, "
115 "0x%2x, 0x%2x while sending CLARiiON trespass " 132 "0x%2x, 0x%2x while sending CLARiiON trespass "
116 "command.\n", sshdr.sense_key, sshdr.asc, 133 "command.\n", CLARIION_NAME, sshdr.sense_key,
117 sshdr.ascq); 134 sshdr.asc, sshdr.ascq);
118 135
119 if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) && 136 if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) &&
120 (sshdr.ascq == 0x00)) { 137 (sshdr.ascq == 0x00)) {
@@ -122,9 +139,9 @@ static int trespass_endio(struct scsi_device *sdev, int result)
122 * Array based copy in progress -- do not send 139 * Array based copy in progress -- do not send
123 * mode_select or copy will be aborted mid-stream. 140 * mode_select or copy will be aborted mid-stream.
124 */ 141 */
125 sdev_printk(KERN_INFO, sdev, "Array Based Copy in " 142 sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in "
126 "progress while sending CLARiiON trespass " 143 "progress while sending CLARiiON trespass "
127 "command.\n"); 144 "command.\n", CLARIION_NAME);
128 err = SCSI_DH_DEV_TEMP_BUSY; 145 err = SCSI_DH_DEV_TEMP_BUSY;
129 } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) && 146 } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) &&
130 (sshdr.ascq == 0x03)) { 147 (sshdr.ascq == 0x03)) {
@@ -132,109 +149,113 @@ static int trespass_endio(struct scsi_device *sdev, int result)
132 * LUN Not Ready - Manual Intervention Required 149 * LUN Not Ready - Manual Intervention Required
133 * indicates in-progress ucode upgrade (NDU). 150 * indicates in-progress ucode upgrade (NDU).
134 */ 151 */
135 sdev_printk(KERN_INFO, sdev, "Detected in-progress " 152 sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress "
136 "ucode upgrade NDU operation while sending " 153 "ucode upgrade NDU operation while sending "
137 "CLARiiON trespass command.\n"); 154 "CLARiiON trespass command.\n", CLARIION_NAME);
138 err = SCSI_DH_DEV_TEMP_BUSY; 155 err = SCSI_DH_DEV_TEMP_BUSY;
139 } else 156 } else
140 err = SCSI_DH_DEV_FAILED; 157 err = SCSI_DH_DEV_FAILED;
141 } else if (result) { 158 } else {
142 sdev_printk(KERN_ERR, sdev, "Error 0x%x while sending " 159 sdev_printk(KERN_INFO, sdev,
143 "CLARiiON trespass command.\n", result); 160 "%s: failed to send MODE SELECT, no sense available\n",
144 err = SCSI_DH_IO; 161 CLARIION_NAME);
145 } 162 }
146
147 return err; 163 return err;
148} 164}
149 165
150static int parse_sp_info_reply(struct scsi_device *sdev, int result, 166static int parse_sp_info_reply(struct scsi_device *sdev,
151 int *default_sp, int *current_sp, int *new_current_sp) 167 struct clariion_dh_data *csdev)
152{ 168{
153 int err = SCSI_DH_OK; 169 int err = SCSI_DH_OK;
154 struct clariion_dh_data *csdev = get_clariion_data(sdev);
155
156 if (result == 0) {
157 /* check for in-progress ucode upgrade (NDU) */
158 if (csdev->buffer[48] != 0) {
159 sdev_printk(KERN_NOTICE, sdev, "Detected in-progress "
160 "ucode upgrade NDU operation while finding "
161 "current active SP.");
162 err = SCSI_DH_DEV_TEMP_BUSY;
163 } else {
164 *default_sp = csdev->buffer[5];
165
166 if (csdev->buffer[4] == 2)
167 /* SP for path is current */
168 *current_sp = csdev->buffer[8];
169 else {
170 if (csdev->buffer[4] == 1)
171 /* SP for this path is NOT current */
172 if (csdev->buffer[8] == 0)
173 *current_sp = 1;
174 else
175 *current_sp = 0;
176 else
177 /* unbound LU or LUNZ */
178 *current_sp = CLARIION_UNBOUND_LU;
179 }
180 *new_current_sp = csdev->buffer[8];
181 }
182 } else {
183 struct scsi_sense_hdr sshdr;
184 170
185 err = SCSI_DH_IO; 171 /* check for in-progress ucode upgrade (NDU) */
186 172 if (csdev->buffer[48] != 0) {
187 if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, 173 sdev_printk(KERN_NOTICE, sdev, "%s: Detected in-progress "
188 &sshdr)) 174 "ucode upgrade NDU operation while finding "
189 sdev_printk(KERN_ERR, sdev, "Found valid sense data " 175 "current active SP.", CLARIION_NAME);
190 "0x%2x, 0x%2x, 0x%2x while finding current " 176 err = SCSI_DH_DEV_TEMP_BUSY;
191 "active SP.", sshdr.sense_key, sshdr.asc, 177 goto out;
192 sshdr.ascq); 178 }
193 else 179 if (csdev->buffer[4] < 0 || csdev->buffer[4] > 2) {
194 sdev_printk(KERN_ERR, sdev, "Error 0x%x finding " 180 /* Invalid buffer format */
195 "current active SP.", result); 181 sdev_printk(KERN_NOTICE, sdev,
182 "%s: invalid VPD page 0xC0 format\n",
183 CLARIION_NAME);
184 err = SCSI_DH_NOSYS;
185 goto out;
186 }
187 switch (csdev->buffer[28] & 0x0f) {
188 case 6:
189 sdev_printk(KERN_NOTICE, sdev,
190 "%s: ALUA failover mode detected\n",
191 CLARIION_NAME);
192 break;
193 case 4:
194 /* Linux failover */
195 break;
196 default:
197 sdev_printk(KERN_WARNING, sdev,
198 "%s: Invalid failover mode %d\n",
199 CLARIION_NAME, csdev->buffer[28] & 0x0f);
200 err = SCSI_DH_NOSYS;
201 goto out;
196 } 202 }
197 203
204 csdev->default_sp = csdev->buffer[5];
205 csdev->lun_state = csdev->buffer[4];
206 csdev->current_sp = csdev->buffer[8];
207 csdev->port = csdev->buffer[7];
208
209out:
198 return err; 210 return err;
199} 211}
200 212
201static int sp_info_endio(struct scsi_device *sdev, int result, 213#define emc_default_str "FC (Legacy)"
202 int mode_select_sent, int *done) 214
215static char * parse_sp_model(struct scsi_device *sdev, unsigned char *buffer)
203{ 216{
204 struct clariion_dh_data *csdev = get_clariion_data(sdev); 217 unsigned char len = buffer[4] + 5;
205 int err_flags, default_sp, current_sp, new_current_sp; 218 char *sp_model = NULL;
219 unsigned char sp_len, serial_len;
220
221 if (len < 160) {
222 sdev_printk(KERN_WARNING, sdev,
223 "%s: Invalid information section length %d\n",
224 CLARIION_NAME, len);
225 /* Check for old FC arrays */
226 if (!strncmp(buffer + 8, "DGC", 3)) {
227 /* Old FC array, not supporting extended information */
228 sp_model = emc_default_str;
229 }
230 goto out;
231 }
206 232
207 err_flags = parse_sp_info_reply(sdev, result, &default_sp, 233 /*
208 &current_sp, &new_current_sp); 234 * Parse extended information for SP model number
235 */
236 serial_len = buffer[160];
237 if (serial_len == 0 || serial_len + 161 > len) {
238 sdev_printk(KERN_WARNING, sdev,
239 "%s: Invalid array serial number length %d\n",
240 CLARIION_NAME, serial_len);
241 goto out;
242 }
243 sp_len = buffer[99];
244 if (sp_len == 0 || serial_len + sp_len + 161 > len) {
245 sdev_printk(KERN_WARNING, sdev,
246 "%s: Invalid model number length %d\n",
247 CLARIION_NAME, sp_len);
248 goto out;
249 }
250 sp_model = &buffer[serial_len + 161];
251 /* Strip whitespace at the end */
252 while (sp_len > 1 && sp_model[sp_len - 1] == ' ')
253 sp_len--;
209 254
210 if (err_flags != SCSI_DH_OK) 255 sp_model[sp_len] = '\0';
211 goto done;
212 256
213 if (mode_select_sent) { 257out:
214 csdev->default_sp = default_sp; 258 return sp_model;
215 csdev->current_sp = current_sp;
216 } else {
217 /*
218 * Issue the actual module_selec request IFF either
219 * (1) we do not know the identity of the current SP OR
220 * (2) what we think we know is actually correct.
221 */
222 if ((current_sp != CLARIION_UNBOUND_LU) &&
223 (new_current_sp != current_sp)) {
224
225 csdev->default_sp = default_sp;
226 csdev->current_sp = current_sp;
227
228 sdev_printk(KERN_INFO, sdev, "Ignoring path group "
229 "switch-over command for CLARiiON SP%s since "
230 " mapped device is already initialized.",
231 current_sp ? "B" : "A");
232 if (done)
233 *done = 1; /* as good as doing it */
234 }
235 }
236done:
237 return err_flags;
238} 259}
239 260
240/* 261/*
@@ -244,48 +265,37 @@ done:
244 * Uses data and sense buffers in hardware handler context structure and 265 * Uses data and sense buffers in hardware handler context structure and
245 * assumes serial servicing of commands, both issuance and completion. 266 * assumes serial servicing of commands, both issuance and completion.
246 */ 267 */
247static struct request *get_req(struct scsi_device *sdev, int cmd) 268static struct request *get_req(struct scsi_device *sdev, int cmd,
269 unsigned char *buffer)
248{ 270{
249 struct clariion_dh_data *csdev = get_clariion_data(sdev);
250 struct request *rq; 271 struct request *rq;
251 unsigned char *page22;
252 int len = 0; 272 int len = 0;
253 273
254 rq = blk_get_request(sdev->request_queue, 274 rq = blk_get_request(sdev->request_queue,
255 (cmd == MODE_SELECT) ? WRITE : READ, GFP_ATOMIC); 275 (cmd == MODE_SELECT) ? WRITE : READ, GFP_NOIO);
256 if (!rq) { 276 if (!rq) {
257 sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); 277 sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
258 return NULL; 278 return NULL;
259 } 279 }
260 280
261 memset(&rq->cmd, 0, BLK_MAX_CDB); 281 memset(rq->cmd, 0, BLK_MAX_CDB);
282 rq->cmd_len = COMMAND_SIZE(cmd);
262 rq->cmd[0] = cmd; 283 rq->cmd[0] = cmd;
263 rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
264 284
265 switch (cmd) { 285 switch (cmd) {
266 case MODE_SELECT: 286 case MODE_SELECT:
267 if (csdev->short_trespass) { 287 len = sizeof(short_trespass);
268 page22 = csdev->hr ? short_trespass_hr : short_trespass; 288 rq->cmd_flags |= REQ_RW;
269 len = sizeof(short_trespass); 289 rq->cmd[1] = 0x10;
270 } else { 290 break;
271 page22 = csdev->hr ? long_trespass_hr : long_trespass; 291 case MODE_SELECT_10:
272 len = sizeof(long_trespass); 292 len = sizeof(long_trespass);
273 }
274 /*
275 * Can't DMA from kernel BSS -- must copy selected trespass
276 * command mode page contents to context buffer which is
277 * allocated by kmalloc.
278 */
279 BUG_ON((len > CLARIION_BUFFER_SIZE));
280 memcpy(csdev->buffer, page22, len);
281 rq->cmd_flags |= REQ_RW; 293 rq->cmd_flags |= REQ_RW;
282 rq->cmd[1] = 0x10; 294 rq->cmd[1] = 0x10;
283 break; 295 break;
284 case INQUIRY: 296 case INQUIRY:
285 rq->cmd[1] = 0x1;
286 rq->cmd[2] = 0xC0;
287 len = CLARIION_BUFFER_SIZE; 297 len = CLARIION_BUFFER_SIZE;
288 memset(csdev->buffer, 0, CLARIION_BUFFER_SIZE); 298 memset(buffer, 0, len);
289 break; 299 break;
290 default: 300 default:
291 BUG_ON(1); 301 BUG_ON(1);
@@ -298,47 +308,94 @@ static struct request *get_req(struct scsi_device *sdev, int cmd)
298 rq->timeout = CLARIION_TIMEOUT; 308 rq->timeout = CLARIION_TIMEOUT;
299 rq->retries = CLARIION_RETRIES; 309 rq->retries = CLARIION_RETRIES;
300 310
301 rq->sense = csdev->sense; 311 if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) {
302 memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); 312 blk_put_request(rq);
303 rq->sense_len = 0;
304
305 if (blk_rq_map_kern(sdev->request_queue, rq, csdev->buffer,
306 len, GFP_ATOMIC)) {
307 __blk_put_request(rq->q, rq);
308 return NULL; 313 return NULL;
309 } 314 }
310 315
311 return rq; 316 return rq;
312} 317}
313 318
314static int send_cmd(struct scsi_device *sdev, int cmd) 319static int send_inquiry_cmd(struct scsi_device *sdev, int page,
320 struct clariion_dh_data *csdev)
315{ 321{
316 struct request *rq = get_req(sdev, cmd); 322 struct request *rq = get_req(sdev, INQUIRY, csdev->buffer);
323 int err;
317 324
318 if (!rq) 325 if (!rq)
319 return SCSI_DH_RES_TEMP_UNAVAIL; 326 return SCSI_DH_RES_TEMP_UNAVAIL;
320 327
321 return blk_execute_rq(sdev->request_queue, NULL, rq, 1); 328 rq->sense = csdev->sense;
329 memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
330 rq->sense_len = csdev->senselen = 0;
331
332 rq->cmd[0] = INQUIRY;
333 if (page != 0) {
334 rq->cmd[1] = 1;
335 rq->cmd[2] = page;
336 }
337 err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
338 if (err == -EIO) {
339 sdev_printk(KERN_INFO, sdev,
340 "%s: failed to send %s INQUIRY: %x\n",
341 CLARIION_NAME, page?"EVPD":"standard",
342 rq->errors);
343 csdev->senselen = rq->sense_len;
344 err = SCSI_DH_IO;
345 }
346
347 blk_put_request(rq);
348
349 return err;
322} 350}
323 351
324static int clariion_activate(struct scsi_device *sdev) 352static int send_trespass_cmd(struct scsi_device *sdev,
353 struct clariion_dh_data *csdev)
325{ 354{
326 int result, done = 0; 355 struct request *rq;
356 unsigned char *page22;
357 int err, len, cmd;
358
359 if (csdev->flags & CLARIION_SHORT_TRESPASS) {
360 page22 = short_trespass;
361 if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
362 /* Set Honor Reservations bit */
363 page22[6] |= 0x80;
364 len = sizeof(short_trespass);
365 cmd = MODE_SELECT;
366 } else {
367 page22 = long_trespass;
368 if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
369 /* Set Honor Reservations bit */
370 page22[10] |= 0x80;
371 len = sizeof(long_trespass);
372 cmd = MODE_SELECT_10;
373 }
374 BUG_ON((len > CLARIION_BUFFER_SIZE));
375 memcpy(csdev->buffer, page22, len);
327 376
328 result = send_cmd(sdev, INQUIRY); 377 rq = get_req(sdev, cmd, csdev->buffer);
329 result = sp_info_endio(sdev, result, 0, &done); 378 if (!rq)
330 if (result || done) 379 return SCSI_DH_RES_TEMP_UNAVAIL;
331 goto done;
332 380
333 result = send_cmd(sdev, MODE_SELECT); 381 rq->sense = csdev->sense;
334 result = trespass_endio(sdev, result); 382 memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
335 if (result) 383 rq->sense_len = csdev->senselen = 0;
336 goto done;
337 384
338 result = send_cmd(sdev, INQUIRY); 385 err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
339 result = sp_info_endio(sdev, result, 1, NULL); 386 if (err == -EIO) {
340done: 387 if (rq->sense_len) {
341 return result; 388 err = trespass_endio(sdev, csdev->sense);
389 } else {
390 sdev_printk(KERN_INFO, sdev,
391 "%s: failed to send MODE SELECT: %x\n",
392 CLARIION_NAME, rq->errors);
393 }
394 }
395
396 blk_put_request(rq);
397
398 return err;
342} 399}
343 400
344static int clariion_check_sense(struct scsi_device *sdev, 401static int clariion_check_sense(struct scsi_device *sdev,
@@ -386,13 +443,129 @@ static int clariion_check_sense(struct scsi_device *sdev,
386 break; 443 break;
387 } 444 }
388 445
389 /* success just means we do not care what scsi-ml does */ 446 return SCSI_RETURN_NOT_HANDLED;
390 return SUCCESS; 447}
448
449static int clariion_prep_fn(struct scsi_device *sdev, struct request *req)
450{
451 struct clariion_dh_data *h = get_clariion_data(sdev);
452 int ret = BLKPREP_OK;
453
454 if (h->lun_state != CLARIION_LUN_OWNED) {
455 ret = BLKPREP_KILL;
456 req->cmd_flags |= REQ_QUIET;
457 }
458 return ret;
459
460}
461
462static int clariion_std_inquiry(struct scsi_device *sdev,
463 struct clariion_dh_data *csdev)
464{
465 int err;
466 char *sp_model;
467
468 err = send_inquiry_cmd(sdev, 0, csdev);
469 if (err != SCSI_DH_OK && csdev->senselen) {
470 struct scsi_sense_hdr sshdr;
471
472 if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
473 &sshdr)) {
474 sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
475 "%02x/%02x/%02x\n", CLARIION_NAME,
476 sshdr.sense_key, sshdr.asc, sshdr.ascq);
477 }
478 err = SCSI_DH_IO;
479 goto out;
480 }
481
482 sp_model = parse_sp_model(sdev, csdev->buffer);
483 if (!sp_model) {
484 err = SCSI_DH_DEV_UNSUPP;
485 goto out;
486 }
487
488 /*
489 * FC Series arrays do not support long trespass
490 */
491 if (!strlen(sp_model) || !strncmp(sp_model, "FC",2))
492 csdev->flags |= CLARIION_SHORT_TRESPASS;
493
494 sdev_printk(KERN_INFO, sdev,
495 "%s: detected Clariion %s, flags %x\n",
496 CLARIION_NAME, sp_model, csdev->flags);
497out:
498 return err;
499}
500
501static int clariion_send_inquiry(struct scsi_device *sdev,
502 struct clariion_dh_data *csdev)
503{
504 int err, retry = CLARIION_RETRIES;
505
506retry:
507 err = send_inquiry_cmd(sdev, 0xC0, csdev);
508 if (err != SCSI_DH_OK && csdev->senselen) {
509 struct scsi_sense_hdr sshdr;
510
511 err = scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
512 &sshdr);
513 if (!err)
514 return SCSI_DH_IO;
515
516 err = clariion_check_sense(sdev, &sshdr);
517 if (retry > 0 && err == NEEDS_RETRY) {
518 retry--;
519 goto retry;
520 }
521 sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
522 "%02x/%02x/%02x\n", CLARIION_NAME,
523 sshdr.sense_key, sshdr.asc, sshdr.ascq);
524 err = SCSI_DH_IO;
525 } else {
526 err = parse_sp_info_reply(sdev, csdev);
527 }
528 return err;
529}
530
531static int clariion_activate(struct scsi_device *sdev)
532{
533 struct clariion_dh_data *csdev = get_clariion_data(sdev);
534 int result;
535
536 result = clariion_send_inquiry(sdev, csdev);
537 if (result != SCSI_DH_OK)
538 goto done;
539
540 if (csdev->lun_state == CLARIION_LUN_OWNED)
541 goto done;
542
543 result = send_trespass_cmd(sdev, csdev);
544 if (result != SCSI_DH_OK)
545 goto done;
546 sdev_printk(KERN_INFO, sdev,"%s: %s trespass command sent\n",
547 CLARIION_NAME,
548 csdev->flags&CLARIION_SHORT_TRESPASS?"short":"long" );
549
550 /* Update status */
551 result = clariion_send_inquiry(sdev, csdev);
552 if (result != SCSI_DH_OK)
553 goto done;
554
555done:
556 sdev_printk(KERN_INFO, sdev,
557 "%s: at SP %c Port %d (%s, default SP %c)\n",
558 CLARIION_NAME, csdev->current_sp + 'A',
559 csdev->port, lun_state[csdev->lun_state],
560 csdev->default_sp + 'A');
561
562 return result;
391} 563}
392 564
393const struct scsi_dh_devlist clariion_dev_list[] = { 565const struct scsi_dh_devlist clariion_dev_list[] = {
394 {"DGC", "RAID"}, 566 {"DGC", "RAID"},
395 {"DGC", "DISK"}, 567 {"DGC", "DISK"},
568 {"DGC", "VRAID"},
396 {NULL, NULL}, 569 {NULL, NULL},
397}; 570};
398 571
@@ -407,6 +580,7 @@ static struct scsi_device_handler clariion_dh = {
407 .detach = clariion_bus_detach, 580 .detach = clariion_bus_detach,
408 .check_sense = clariion_check_sense, 581 .check_sense = clariion_check_sense,
409 .activate = clariion_activate, 582 .activate = clariion_activate,
583 .prep_fn = clariion_prep_fn,
410}; 584};
411 585
412/* 586/*
@@ -417,28 +591,50 @@ static int clariion_bus_attach(struct scsi_device *sdev)
417 struct scsi_dh_data *scsi_dh_data; 591 struct scsi_dh_data *scsi_dh_data;
418 struct clariion_dh_data *h; 592 struct clariion_dh_data *h;
419 unsigned long flags; 593 unsigned long flags;
594 int err;
420 595
421 scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) 596 scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
422 + sizeof(*h) , GFP_KERNEL); 597 + sizeof(*h) , GFP_KERNEL);
423 if (!scsi_dh_data) { 598 if (!scsi_dh_data) {
424 sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", 599 sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
425 CLARIION_NAME); 600 CLARIION_NAME);
426 return -ENOMEM; 601 return -ENOMEM;
427 } 602 }
428 603
429 scsi_dh_data->scsi_dh = &clariion_dh; 604 scsi_dh_data->scsi_dh = &clariion_dh;
430 h = (struct clariion_dh_data *) scsi_dh_data->buf; 605 h = (struct clariion_dh_data *) scsi_dh_data->buf;
606 h->lun_state = CLARIION_LUN_UNINITIALIZED;
431 h->default_sp = CLARIION_UNBOUND_LU; 607 h->default_sp = CLARIION_UNBOUND_LU;
432 h->current_sp = CLARIION_UNBOUND_LU; 608 h->current_sp = CLARIION_UNBOUND_LU;
433 609
610 err = clariion_std_inquiry(sdev, h);
611 if (err != SCSI_DH_OK)
612 goto failed;
613
614 err = clariion_send_inquiry(sdev, h);
615 if (err != SCSI_DH_OK)
616 goto failed;
617
618 if (!try_module_get(THIS_MODULE))
619 goto failed;
620
434 spin_lock_irqsave(sdev->request_queue->queue_lock, flags); 621 spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
435 sdev->scsi_dh_data = scsi_dh_data; 622 sdev->scsi_dh_data = scsi_dh_data;
436 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); 623 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
437 624
438 sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME); 625 sdev_printk(KERN_INFO, sdev,
439 try_module_get(THIS_MODULE); 626 "%s: connected to SP %c Port %d (%s, default SP %c)\n",
627 CLARIION_NAME, h->current_sp + 'A',
628 h->port, lun_state[h->lun_state],
629 h->default_sp + 'A');
440 630
441 return 0; 631 return 0;
632
633failed:
634 kfree(scsi_dh_data);
635 sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
636 CLARIION_NAME);
637 return -EINVAL;
442} 638}
443 639
444static void clariion_bus_detach(struct scsi_device *sdev) 640static void clariion_bus_detach(struct scsi_device *sdev)
@@ -451,7 +647,7 @@ static void clariion_bus_detach(struct scsi_device *sdev)
451 sdev->scsi_dh_data = NULL; 647 sdev->scsi_dh_data = NULL;
452 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); 648 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
453 649
454 sdev_printk(KERN_NOTICE, sdev, "Detached %s.\n", 650 sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n",
455 CLARIION_NAME); 651 CLARIION_NAME);
456 652
457 kfree(scsi_dh_data); 653 kfree(scsi_dh_data);
@@ -464,7 +660,8 @@ static int __init clariion_init(void)
464 660
465 r = scsi_register_device_handler(&clariion_dh); 661 r = scsi_register_device_handler(&clariion_dh);
466 if (r != 0) 662 if (r != 0)
467 printk(KERN_ERR "Failed to register scsi device handler."); 663 printk(KERN_ERR "%s: Failed to register scsi device handler.",
664 CLARIION_NAME);
468 return r; 665 return r;
469} 666}
470 667