Linux Audio

Check our new training course

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