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");
v3.5.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
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");