Linux Audio

Check our new training course

Loading...
  1/*
  2 * Target driver for EMC CLARiiON AX/CX-series hardware.
  3 * Based on code from Lars Marowsky-Bree <lmb@suse.de>
  4 * and Ed Goggin <egoggin@emc.com>.
  5 *
  6 * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
  7 * Copyright (C) 2006 Mike Christie
  8 *
  9 * This program is free software; you can redistribute it and/or modify
 10 * it under the terms of the GNU General Public License as published by
 11 * the Free Software Foundation; either version 2, or (at your option)
 12 * any later version.
 13 *
 14 * This program is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17 * GNU General Public License for more details.
 18 *
 19 * You should have received a copy of the GNU General Public License
 20 * along with this program; see the file COPYING.  If not, write to
 21 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 22 */
 23#include <linux/slab.h>
 24#include <linux/module.h>
 25#include <scsi/scsi.h>
 26#include <scsi/scsi_eh.h>
 27#include <scsi/scsi_dh.h>
 28#include <scsi/scsi_device.h>
 29
 30#define CLARIION_NAME			"emc"
 31
 32#define CLARIION_TRESPASS_PAGE		0x22
 33#define CLARIION_BUFFER_SIZE		0xFC
 34#define CLARIION_TIMEOUT		(60 * HZ)
 35#define CLARIION_RETRIES		3
 36#define CLARIION_UNBOUND_LU		-1
 37#define CLARIION_SP_A			0
 38#define CLARIION_SP_B			1
 39
 40/* Flags */
 41#define CLARIION_SHORT_TRESPASS		1
 42#define CLARIION_HONOR_RESERVATIONS	2
 43
 44/* LUN states */
 45#define CLARIION_LUN_UNINITIALIZED	-1
 46#define CLARIION_LUN_UNBOUND		0
 47#define CLARIION_LUN_BOUND		1
 48#define CLARIION_LUN_OWNED		2
 49
 50static unsigned char long_trespass[] = {
 51	0, 0, 0, 0, 0, 0, 0, 0,
 52	CLARIION_TRESPASS_PAGE,	/* Page code */
 53	0x09,			/* Page length - 2 */
 54	0x01,			/* Trespass code */
 55	0xff, 0xff,		/* Trespass target */
 56	0, 0, 0, 0, 0, 0	/* Reserved bytes / unknown */
 57};
 58
 59static unsigned char short_trespass[] = {
 60	0, 0, 0, 0,
 61	CLARIION_TRESPASS_PAGE,	/* Page code */
 62	0x02,			/* Page length - 2 */
 63	0x01,			/* Trespass code */
 64	0xff,			/* Trespass target */
 65};
 66
 67static const char * lun_state[] =
 68{
 69    "not bound",
 70    "bound",
 71    "owned",
 72};
 73
 74struct clariion_dh_data {
 75	/*
 76	 * Flags:
 77	 *  CLARIION_SHORT_TRESPASS
 78	 * Use short trespass command (FC-series) or the long version
 79	 * (default for AX/CX CLARiiON arrays).
 80	 *
 81	 *  CLARIION_HONOR_RESERVATIONS
 82	 * Whether or not (default) to honor SCSI reservations when
 83	 * initiating a switch-over.
 84	 */
 85	unsigned flags;
 86	/*
 87	 * I/O buffer for both MODE_SELECT and INQUIRY commands.
 88	 */
 89	unsigned char buffer[CLARIION_BUFFER_SIZE];
 90	/*
 91	 * SCSI sense buffer for commands -- assumes serial issuance
 92	 * and completion sequence of all commands for same multipath.
 93	 */
 94	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
 95	unsigned int senselen;
 96	/*
 97	 * LUN state
 98	 */
 99	int lun_state;
100	/*
101	 * SP Port number
102	 */
103	int port;
104	/*
105	 * which SP (A=0,B=1,UNBOUND=-1) is the default SP for this
106	 * path's mapped LUN
107	 */
108	int default_sp;
109	/*
110	 * which SP (A=0,B=1,UNBOUND=-1) is the active SP for this
111	 * path's mapped LUN
112	 */
113	int current_sp;
114};
115
116static inline struct clariion_dh_data
117			*get_clariion_data(struct scsi_device *sdev)
118{
119	struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
120	BUG_ON(scsi_dh_data == NULL);
121	return ((struct clariion_dh_data *) scsi_dh_data->buf);
122}
123
124/*
125 * Parse MODE_SELECT cmd reply.
126 */
127static int trespass_endio(struct scsi_device *sdev, char *sense)
128{
129	int err = SCSI_DH_IO;
130	struct scsi_sense_hdr sshdr;
131
132	if (!scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) {
133		sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, "
134			    "0x%2x, 0x%2x while sending CLARiiON trespass "
135			    "command.\n", CLARIION_NAME, sshdr.sense_key,
136			    sshdr.asc, sshdr.ascq);
137
138		if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) &&
139		     (sshdr.ascq == 0x00)) {
140			/*
141			 * Array based copy in progress -- do not send
142			 * mode_select or copy will be aborted mid-stream.
143			 */
144			sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in "
145				    "progress while sending CLARiiON trespass "
146				    "command.\n", CLARIION_NAME);
147			err = SCSI_DH_DEV_TEMP_BUSY;
148		} else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) &&
149			    (sshdr.ascq == 0x03)) {
150			/*
151			 * LUN Not Ready - Manual Intervention Required
152			 * indicates in-progress ucode upgrade (NDU).
153			 */
154			sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress "
155				    "ucode upgrade NDU operation while sending "
156				    "CLARiiON trespass command.\n", CLARIION_NAME);
157			err = SCSI_DH_DEV_TEMP_BUSY;
158		} else
159			err = SCSI_DH_DEV_FAILED;
160	} else {
161		sdev_printk(KERN_INFO, sdev,
162			    "%s: failed to send MODE SELECT, no sense available\n",
163			    CLARIION_NAME);
164	}
165	return err;
166}
167
168static int parse_sp_info_reply(struct scsi_device *sdev,
169			       struct clariion_dh_data *csdev)
170{
171	int err = SCSI_DH_OK;
172
173	/* check for in-progress ucode upgrade (NDU) */
174	if (csdev->buffer[48] != 0) {
175		sdev_printk(KERN_NOTICE, sdev, "%s: Detected in-progress "
176			    "ucode upgrade NDU operation while finding "
177			    "current active SP.", CLARIION_NAME);
178		err = SCSI_DH_DEV_TEMP_BUSY;
179		goto out;
180	}
181	if (csdev->buffer[4] > 2) {
182		/* Invalid buffer format */
183		sdev_printk(KERN_NOTICE, sdev,
184			    "%s: invalid VPD page 0xC0 format\n",
185			    CLARIION_NAME);
186		err = SCSI_DH_NOSYS;
187		goto out;
188	}
189	switch (csdev->buffer[28] & 0x0f) {
190	case 6:
191		sdev_printk(KERN_NOTICE, sdev,
192			    "%s: ALUA failover mode detected\n",
193			    CLARIION_NAME);
194		break;
195	case 4:
196		/* Linux failover */
197		break;
198	default:
199		sdev_printk(KERN_WARNING, sdev,
200			    "%s: Invalid failover mode %d\n",
201			    CLARIION_NAME, csdev->buffer[28] & 0x0f);
202		err = SCSI_DH_NOSYS;
203		goto out;
204	}
205
206	csdev->default_sp = csdev->buffer[5];
207	csdev->lun_state = csdev->buffer[4];
208	csdev->current_sp = csdev->buffer[8];
209	csdev->port = csdev->buffer[7];
210
211out:
212	return err;
213}
214
215#define emc_default_str "FC (Legacy)"
216
217static char * parse_sp_model(struct scsi_device *sdev, unsigned char *buffer)
218{
219	unsigned char len = buffer[4] + 5;
220	char *sp_model = NULL;
221	unsigned char sp_len, serial_len;
222
223	if (len < 160) {
224		sdev_printk(KERN_WARNING, sdev,
225			    "%s: Invalid information section length %d\n",
226			    CLARIION_NAME, len);
227		/* Check for old FC arrays */
228		if (!strncmp(buffer + 8, "DGC", 3)) {
229			/* Old FC array, not supporting extended information */
230			sp_model = emc_default_str;
231		}
232		goto out;
233	}
234
235	/*
236	 * Parse extended information for SP model number
237	 */
238	serial_len = buffer[160];
239	if (serial_len == 0 || serial_len + 161 > len) {
240		sdev_printk(KERN_WARNING, sdev,
241			    "%s: Invalid array serial number length %d\n",
242			    CLARIION_NAME, serial_len);
243		goto out;
244	}
245	sp_len = buffer[99];
246	if (sp_len == 0 || serial_len + sp_len + 161 > len) {
247		sdev_printk(KERN_WARNING, sdev,
248			    "%s: Invalid model number length %d\n",
249			    CLARIION_NAME, sp_len);
250		goto out;
251	}
252	sp_model = &buffer[serial_len + 161];
253	/* Strip whitespace at the end */
254	while (sp_len > 1 && sp_model[sp_len - 1] == ' ')
255		sp_len--;
256
257	sp_model[sp_len] = '\0';
258
259out:
260	return sp_model;
261}
262
263/*
264 * Get block request for REQ_BLOCK_PC command issued to path.  Currently
265 * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
266 *
267 * Uses data and sense buffers in hardware handler context structure and
268 * assumes serial servicing of commands, both issuance and completion.
269 */
270static struct request *get_req(struct scsi_device *sdev, int cmd,
271				unsigned char *buffer)
272{
273	struct request *rq;
274	int len = 0;
275
276	rq = blk_get_request(sdev->request_queue,
277			(cmd != INQUIRY) ? WRITE : READ, GFP_NOIO);
278	if (!rq) {
279		sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
280		return NULL;
281	}
282
283	rq->cmd_len = COMMAND_SIZE(cmd);
284	rq->cmd[0] = cmd;
285
286	switch (cmd) {
287	case MODE_SELECT:
288		len = sizeof(short_trespass);
289		rq->cmd[1] = 0x10;
290		rq->cmd[4] = len;
291		break;
292	case MODE_SELECT_10:
293		len = sizeof(long_trespass);
294		rq->cmd[1] = 0x10;
295		rq->cmd[8] = len;
296		break;
297	case INQUIRY:
298		len = CLARIION_BUFFER_SIZE;
299		rq->cmd[4] = len;
300		memset(buffer, 0, len);
301		break;
302	default:
303		BUG_ON(1);
304		break;
305	}
306
307	rq->cmd_type = REQ_TYPE_BLOCK_PC;
308	rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
309			 REQ_FAILFAST_DRIVER;
310	rq->timeout = CLARIION_TIMEOUT;
311	rq->retries = CLARIION_RETRIES;
312
313	if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) {
314		blk_put_request(rq);
315		return NULL;
316	}
317
318	return rq;
319}
320
321static int send_inquiry_cmd(struct scsi_device *sdev, int page,
322			    struct clariion_dh_data *csdev)
323{
324	struct request *rq = get_req(sdev, INQUIRY, csdev->buffer);
325	int err;
326
327	if (!rq)
328		return SCSI_DH_RES_TEMP_UNAVAIL;
329
330	rq->sense = csdev->sense;
331	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
332	rq->sense_len = csdev->senselen = 0;
333
334	rq->cmd[0] = INQUIRY;
335	if (page != 0) {
336		rq->cmd[1] = 1;
337		rq->cmd[2] = page;
338	}
339	err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
340	if (err == -EIO) {
341		sdev_printk(KERN_INFO, sdev,
342			    "%s: failed to send %s INQUIRY: %x\n",
343			    CLARIION_NAME, page?"EVPD":"standard",
344			    rq->errors);
345		csdev->senselen = rq->sense_len;
346		err = SCSI_DH_IO;
347	}
348
349	blk_put_request(rq);
350
351	return err;
352}
353
354static int send_trespass_cmd(struct scsi_device *sdev,
355			    struct clariion_dh_data *csdev)
356{
357	struct request *rq;
358	unsigned char *page22;
359	int err, len, cmd;
360
361	if (csdev->flags & CLARIION_SHORT_TRESPASS) {
362		page22 = short_trespass;
363		if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
364			/* Set Honor Reservations bit */
365			page22[6] |= 0x80;
366		len = sizeof(short_trespass);
367		cmd = MODE_SELECT;
368	} else {
369		page22 = long_trespass;
370		if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
371			/* Set Honor Reservations bit */
372			page22[10] |= 0x80;
373		len = sizeof(long_trespass);
374		cmd = MODE_SELECT_10;
375	}
376	BUG_ON((len > CLARIION_BUFFER_SIZE));
377	memcpy(csdev->buffer, page22, len);
378
379	rq = get_req(sdev, cmd, csdev->buffer);
380	if (!rq)
381		return SCSI_DH_RES_TEMP_UNAVAIL;
382
383	rq->sense = csdev->sense;
384	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
385	rq->sense_len = csdev->senselen = 0;
386
387	err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
388	if (err == -EIO) {
389		if (rq->sense_len) {
390			err = trespass_endio(sdev, csdev->sense);
391		} else {
392			sdev_printk(KERN_INFO, sdev,
393				    "%s: failed to send MODE SELECT: %x\n",
394				    CLARIION_NAME, rq->errors);
395		}
396	}
397
398	blk_put_request(rq);
399
400	return err;
401}
402
403static int clariion_check_sense(struct scsi_device *sdev,
404				struct scsi_sense_hdr *sense_hdr)
405{
406	switch (sense_hdr->sense_key) {
407	case NOT_READY:
408		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x03)
409			/*
410			 * LUN Not Ready - Manual Intervention Required
411			 * indicates this is a passive path.
412			 *
413			 * FIXME: However, if this is seen and EVPD C0
414			 * indicates that this is due to a NDU in
415			 * progress, we should set FAIL_PATH too.
416			 * This indicates we might have to do a SCSI
417			 * inquiry in the end_io path. Ugh.
418			 *
419			 * Can return FAILED only when we want the error
420			 * recovery process to kick in.
421			 */
422			return SUCCESS;
423		break;
424	case ILLEGAL_REQUEST:
425		if (sense_hdr->asc == 0x25 && sense_hdr->ascq == 0x01)
426			/*
427			 * An array based copy is in progress. Do not
428			 * fail the path, do not bypass to another PG,
429			 * do not retry. Fail the IO immediately.
430			 * (Actually this is the same conclusion as in
431			 * the default handler, but lets make sure.)
432			 *
433			 * Can return FAILED only when we want the error
434			 * recovery process to kick in.
435			 */
436			return SUCCESS;
437		break;
438	case UNIT_ATTENTION:
439		if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
440			/*
441			 * Unit Attention Code. This is the first IO
442			 * to the new path, so just retry.
443			 */
444			return ADD_TO_MLQUEUE;
445		break;
446	}
447
448	return SCSI_RETURN_NOT_HANDLED;
449}
450
451static int clariion_prep_fn(struct scsi_device *sdev, struct request *req)
452{
453	struct clariion_dh_data *h = get_clariion_data(sdev);
454	int ret = BLKPREP_OK;
455
456	if (h->lun_state != CLARIION_LUN_OWNED) {
457		ret = BLKPREP_KILL;
458		req->cmd_flags |= REQ_QUIET;
459	}
460	return ret;
461
462}
463
464static int clariion_std_inquiry(struct scsi_device *sdev,
465				struct clariion_dh_data *csdev)
466{
467	int err;
468	char *sp_model;
469
470	err = send_inquiry_cmd(sdev, 0, csdev);
471	if (err != SCSI_DH_OK && csdev->senselen) {
472		struct scsi_sense_hdr sshdr;
473
474		if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
475					 &sshdr)) {
476			sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
477				    "%02x/%02x/%02x\n", CLARIION_NAME,
478				    sshdr.sense_key, sshdr.asc, sshdr.ascq);
479		}
480		err = SCSI_DH_IO;
481		goto out;
482	}
483
484	sp_model = parse_sp_model(sdev, csdev->buffer);
485	if (!sp_model) {
486		err = SCSI_DH_DEV_UNSUPP;
487		goto out;
488	}
489
490	/*
491	 * FC Series arrays do not support long trespass
492	 */
493	if (!strlen(sp_model) || !strncmp(sp_model, "FC",2))
494		csdev->flags |= CLARIION_SHORT_TRESPASS;
495
496	sdev_printk(KERN_INFO, sdev,
497		    "%s: detected Clariion %s, flags %x\n",
498		    CLARIION_NAME, sp_model, csdev->flags);
499out:
500	return err;
501}
502
503static int clariion_send_inquiry(struct scsi_device *sdev,
504				 struct clariion_dh_data *csdev)
505{
506	int err, retry = CLARIION_RETRIES;
507
508retry:
509	err = send_inquiry_cmd(sdev, 0xC0, csdev);
510	if (err != SCSI_DH_OK && csdev->senselen) {
511		struct scsi_sense_hdr sshdr;
512
513		err = scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
514					   &sshdr);
515		if (!err)
516			return SCSI_DH_IO;
517
518		err = clariion_check_sense(sdev, &sshdr);
519		if (retry > 0 && err == ADD_TO_MLQUEUE) {
520			retry--;
521			goto retry;
522		}
523		sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
524			    "%02x/%02x/%02x\n", CLARIION_NAME,
525			      sshdr.sense_key, sshdr.asc, sshdr.ascq);
526		err = SCSI_DH_IO;
527	} else {
528		err = parse_sp_info_reply(sdev, csdev);
529	}
530	return err;
531}
532
533static int clariion_activate(struct scsi_device *sdev,
534				activate_complete fn, void *data)
535{
536	struct clariion_dh_data *csdev = get_clariion_data(sdev);
537	int result;
538
539	result = clariion_send_inquiry(sdev, csdev);
540	if (result != SCSI_DH_OK)
541		goto done;
542
543	if (csdev->lun_state == CLARIION_LUN_OWNED)
544		goto done;
545
546	result = send_trespass_cmd(sdev, csdev);
547	if (result != SCSI_DH_OK)
548		goto done;
549	sdev_printk(KERN_INFO, sdev,"%s: %s trespass command sent\n",
550		    CLARIION_NAME,
551		    csdev->flags&CLARIION_SHORT_TRESPASS?"short":"long" );
552
553	/* Update status */
554	result = clariion_send_inquiry(sdev, csdev);
555	if (result != SCSI_DH_OK)
556		goto done;
557
558done:
559	sdev_printk(KERN_INFO, sdev,
560		    "%s: at SP %c Port %d (%s, default SP %c)\n",
561		    CLARIION_NAME, csdev->current_sp + 'A',
562		    csdev->port, lun_state[csdev->lun_state],
563		    csdev->default_sp + 'A');
564
565	if (fn)
566		fn(data, result);
567	return 0;
568}
569/*
570 * params - parameters in the following format
571 *      "no_of_params\0param1\0param2\0param3\0...\0"
572 *      for example, string for 2 parameters with value 10 and 21
573 *      is specified as "2\010\021\0".
574 */
575static int clariion_set_params(struct scsi_device *sdev, const char *params)
576{
577	struct clariion_dh_data *csdev = get_clariion_data(sdev);
578	unsigned int hr = 0, st = 0, argc;
579	const char *p = params;
580	int result = SCSI_DH_OK;
581
582	if ((sscanf(params, "%u", &argc) != 1) || (argc != 2))
583		return -EINVAL;
584
585	while (*p++)
586		;
587	if ((sscanf(p, "%u", &st) != 1) || (st > 1))
588		return -EINVAL;
589
590	while (*p++)
591		;
592	if ((sscanf(p, "%u", &hr) != 1) || (hr > 1))
593		return -EINVAL;
594
595	if (st)
596		csdev->flags |= CLARIION_SHORT_TRESPASS;
597	else
598		csdev->flags &= ~CLARIION_SHORT_TRESPASS;
599
600	if (hr)
601		csdev->flags |= CLARIION_HONOR_RESERVATIONS;
602	else
603		csdev->flags &= ~CLARIION_HONOR_RESERVATIONS;
604
605	/*
606	 * If this path is owned, we have to send a trespass command
607	 * with the new parameters. If not, simply return. Next trespass
608	 * command would use the parameters.
609	 */
610	if (csdev->lun_state != CLARIION_LUN_OWNED)
611		goto done;
612
613	csdev->lun_state = CLARIION_LUN_UNINITIALIZED;
614	result = send_trespass_cmd(sdev, csdev);
615	if (result != SCSI_DH_OK)
616		goto done;
617
618	/* Update status */
619	result = clariion_send_inquiry(sdev, csdev);
620
621done:
622	return result;
623}
624
625static const struct scsi_dh_devlist clariion_dev_list[] = {
626	{"DGC", "RAID"},
627	{"DGC", "DISK"},
628	{"DGC", "VRAID"},
629	{NULL, NULL},
630};
631
632static bool clariion_match(struct scsi_device *sdev)
633{
634	int i;
635
636	if (scsi_device_tpgs(sdev))
637		return false;
638
639	for (i = 0; clariion_dev_list[i].vendor; i++) {
640		if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor,
641			strlen(clariion_dev_list[i].vendor)) &&
642		    !strncmp(sdev->model, clariion_dev_list[i].model,
643			strlen(clariion_dev_list[i].model))) {
644			return true;
645		}
646	}
647	return false;
648}
649
650static int clariion_bus_attach(struct scsi_device *sdev);
651static void clariion_bus_detach(struct scsi_device *sdev);
652
653static struct scsi_device_handler clariion_dh = {
654	.name		= CLARIION_NAME,
655	.module		= THIS_MODULE,
656	.devlist	= clariion_dev_list,
657	.attach		= clariion_bus_attach,
658	.detach		= clariion_bus_detach,
659	.check_sense	= clariion_check_sense,
660	.activate	= clariion_activate,
661	.prep_fn	= clariion_prep_fn,
662	.set_params	= clariion_set_params,
663	.match		= clariion_match,
664};
665
666static int clariion_bus_attach(struct scsi_device *sdev)
667{
668	struct scsi_dh_data *scsi_dh_data;
669	struct clariion_dh_data *h;
670	unsigned long flags;
671	int err;
672
673	scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
674			       + sizeof(*h) , GFP_KERNEL);
675	if (!scsi_dh_data) {
676		sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
677			    CLARIION_NAME);
678		return -ENOMEM;
679	}
680
681	scsi_dh_data->scsi_dh = &clariion_dh;
682	h = (struct clariion_dh_data *) scsi_dh_data->buf;
683	h->lun_state = CLARIION_LUN_UNINITIALIZED;
684	h->default_sp = CLARIION_UNBOUND_LU;
685	h->current_sp = CLARIION_UNBOUND_LU;
686
687	err = clariion_std_inquiry(sdev, h);
688	if (err != SCSI_DH_OK)
689		goto failed;
690
691	err = clariion_send_inquiry(sdev, h);
692	if (err != SCSI_DH_OK)
693		goto failed;
694
695	if (!try_module_get(THIS_MODULE))
696		goto failed;
697
698	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
699	sdev->scsi_dh_data = scsi_dh_data;
700	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
701
702	sdev_printk(KERN_INFO, sdev,
703		    "%s: connected to SP %c Port %d (%s, default SP %c)\n",
704		    CLARIION_NAME, h->current_sp + 'A',
705		    h->port, lun_state[h->lun_state],
706		    h->default_sp + 'A');
707
708	return 0;
709
710failed:
711	kfree(scsi_dh_data);
712	sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
713		    CLARIION_NAME);
714	return -EINVAL;
715}
716
717static void clariion_bus_detach(struct scsi_device *sdev)
718{
719	struct scsi_dh_data *scsi_dh_data;
720	unsigned long flags;
721
722	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
723	scsi_dh_data = sdev->scsi_dh_data;
724	sdev->scsi_dh_data = NULL;
725	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
726
727	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n",
728		    CLARIION_NAME);
729
730	kfree(scsi_dh_data);
731	module_put(THIS_MODULE);
732}
733
734static int __init clariion_init(void)
735{
736	int r;
737
738	r = scsi_register_device_handler(&clariion_dh);
739	if (r != 0)
740		printk(KERN_ERR "%s: Failed to register scsi device handler.",
741			CLARIION_NAME);
742	return r;
743}
744
745static void __exit clariion_exit(void)
746{
747	scsi_unregister_device_handler(&clariion_dh);
748}
749
750module_init(clariion_init);
751module_exit(clariion_exit);
752
753MODULE_DESCRIPTION("EMC CX/AX/FC-family driver");
754MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, Chandra Seetharaman <sekharan@us.ibm.com>");
755MODULE_LICENSE("GPL");