Blame view

drivers/block/cciss.c 149 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
bd4f36d6d   Mike Miller   cciss: update cop...
2
3
   *    Disk Array driver for HP Smart Array controllers.
   *    (C) Copyright 2000, 2007 Hewlett-Packard Development Company, L.P.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
   *
   *    This program is free software; you can redistribute it and/or modify
   *    it under the terms of the GNU General Public License as published by
bd4f36d6d   Mike Miller   cciss: update cop...
7
   *    the Free Software Foundation; version 2 of the License.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
   *
   *    This program is distributed in the hope that it will be useful,
   *    but WITHOUT ANY WARRANTY; without even the implied warranty of
bd4f36d6d   Mike Miller   cciss: update cop...
11
12
   *    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   *    General Public License for more details.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
   *
   *    You should have received a copy of the GNU General Public License
   *    along with this program; if not, write to the Free Software
bd4f36d6d   Mike Miller   cciss: update cop...
16
17
   *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   *    02111-1307, USA.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
   *
   *    Questions/Comments/Bugfixes to iss_storagedev@hp.com
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
  #include <linux/module.h>
  #include <linux/interrupt.h>
  #include <linux/types.h>
  #include <linux/pci.h>
193733585   Matthew Garrett   The Windows drive...
26
  #include <linux/pci-aspm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
33
34
35
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/delay.h>
  #include <linux/major.h>
  #include <linux/fs.h>
  #include <linux/bio.h>
  #include <linux/blkpg.h>
  #include <linux/timer.h>
  #include <linux/proc_fs.h>
89b6e7437   Mike Miller   resubmit: cciss: ...
36
  #include <linux/seq_file.h>
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
37
  #include <linux/init.h>
4d7616094   Randy Dunlap   cciss: fix schedu...
38
  #include <linux/jiffies.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  #include <linux/hdreg.h>
  #include <linux/spinlock.h>
  #include <linux/compat.h>
b368c9dd6   Andrew Patterson   cciss: Use one sc...
42
  #include <linux/mutex.h>
1f118bc47   Akinobu Mita   cciss: cleanup bi...
43
  #include <linux/bitmap.h>
d48c152a4   Akinobu Mita   cciss: use check_...
44
  #include <linux/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

eb0df9962   mike.miller@hp.com   [SCSI] cciss 2.6 ...
47
  #include <linux/dma-mapping.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
  #include <linux/blkdev.h>
  #include <linux/genhd.h>
  #include <linux/completion.h>
d5d3b736e   Stephen Cameron   cciss: include sc...
51
  #include <scsi/scsi.h>
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
52
53
54
  #include <scsi/sg.h>
  #include <scsi/scsi_ioctl.h>
  #include <linux/cdrom.h>
231bc2a22   Mike Pagano   cciss: error: imp...
55
  #include <linux/scatterlist.h>
0a9279cc7   Mike Miller   cciss: kernel sca...
56
  #include <linux/kthread.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
  
  #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
841fdffdd   Mike Miller   cciss: new contro...
59
60
  #define DRIVER_NAME "HP CISS Driver (v 3.6.26)"
  #define DRIVER_VERSION CCISS_DRIVER_VERSION(3, 6, 26)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
  
  /* Embedded module documentation macros - see modules.h */
  MODULE_AUTHOR("Hewlett-Packard Company");
24aac480e   Mike Miller   cciss: add new ha...
64
  MODULE_DESCRIPTION("Driver for HP Smart Array Controllers");
841fdffdd   Mike Miller   cciss: new contro...
65
66
  MODULE_SUPPORTED_DEVICE("HP Smart Array Controllers");
  MODULE_VERSION("3.6.26");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  MODULE_LICENSE("GPL");
8a4ec67bd   Stephen M. Cameron   cciss: add cciss_...
68
69
70
71
  static int cciss_tape_cmds = 6;
  module_param(cciss_tape_cmds, int, 0644);
  MODULE_PARM_DESC(cciss_tape_cmds,
  	"number of commands to allocate for tape devices (default: 6)");
130495370   Joseph Handzik   cciss: Adds simpl...
72
73
74
75
  static int cciss_simple_mode;
  module_param(cciss_simple_mode, int, S_IRUGO|S_IWUSR);
  MODULE_PARM_DESC(cciss_simple_mode,
  	"Use 'simple mode' rather than 'performant mode'");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

e4292e05d   Mike Miller   cciss: add cciss_...
77
78
79
80
81
  static int cciss_allow_hpsa;
  module_param(cciss_allow_hpsa, int, S_IRUGO|S_IWUSR);
  MODULE_PARM_DESC(cciss_allow_hpsa,
  	"Prevent cciss driver from accessing hardware known to be "
  	" supported by the hpsa driver");
2a48fc0ab   Arnd Bergmann   block: autoconver...
82
  static DEFINE_MUTEX(cciss_mutex);
bbe425cd9   Jens Axboe   cciss: fix build ...
83
  static struct proc_dir_entry *proc_cciss;
2ec24ff1d   Stephen M. Cameron   cciss: Add cciss_...
84

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
88
89
90
  #include "cciss_cmd.h"
  #include "cciss.h"
  #include <linux/cciss_ioctl.h>
  
  /* define the PCI info for the cards we can control */
  static const struct pci_device_id cciss_pci_device_id[] = {
f82ccdb99   Bjorn Helgaas   [PATCH] CCISS: ti...
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS,  0x0E11, 0x4070},
  	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4080},
  	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4082},
  	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4083},
  	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x4091},
  	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409A},
  	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409B},
  	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409C},
  	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409D},
  	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSA,     0x103C, 0x3225},
  	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3223},
  	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3234},
  	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3235},
  	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3211},
  	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3212},
  	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3213},
  	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3214},
  	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3215},
de9239167   Mike Miller   [PATCH] cciss: fi...
109
  	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3237},
9cff3b383   Mike Miller (OS Dev   cciss: add new co...
110
  	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x323D},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
  	{0,}
  };
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
113

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
  /*  board_id = Subsystem Device ID & Vendor ID
   *  product = Marketing Name for the board
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
117
   *  access = Address of the struct of function pointers
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
   */
  static struct board_type products[] = {
491539982   Mike Miller   cciss: read confi...
120
121
122
123
124
125
126
127
128
129
  	{0x40700E11, "Smart Array 5300", &SA5_access},
  	{0x40800E11, "Smart Array 5i", &SA5B_access},
  	{0x40820E11, "Smart Array 532", &SA5B_access},
  	{0x40830E11, "Smart Array 5312", &SA5B_access},
  	{0x409A0E11, "Smart Array 641", &SA5_access},
  	{0x409B0E11, "Smart Array 642", &SA5_access},
  	{0x409C0E11, "Smart Array 6400", &SA5_access},
  	{0x409D0E11, "Smart Array 6400 EM", &SA5_access},
  	{0x40910E11, "Smart Array 6i", &SA5_access},
  	{0x3225103C, "Smart Array P600", &SA5_access},
4205df340   Stephen M. Cameron   cciss: remove con...
130
131
  	{0x3223103C, "Smart Array P800", &SA5_access},
  	{0x3234103C, "Smart Array P400", &SA5_access},
491539982   Mike Miller   cciss: read confi...
132
133
134
135
136
137
138
  	{0x3235103C, "Smart Array P400i", &SA5_access},
  	{0x3211103C, "Smart Array E200i", &SA5_access},
  	{0x3212103C, "Smart Array E200", &SA5_access},
  	{0x3213103C, "Smart Array E200i", &SA5_access},
  	{0x3214103C, "Smart Array E200i", &SA5_access},
  	{0x3215103C, "Smart Array E200i", &SA5_access},
  	{0x3237103C, "Smart Array E500", &SA5_access},
2ec24ff1d   Stephen M. Cameron   cciss: Add cciss_...
139
140
  	{0x3223103C, "Smart Array P800", &SA5_access},
  	{0x3234103C, "Smart Array P400", &SA5_access},
491539982   Mike Miller   cciss: read confi...
141
  	{0x323D103C, "Smart Array P700m", &SA5_access},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  };
d14c4ab58   Bjorn Helgaas   [PATCH] CCISS: fi...
143
  /* How long to wait (in milliseconds) for board to go into simple mode */
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
144
  #define MAX_CONFIG_WAIT 30000
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
  #define MAX_IOCTL_CONFIG_WAIT 1000
  
  /*define how many times we will try a command because of bus resets */
  #define MAX_CMD_RETRIES 3
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
  #define MAX_CTLR	32
  
  /* Originally cciss driver only supports 8 major numbers */
  #define MAX_CTLR_ORIG 	8
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  static ctlr_info_t *hba[MAX_CTLR];
b368c9dd6   Andrew Patterson   cciss: Use one sc...
154
155
156
  static struct task_struct *cciss_scan_thread;
  static DEFINE_MUTEX(scan_mutex);
  static LIST_HEAD(scan_q);
165125e1e   Jens Axboe   [BLOCK] Get rid o...
157
  static void do_cciss_request(struct request_queue *q);
0c2b39087   Mike Miller   cciss: clean up i...
158
159
  static irqreturn_t do_cciss_intx(int irq, void *dev_id);
  static irqreturn_t do_cciss_msix_intr(int irq, void *dev_id);
ef7822c2f   Al Viro   [PATCH] switch cciss
160
  static int cciss_open(struct block_device *bdev, fmode_t mode);
6e9624b8c   Arnd Bergmann   block: push down ...
161
  static int cciss_unlocked_open(struct block_device *bdev, fmode_t mode);
db2a144be   Al Viro   block_device_oper...
162
  static void cciss_release(struct gendisk *disk, fmode_t mode);
ef7822c2f   Al Viro   [PATCH] switch cciss
163
  static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
164
  		       unsigned int cmd, unsigned long arg);
a885c8c43   Christoph Hellwig   [PATCH] Add block...
165
  static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  static int cciss_revalidate(struct gendisk *disk);
2d11d9931   Stephen M. Cameron   cciss: Fix usage_...
168
  static int rebuild_lun_table(ctlr_info_t *h, int first_time, int via_ioctl);
a0ea86229   Stephen M. Cameron   cciss: simplify p...
169
  static int deregister_disk(ctlr_info_t *h, int drv_index,
2d11d9931   Stephen M. Cameron   cciss: Fix usage_...
170
  			   int clear_all, int via_ioctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171

f70dba836   Stephen M. Cameron   cciss: use consis...
172
  static void cciss_read_capacity(ctlr_info_t *h, int logvol,
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
173
  			sector_t *total_size, unsigned int *block_size);
f70dba836   Stephen M. Cameron   cciss: use consis...
174
  static void cciss_read_capacity_16(ctlr_info_t *h, int logvol,
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
175
  			sector_t *total_size, unsigned int *block_size);
f70dba836   Stephen M. Cameron   cciss: use consis...
176
  static void cciss_geometry_inquiry(ctlr_info_t *h, int logvol,
7b838bde9   Stephen M. Cameron   cciss: Remove the...
177
  			sector_t total_size,
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
178
  			unsigned int block_size, InquiryData_struct *inq_buff,
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
179
  				   drive_info_struct *drv);
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
180
181
  static void cciss_interrupt_mode(ctlr_info_t *);
  static int cciss_enter_simple_mode(struct ctlr_info *h);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
182
  static void start_io(ctlr_info_t *h);
f70dba836   Stephen M. Cameron   cciss: use consis...
183
  static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size,
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
184
185
  			__u8 page_code, unsigned char scsi3addr[],
  			int cmd_type);
85cc61ae4   scameron@beardog.cca.cpqcorp.net   cciss: change SCS...
186
187
188
  static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
  	int attempt_retry);
  static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189

d6f4965d7   Andrew Patterson   cciss: Allow trig...
190
  static int add_to_scan_list(struct ctlr_info *h);
0a9279cc7   Mike Miller   cciss: kernel sca...
191
192
  static int scan_thread(void *data);
  static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c);
617e13442   Stephen M. Cameron   cciss: Dynamicall...
193
194
  static void cciss_hba_release(struct device *dev);
  static void cciss_device_release(struct device *dev);
361e9b07d   Stephen M. Cameron   cciss: Handle cas...
195
  static void cciss_free_gendisk(ctlr_info_t *h, int drv_index);
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
196
  static void cciss_free_drive_info(ctlr_info_t *h, int drv_index);
29979a712   Mike Miller   cciss: move next_...
197
  static inline u32 next_command(ctlr_info_t *h);
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
198
199
200
201
202
  static int cciss_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
  				u32 *cfg_base_addr, u64 *cfg_base_addr_index,
  				u64 *cfg_offset);
  static int cciss_pci_find_memory_BAR(struct pci_dev *pdev,
  				     unsigned long *memory_bar);
16011131c   Stephen M. Cameron   cciss: Mask off e...
203
  static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag);
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
204
  static int write_driver_ver_to_cfgtable(CfgTable_struct __iomem *cfgtable);
33079b219   Mike Miller   [PATCH] cciss: di...
205

5e216153c   Mike Miller   cciss: add perfor...
206
207
208
209
  /* performant mode helper functions */
  static void  calc_bucket_map(int *bucket, int num_buckets, int nsgs,
  				int *bucket_map);
  static void cciss_put_controller_into_performant_mode(ctlr_info_t *h);
33079b219   Mike Miller   [PATCH] cciss: di...
210

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  #ifdef CONFIG_PROC_FS
f70dba836   Stephen M. Cameron   cciss: use consis...
212
  static void cciss_procinit(ctlr_info_t *h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  #else
f70dba836   Stephen M. Cameron   cciss: use consis...
214
  static void cciss_procinit(ctlr_info_t *h)
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
215
216
217
  {
  }
  #endif				/* CONFIG_PROC_FS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
  
  #ifdef CONFIG_COMPAT
ef7822c2f   Al Viro   [PATCH] switch cciss
220
221
  static int cciss_compat_ioctl(struct block_device *, fmode_t,
  			      unsigned, unsigned long);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  #endif
83d5cde47   Alexey Dobriyan   const: make block...
223
  static const struct block_device_operations cciss_fops = {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
224
  	.owner = THIS_MODULE,
6e9624b8c   Arnd Bergmann   block: push down ...
225
  	.open = cciss_unlocked_open,
ef7822c2f   Al Viro   [PATCH] switch cciss
226
  	.release = cciss_release,
03f47e888   Stephen M. Cameron   cciss: fix broken...
227
  	.ioctl = cciss_ioctl,
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
228
  	.getgeo = cciss_getgeo,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  #ifdef CONFIG_COMPAT
ef7822c2f   Al Viro   [PATCH] switch cciss
230
  	.compat_ioctl = cciss_compat_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  #endif
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
232
  	.revalidate_disk = cciss_revalidate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  };
5e216153c   Mike Miller   cciss: add perfor...
234
235
236
237
238
239
  /* set_performant_mode: Modify the tag for cciss performant
   * set bit 0 for pull model, bits 3-1 for block fetch
   * register number
   */
  static void set_performant_mode(ctlr_info_t *h, CommandList_struct *c)
  {
0498cc2a9   Stephen M. Cameron   cciss: Inform con...
240
  	if (likely(h->transMethod & CFGTBL_Trans_Performant))
5e216153c   Mike Miller   cciss: add perfor...
241
242
  		c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
  /*
   * Enqueuing and dequeuing functions for cmdlists.
   */
e6e1ee936   Jens Axboe   cciss: reinstate ...
246
  static inline void addQ(struct list_head *list, CommandList_struct *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  {
e6e1ee936   Jens Axboe   cciss: reinstate ...
248
  	list_add_tail(&c->list, list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  }
8a3173de4   Jens Axboe   cciss: switch to ...
250
  static inline void removeQ(CommandList_struct *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  {
b59e64d0d   Hannes Reinecke   cciss: Ignore sta...
252
253
254
255
256
257
258
259
  	/*
  	 * After kexec/dump some commands might still
  	 * be in flight, which the firmware will try
  	 * to complete. Resetting the firmware doesn't work
  	 * with old fw revisions, so we have to mark
  	 * them off as 'stale' to prevent the driver from
  	 * falling over.
  	 */
e6e1ee936   Jens Axboe   cciss: reinstate ...
260
  	if (WARN_ON(list_empty(&c->list))) {
b59e64d0d   Hannes Reinecke   cciss: Ignore sta...
261
  		c->cmd_type = CMD_MSG_STALE;
8a3173de4   Jens Axboe   cciss: switch to ...
262
  		return;
b59e64d0d   Hannes Reinecke   cciss: Ignore sta...
263
  	}
8a3173de4   Jens Axboe   cciss: switch to ...
264

e6e1ee936   Jens Axboe   cciss: reinstate ...
265
  	list_del_init(&c->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  }
664a717d3   Mike Miller   cciss: enqueue an...
267
268
269
270
  static void enqueue_cmd_and_start_io(ctlr_info_t *h,
  	CommandList_struct *c)
  {
  	unsigned long flags;
5e216153c   Mike Miller   cciss: add perfor...
271
  	set_performant_mode(h, c);
664a717d3   Mike Miller   cciss: enqueue an...
272
273
274
  	spin_lock_irqsave(&h->lock, flags);
  	addQ(&h->reqQ, c);
  	h->Qdepth++;
2a643ec67   Stephen M. Cameron   cciss: fix report...
275
276
  	if (h->Qdepth > h->maxQsinceinit)
  		h->maxQsinceinit = h->Qdepth;
664a717d3   Mike Miller   cciss: enqueue an...
277
278
279
  	start_io(h);
  	spin_unlock_irqrestore(&h->lock, flags);
  }
dccc9b563   Stephen M. Cameron   cciss: simplify s...
280
  static void cciss_free_sg_chain_blocks(SGDescriptor_struct **cmd_sg_list,
49fc5601e   Stephen M. Cameron   cciss: factor out...
281
282
283
284
285
286
287
  	int nr_cmds)
  {
  	int i;
  
  	if (!cmd_sg_list)
  		return;
  	for (i = 0; i < nr_cmds; i++) {
dccc9b563   Stephen M. Cameron   cciss: simplify s...
288
289
  		kfree(cmd_sg_list[i]);
  		cmd_sg_list[i] = NULL;
49fc5601e   Stephen M. Cameron   cciss: factor out...
290
291
292
  	}
  	kfree(cmd_sg_list);
  }
dccc9b563   Stephen M. Cameron   cciss: simplify s...
293
294
  static SGDescriptor_struct **cciss_allocate_sg_chain_blocks(
  	ctlr_info_t *h, int chainsize, int nr_cmds)
49fc5601e   Stephen M. Cameron   cciss: factor out...
295
296
  {
  	int j;
dccc9b563   Stephen M. Cameron   cciss: simplify s...
297
  	SGDescriptor_struct **cmd_sg_list;
49fc5601e   Stephen M. Cameron   cciss: factor out...
298
299
300
301
302
303
304
305
306
307
  
  	if (chainsize <= 0)
  		return NULL;
  
  	cmd_sg_list = kmalloc(sizeof(*cmd_sg_list) * nr_cmds, GFP_KERNEL);
  	if (!cmd_sg_list)
  		return NULL;
  
  	/* Build up chain blocks for each command */
  	for (j = 0; j < nr_cmds; j++) {
49fc5601e   Stephen M. Cameron   cciss: factor out...
308
  		/* Need a block of chainsized s/g elements. */
dccc9b563   Stephen M. Cameron   cciss: simplify s...
309
310
311
  		cmd_sg_list[j] = kmalloc((chainsize *
  			sizeof(*cmd_sg_list[j])), GFP_KERNEL);
  		if (!cmd_sg_list[j]) {
49fc5601e   Stephen M. Cameron   cciss: factor out...
312
313
314
315
316
317
318
319
320
321
322
  			dev_err(&h->pdev->dev, "Cannot get memory "
  				"for s/g chains.
  ");
  			goto clean;
  		}
  	}
  	return cmd_sg_list;
  clean:
  	cciss_free_sg_chain_blocks(cmd_sg_list, nr_cmds);
  	return NULL;
  }
d45033ef5   Stephen M. Cameron   cciss: factor out...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
  static void cciss_unmap_sg_chain_block(ctlr_info_t *h, CommandList_struct *c)
  {
  	SGDescriptor_struct *chain_sg;
  	u64bit temp64;
  
  	if (c->Header.SGTotal <= h->max_cmd_sgentries)
  		return;
  
  	chain_sg = &c->SG[h->max_cmd_sgentries - 1];
  	temp64.val32.lower = chain_sg->Addr.lower;
  	temp64.val32.upper = chain_sg->Addr.upper;
  	pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
  }
  
  static void cciss_map_sg_chain_block(ctlr_info_t *h, CommandList_struct *c,
  	SGDescriptor_struct *chain_block, int len)
  {
  	SGDescriptor_struct *chain_sg;
  	u64bit temp64;
  
  	chain_sg = &c->SG[h->max_cmd_sgentries - 1];
  	chain_sg->Ext = CCISS_SG_CHAIN;
  	chain_sg->Len = len;
  	temp64.val = pci_map_single(h->pdev, chain_block, len,
  				PCI_DMA_TODEVICE);
  	chain_sg->Addr.lower = temp64.val32.lower;
  	chain_sg->Addr.upper = temp64.val32.upper;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
  #include "cciss_scsi.c"		/* For SCSI tape support */
1e6f2dc11   Alexander Beregalov   cciss: fix build ...
352
353
354
  static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
  	"UNKNOWN"
  };
0e4a9d03d   Kulikov Vasiliy   block: cciss: use...
355
  #define RAID_UNKNOWN (ARRAY_SIZE(raid_label)-1)
0f5486ecf   Randy Dunlap   [PATCH] cciss: bu...
356

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
361
362
363
  #ifdef CONFIG_PROC_FS
  
  /*
   * Report information about this controller.
   */
  #define ENG_GIG 1000000000
  #define ENG_GIG_FACTOR (ENG_GIG/512)
89b6e7437   Mike Miller   resubmit: cciss: ...
364
  #define ENGAGE_SCSI	"engage scsi"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365

89b6e7437   Mike Miller   resubmit: cciss: ...
366
  static void cciss_seq_show_header(struct seq_file *seq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  {
89b6e7437   Mike Miller   resubmit: cciss: ...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  	ctlr_info_t *h = seq->private;
  
  	seq_printf(seq, "%s: HP %s Controller
  "
  		"Board ID: 0x%08lx
  "
  		"Firmware Version: %c%c%c%c
  "
  		"IRQ: %d
  "
  		"Logical drives: %d
  "
  		"Current Q depth: %d
  "
  		"Current # commands on controller: %d
  "
  		"Max Q depth since init: %d
  "
  		"Max # commands on controller since init: %d
  "
  		"Max SG entries since init: %d
  ",
  		h->devname,
  		h->product_name,
  		(unsigned long)h->board_id,
  		h->firm_ver[0], h->firm_ver[1], h->firm_ver[2],
130495370   Joseph Handzik   cciss: Adds simpl...
394
  		h->firm_ver[3], (unsigned int)h->intr[h->intr_mode],
89b6e7437   Mike Miller   resubmit: cciss: ...
395
396
397
398
399
  		h->num_luns,
  		h->Qdepth, h->commands_outstanding,
  		h->maxQsinceinit, h->max_outstanding, h->maxSG);
  
  #ifdef CONFIG_CISS_SCSI_TAPE
f70dba836   Stephen M. Cameron   cciss: use consis...
400
  	cciss_seq_tape_report(seq, h);
89b6e7437   Mike Miller   resubmit: cciss: ...
401
402
  #endif /* CONFIG_CISS_SCSI_TAPE */
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403

89b6e7437   Mike Miller   resubmit: cciss: ...
404
405
406
  static void *cciss_seq_start(struct seq_file *seq, loff_t *pos)
  {
  	ctlr_info_t *h = seq->private;
89b6e7437   Mike Miller   resubmit: cciss: ...
407
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
411
  
  	/* prevent displaying bogus info during configuration
  	 * or deconfiguration of a logical volume
  	 */
f70dba836   Stephen M. Cameron   cciss: use consis...
412
  	spin_lock_irqsave(&h->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
  	if (h->busy_configuring) {
f70dba836   Stephen M. Cameron   cciss: use consis...
414
  		spin_unlock_irqrestore(&h->lock, flags);
89b6e7437   Mike Miller   resubmit: cciss: ...
415
  		return ERR_PTR(-EBUSY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
  	}
  	h->busy_configuring = 1;
f70dba836   Stephen M. Cameron   cciss: use consis...
418
  	spin_unlock_irqrestore(&h->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419

89b6e7437   Mike Miller   resubmit: cciss: ...
420
421
422
423
424
425
426
427
428
429
430
431
  	if (*pos == 0)
  		cciss_seq_show_header(seq);
  
  	return pos;
  }
  
  static int cciss_seq_show(struct seq_file *seq, void *v)
  {
  	sector_t vol_sz, vol_sz_frac;
  	ctlr_info_t *h = seq->private;
  	unsigned ctlr = h->ctlr;
  	loff_t *pos = v;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
432
  	drive_info_struct *drv = h->drv[*pos];
89b6e7437   Mike Miller   resubmit: cciss: ...
433
434
435
  
  	if (*pos > h->highest_lun)
  		return 0;
531c2dc70   Stephen M. Cameron   cciss: Make cciss...
436
437
  	if (drv == NULL) /* it's possible for h->drv[] to have holes. */
  		return 0;
89b6e7437   Mike Miller   resubmit: cciss: ...
438
439
440
441
442
443
444
  	if (drv->heads == 0)
  		return 0;
  
  	vol_sz = drv->nr_blocks;
  	vol_sz_frac = sector_div(vol_sz, ENG_GIG_FACTOR);
  	vol_sz_frac *= 100;
  	sector_div(vol_sz_frac, ENG_GIG_FACTOR);
fa52bec9d   Stephen M. Cameron   cciss: fix some m...
445
  	if (drv->raid_level < 0 || drv->raid_level > RAID_UNKNOWN)
89b6e7437   Mike Miller   resubmit: cciss: ...
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  		drv->raid_level = RAID_UNKNOWN;
  	seq_printf(seq, "cciss/c%dd%d:"
  			"\t%4u.%02uGB\tRAID %s
  ",
  			ctlr, (int) *pos, (int)vol_sz, (int)vol_sz_frac,
  			raid_label[drv->raid_level]);
  	return 0;
  }
  
  static void *cciss_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	ctlr_info_t *h = seq->private;
  
  	if (*pos > h->highest_lun)
  		return NULL;
  	*pos += 1;
  
  	return pos;
  }
  
  static void cciss_seq_stop(struct seq_file *seq, void *v)
  {
  	ctlr_info_t *h = seq->private;
  
  	/* Only reset h->busy_configuring if we succeeded in setting
  	 * it during cciss_seq_start. */
  	if (v == ERR_PTR(-EBUSY))
  		return;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
474

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
  	h->busy_configuring = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  }
88e9d34c7   James Morris   seq_file: constif...
477
  static const struct seq_operations cciss_seq_ops = {
89b6e7437   Mike Miller   resubmit: cciss: ...
478
479
480
481
482
483
484
485
486
487
488
489
  	.start = cciss_seq_start,
  	.show  = cciss_seq_show,
  	.next  = cciss_seq_next,
  	.stop  = cciss_seq_stop,
  };
  
  static int cciss_seq_open(struct inode *inode, struct file *file)
  {
  	int ret = seq_open(file, &cciss_seq_ops);
  	struct seq_file *seq = file->private_data;
  
  	if (!ret)
d9dda78ba   Al Viro   procfs: new helpe...
490
  		seq->private = PDE_DATA(inode);
89b6e7437   Mike Miller   resubmit: cciss: ...
491
492
493
494
495
496
497
  
  	return ret;
  }
  
  static ssize_t
  cciss_proc_write(struct file *file, const char __user *buf,
  		 size_t length, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
  {
89b6e7437   Mike Miller   resubmit: cciss: ...
499
500
501
502
503
  	int err;
  	char *buffer;
  
  #ifndef CONFIG_CISS_SCSI_TAPE
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
  #endif
89b6e7437   Mike Miller   resubmit: cciss: ...
505
  	if (!buf || length > PAGE_SIZE - 1)
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
506
  		return -EINVAL;
89b6e7437   Mike Miller   resubmit: cciss: ...
507
508
509
510
511
512
513
514
515
516
517
518
519
520
  
  	buffer = (char *)__get_free_page(GFP_KERNEL);
  	if (!buffer)
  		return -ENOMEM;
  
  	err = -EFAULT;
  	if (copy_from_user(buffer, buf, length))
  		goto out;
  	buffer[length] = '\0';
  
  #ifdef CONFIG_CISS_SCSI_TAPE
  	if (strncmp(ENGAGE_SCSI, buffer, sizeof ENGAGE_SCSI - 1) == 0) {
  		struct seq_file *seq = file->private_data;
  		ctlr_info_t *h = seq->private;
89b6e7437   Mike Miller   resubmit: cciss: ...
521

f70dba836   Stephen M. Cameron   cciss: use consis...
522
  		err = cciss_engage_scsi(h);
8721c81f6   Stephen M. Cameron   cciss: Fix weird ...
523
  		if (err == 0)
89b6e7437   Mike Miller   resubmit: cciss: ...
524
525
526
527
  			err = length;
  	} else
  #endif /* CONFIG_CISS_SCSI_TAPE */
  		err = -EINVAL;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
528
529
  	/* might be nice to have "disengage" too, but it's not
  	   safely possible. (only 1 module use count, lock issues.) */
89b6e7437   Mike Miller   resubmit: cciss: ...
530
531
532
533
  
  out:
  	free_page((unsigned long)buffer);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
  }
828c09509   Alexey Dobriyan   const: constify r...
535
  static const struct file_operations cciss_proc_fops = {
89b6e7437   Mike Miller   resubmit: cciss: ...
536
537
538
539
540
541
542
  	.owner	 = THIS_MODULE,
  	.open    = cciss_seq_open,
  	.read    = seq_read,
  	.llseek  = seq_lseek,
  	.release = seq_release,
  	.write	 = cciss_proc_write,
  };
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
543
  static void cciss_procinit(ctlr_info_t *h)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
  {
  	struct proc_dir_entry *pde;
89b6e7437   Mike Miller   resubmit: cciss: ...
546
  	if (proc_cciss == NULL)
928b4d8c8   Alexey Dobriyan   proc: remove proc...
547
  		proc_cciss = proc_mkdir("driver/cciss", NULL);
89b6e7437   Mike Miller   resubmit: cciss: ...
548
549
  	if (!proc_cciss)
  		return;
f70dba836   Stephen M. Cameron   cciss: use consis...
550
  	pde = proc_create_data(h->devname, S_IWUSR | S_IRUSR | S_IRGRP |
89b6e7437   Mike Miller   resubmit: cciss: ...
551
  					S_IROTH, proc_cciss,
f70dba836   Stephen M. Cameron   cciss: use consis...
552
  					&cciss_proc_fops, h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
554
  #endif				/* CONFIG_PROC_FS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555

7fe063268   Andrew Patterson   cciss: add cciss ...
556
557
558
559
  #define MAX_PRODUCT_NAME_LEN 19
  
  #define to_hba(n) container_of(n, struct ctlr_info, dev)
  #define to_drv(n) container_of(n, drive_info_struct, dev)
ec52d5f1c   Stephen M. Cameron   cciss: do not att...
560
  /* List of controllers which cannot be hard reset on kexec with reset_devices */
957c2ec55   Stephen M. Cameron   cciss: export res...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
  static u32 unresettable_controller[] = {
  	0x324a103C, /* Smart Array P712m */
  	0x324b103C, /* SmartArray P711m */
  	0x3223103C, /* Smart Array P800 */
  	0x3234103C, /* Smart Array P400 */
  	0x3235103C, /* Smart Array P400i */
  	0x3211103C, /* Smart Array E200i */
  	0x3212103C, /* Smart Array E200 */
  	0x3213103C, /* Smart Array E200i */
  	0x3214103C, /* Smart Array E200i */
  	0x3215103C, /* Smart Array E200i */
  	0x3237103C, /* Smart Array E500 */
  	0x323D103C, /* Smart Array P700m */
  	0x409C0E11, /* Smart Array 6400 */
  	0x409D0E11, /* Smart Array 6400 EM */
  };
ec52d5f1c   Stephen M. Cameron   cciss: do not att...
577
578
579
580
581
582
583
  /* List of controllers which cannot even be soft reset */
  static u32 soft_unresettable_controller[] = {
  	0x409C0E11, /* Smart Array 6400 */
  	0x409D0E11, /* Smart Array 6400 EM */
  };
  
  static int ctlr_is_hard_resettable(u32 board_id)
957c2ec55   Stephen M. Cameron   cciss: export res...
584
585
586
587
  {
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++)
ec52d5f1c   Stephen M. Cameron   cciss: do not att...
588
  		if (unresettable_controller[i] == board_id)
957c2ec55   Stephen M. Cameron   cciss: export res...
589
590
591
  			return 0;
  	return 1;
  }
ec52d5f1c   Stephen M. Cameron   cciss: do not att...
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
  static int ctlr_is_soft_resettable(u32 board_id)
  {
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(soft_unresettable_controller); i++)
  		if (soft_unresettable_controller[i] == board_id)
  			return 0;
  	return 1;
  }
  
  static int ctlr_is_resettable(u32 board_id)
  {
  	return ctlr_is_hard_resettable(board_id) ||
  		ctlr_is_soft_resettable(board_id);
  }
957c2ec55   Stephen M. Cameron   cciss: export res...
607
608
609
610
611
  static ssize_t host_show_resettable(struct device *dev,
  				    struct device_attribute *attr,
  				    char *buf)
  {
  	struct ctlr_info *h = to_hba(dev);
ec52d5f1c   Stephen M. Cameron   cciss: do not att...
612
613
  	return snprintf(buf, 20, "%d
  ", ctlr_is_resettable(h->board_id));
957c2ec55   Stephen M. Cameron   cciss: export res...
614
615
  }
  static DEVICE_ATTR(resettable, S_IRUGO, host_show_resettable, NULL);
d6f4965d7   Andrew Patterson   cciss: Allow trig...
616
617
618
619
620
621
622
623
624
625
626
627
  static ssize_t host_store_rescan(struct device *dev,
  				 struct device_attribute *attr,
  				 const char *buf, size_t count)
  {
  	struct ctlr_info *h = to_hba(dev);
  
  	add_to_scan_list(h);
  	wake_up_process(cciss_scan_thread);
  	wait_for_completion_interruptible(&h->scan_wait);
  
  	return count;
  }
8ba95c69f   Alex Chiang   cciss: Make devic...
628
  static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
7fe063268   Andrew Patterson   cciss: add cciss ...
629

f963d270c   Joe Handzik   cciss: add transp...
630
631
632
633
634
635
636
637
638
639
640
641
  static ssize_t host_show_transport_mode(struct device *dev,
  				 struct device_attribute *attr,
  				 char *buf)
  {
  	struct ctlr_info *h = to_hba(dev);
  
  	return snprintf(buf, 20, "%s
  ",
  		h->transMethod & CFGTBL_Trans_Performant ?
  			"performant" : "simple");
  }
  static DEVICE_ATTR(transport_mode, S_IRUGO, host_show_transport_mode, NULL);
7fe063268   Andrew Patterson   cciss: add cciss ...
642
643
644
645
646
647
648
649
650
  static ssize_t dev_show_unique_id(struct device *dev,
  				 struct device_attribute *attr,
  				 char *buf)
  {
  	drive_info_struct *drv = to_drv(dev);
  	struct ctlr_info *h = to_hba(drv->dev.parent);
  	__u8 sn[16];
  	unsigned long flags;
  	int ret = 0;
f70dba836   Stephen M. Cameron   cciss: use consis...
651
  	spin_lock_irqsave(&h->lock, flags);
7fe063268   Andrew Patterson   cciss: add cciss ...
652
653
654
655
  	if (h->busy_configuring)
  		ret = -EBUSY;
  	else
  		memcpy(sn, drv->serial_no, sizeof(sn));
f70dba836   Stephen M. Cameron   cciss: use consis...
656
  	spin_unlock_irqrestore(&h->lock, flags);
7fe063268   Andrew Patterson   cciss: add cciss ...
657
658
659
660
661
662
663
664
665
666
667
668
669
  
  	if (ret)
  		return ret;
  	else
  		return snprintf(buf, 16 * 2 + 2,
  				"%02X%02X%02X%02X%02X%02X%02X%02X"
  				"%02X%02X%02X%02X%02X%02X%02X%02X
  ",
  				sn[0], sn[1], sn[2], sn[3],
  				sn[4], sn[5], sn[6], sn[7],
  				sn[8], sn[9], sn[10], sn[11],
  				sn[12], sn[13], sn[14], sn[15]);
  }
8ba95c69f   Alex Chiang   cciss: Make devic...
670
  static DEVICE_ATTR(unique_id, S_IRUGO, dev_show_unique_id, NULL);
7fe063268   Andrew Patterson   cciss: add cciss ...
671
672
673
674
675
676
677
678
679
680
  
  static ssize_t dev_show_vendor(struct device *dev,
  			       struct device_attribute *attr,
  			       char *buf)
  {
  	drive_info_struct *drv = to_drv(dev);
  	struct ctlr_info *h = to_hba(drv->dev.parent);
  	char vendor[VENDOR_LEN + 1];
  	unsigned long flags;
  	int ret = 0;
f70dba836   Stephen M. Cameron   cciss: use consis...
681
  	spin_lock_irqsave(&h->lock, flags);
7fe063268   Andrew Patterson   cciss: add cciss ...
682
683
684
685
  	if (h->busy_configuring)
  		ret = -EBUSY;
  	else
  		memcpy(vendor, drv->vendor, VENDOR_LEN + 1);
f70dba836   Stephen M. Cameron   cciss: use consis...
686
  	spin_unlock_irqrestore(&h->lock, flags);
7fe063268   Andrew Patterson   cciss: add cciss ...
687
688
689
690
691
692
693
  
  	if (ret)
  		return ret;
  	else
  		return snprintf(buf, sizeof(vendor) + 1, "%s
  ", drv->vendor);
  }
8ba95c69f   Alex Chiang   cciss: Make devic...
694
  static DEVICE_ATTR(vendor, S_IRUGO, dev_show_vendor, NULL);
7fe063268   Andrew Patterson   cciss: add cciss ...
695
696
697
698
699
700
701
702
703
704
  
  static ssize_t dev_show_model(struct device *dev,
  			      struct device_attribute *attr,
  			      char *buf)
  {
  	drive_info_struct *drv = to_drv(dev);
  	struct ctlr_info *h = to_hba(drv->dev.parent);
  	char model[MODEL_LEN + 1];
  	unsigned long flags;
  	int ret = 0;
f70dba836   Stephen M. Cameron   cciss: use consis...
705
  	spin_lock_irqsave(&h->lock, flags);
7fe063268   Andrew Patterson   cciss: add cciss ...
706
707
708
709
  	if (h->busy_configuring)
  		ret = -EBUSY;
  	else
  		memcpy(model, drv->model, MODEL_LEN + 1);
f70dba836   Stephen M. Cameron   cciss: use consis...
710
  	spin_unlock_irqrestore(&h->lock, flags);
7fe063268   Andrew Patterson   cciss: add cciss ...
711
712
713
714
715
716
717
  
  	if (ret)
  		return ret;
  	else
  		return snprintf(buf, sizeof(model) + 1, "%s
  ", drv->model);
  }
8ba95c69f   Alex Chiang   cciss: Make devic...
718
  static DEVICE_ATTR(model, S_IRUGO, dev_show_model, NULL);
7fe063268   Andrew Patterson   cciss: add cciss ...
719
720
721
722
723
724
725
726
727
728
  
  static ssize_t dev_show_rev(struct device *dev,
  			    struct device_attribute *attr,
  			    char *buf)
  {
  	drive_info_struct *drv = to_drv(dev);
  	struct ctlr_info *h = to_hba(drv->dev.parent);
  	char rev[REV_LEN + 1];
  	unsigned long flags;
  	int ret = 0;
f70dba836   Stephen M. Cameron   cciss: use consis...
729
  	spin_lock_irqsave(&h->lock, flags);
7fe063268   Andrew Patterson   cciss: add cciss ...
730
731
732
733
  	if (h->busy_configuring)
  		ret = -EBUSY;
  	else
  		memcpy(rev, drv->rev, REV_LEN + 1);
f70dba836   Stephen M. Cameron   cciss: use consis...
734
  	spin_unlock_irqrestore(&h->lock, flags);
7fe063268   Andrew Patterson   cciss: add cciss ...
735
736
737
738
739
740
741
  
  	if (ret)
  		return ret;
  	else
  		return snprintf(buf, sizeof(rev) + 1, "%s
  ", drv->rev);
  }
8ba95c69f   Alex Chiang   cciss: Make devic...
742
  static DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL);
7fe063268   Andrew Patterson   cciss: add cciss ...
743

ce84a8aea   Stephen M. Cameron   cciss: Add lunid ...
744
745
746
  static ssize_t cciss_show_lunid(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
747
748
  	drive_info_struct *drv = to_drv(dev);
  	struct ctlr_info *h = to_hba(drv->dev.parent);
ce84a8aea   Stephen M. Cameron   cciss: Add lunid ...
749
750
  	unsigned long flags;
  	unsigned char lunid[8];
f70dba836   Stephen M. Cameron   cciss: use consis...
751
  	spin_lock_irqsave(&h->lock, flags);
ce84a8aea   Stephen M. Cameron   cciss: Add lunid ...
752
  	if (h->busy_configuring) {
f70dba836   Stephen M. Cameron   cciss: use consis...
753
  		spin_unlock_irqrestore(&h->lock, flags);
ce84a8aea   Stephen M. Cameron   cciss: Add lunid ...
754
755
756
  		return -EBUSY;
  	}
  	if (!drv->heads) {
f70dba836   Stephen M. Cameron   cciss: use consis...
757
  		spin_unlock_irqrestore(&h->lock, flags);
ce84a8aea   Stephen M. Cameron   cciss: Add lunid ...
758
759
760
  		return -ENOTTY;
  	}
  	memcpy(lunid, drv->LunID, sizeof(lunid));
f70dba836   Stephen M. Cameron   cciss: use consis...
761
  	spin_unlock_irqrestore(&h->lock, flags);
ce84a8aea   Stephen M. Cameron   cciss: Add lunid ...
762
763
764
765
766
  	return snprintf(buf, 20, "0x%02x%02x%02x%02x%02x%02x%02x%02x
  ",
  		lunid[0], lunid[1], lunid[2], lunid[3],
  		lunid[4], lunid[5], lunid[6], lunid[7]);
  }
8ba95c69f   Alex Chiang   cciss: Make devic...
767
  static DEVICE_ATTR(lunid, S_IRUGO, cciss_show_lunid, NULL);
ce84a8aea   Stephen M. Cameron   cciss: Add lunid ...
768

3ff1111dc   Stephen M. Cameron   cciss: Add a "rai...
769
770
771
  static ssize_t cciss_show_raid_level(struct device *dev,
  				     struct device_attribute *attr, char *buf)
  {
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
772
773
  	drive_info_struct *drv = to_drv(dev);
  	struct ctlr_info *h = to_hba(drv->dev.parent);
3ff1111dc   Stephen M. Cameron   cciss: Add a "rai...
774
775
  	int raid;
  	unsigned long flags;
f70dba836   Stephen M. Cameron   cciss: use consis...
776
  	spin_lock_irqsave(&h->lock, flags);
3ff1111dc   Stephen M. Cameron   cciss: Add a "rai...
777
  	if (h->busy_configuring) {
f70dba836   Stephen M. Cameron   cciss: use consis...
778
  		spin_unlock_irqrestore(&h->lock, flags);
3ff1111dc   Stephen M. Cameron   cciss: Add a "rai...
779
780
781
  		return -EBUSY;
  	}
  	raid = drv->raid_level;
f70dba836   Stephen M. Cameron   cciss: use consis...
782
  	spin_unlock_irqrestore(&h->lock, flags);
3ff1111dc   Stephen M. Cameron   cciss: Add a "rai...
783
784
785
786
787
788
789
  	if (raid < 0 || raid > RAID_UNKNOWN)
  		raid = RAID_UNKNOWN;
  
  	return snprintf(buf, strlen(raid_label[raid]) + 7, "RAID %s
  ",
  			raid_label[raid]);
  }
8ba95c69f   Alex Chiang   cciss: Make devic...
790
  static DEVICE_ATTR(raid_level, S_IRUGO, cciss_show_raid_level, NULL);
3ff1111dc   Stephen M. Cameron   cciss: Add a "rai...
791

e272afeca   Stephen M. Cameron   cciss: Add usage_...
792
793
794
  static ssize_t cciss_show_usage_count(struct device *dev,
  				      struct device_attribute *attr, char *buf)
  {
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
795
796
  	drive_info_struct *drv = to_drv(dev);
  	struct ctlr_info *h = to_hba(drv->dev.parent);
e272afeca   Stephen M. Cameron   cciss: Add usage_...
797
798
  	unsigned long flags;
  	int count;
f70dba836   Stephen M. Cameron   cciss: use consis...
799
  	spin_lock_irqsave(&h->lock, flags);
e272afeca   Stephen M. Cameron   cciss: Add usage_...
800
  	if (h->busy_configuring) {
f70dba836   Stephen M. Cameron   cciss: use consis...
801
  		spin_unlock_irqrestore(&h->lock, flags);
e272afeca   Stephen M. Cameron   cciss: Add usage_...
802
803
804
  		return -EBUSY;
  	}
  	count = drv->usage_count;
f70dba836   Stephen M. Cameron   cciss: use consis...
805
  	spin_unlock_irqrestore(&h->lock, flags);
e272afeca   Stephen M. Cameron   cciss: Add usage_...
806
807
808
  	return snprintf(buf, 20, "%d
  ", count);
  }
8ba95c69f   Alex Chiang   cciss: Make devic...
809
  static DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL);
e272afeca   Stephen M. Cameron   cciss: Add usage_...
810

d6f4965d7   Andrew Patterson   cciss: Allow trig...
811
812
  static struct attribute *cciss_host_attrs[] = {
  	&dev_attr_rescan.attr,
957c2ec55   Stephen M. Cameron   cciss: export res...
813
  	&dev_attr_resettable.attr,
f963d270c   Joe Handzik   cciss: add transp...
814
  	&dev_attr_transport_mode.attr,
d6f4965d7   Andrew Patterson   cciss: Allow trig...
815
816
817
818
819
820
  	NULL
  };
  
  static struct attribute_group cciss_host_attr_group = {
  	.attrs = cciss_host_attrs,
  };
9f792d9f5   Jens Axboe   cciss: cciss_host...
821
  static const struct attribute_group *cciss_host_attr_groups[] = {
d6f4965d7   Andrew Patterson   cciss: Allow trig...
822
823
824
825
826
827
828
  	&cciss_host_attr_group,
  	NULL
  };
  
  static struct device_type cciss_host_type = {
  	.name		= "cciss_host",
  	.groups		= cciss_host_attr_groups,
617e13442   Stephen M. Cameron   cciss: Dynamicall...
829
  	.release	= cciss_hba_release,
d6f4965d7   Andrew Patterson   cciss: Allow trig...
830
  };
7fe063268   Andrew Patterson   cciss: add cciss ...
831
832
833
834
835
  static struct attribute *cciss_dev_attrs[] = {
  	&dev_attr_unique_id.attr,
  	&dev_attr_model.attr,
  	&dev_attr_vendor.attr,
  	&dev_attr_rev.attr,
ce84a8aea   Stephen M. Cameron   cciss: Add lunid ...
836
  	&dev_attr_lunid.attr,
3ff1111dc   Stephen M. Cameron   cciss: Add a "rai...
837
  	&dev_attr_raid_level.attr,
e272afeca   Stephen M. Cameron   cciss: Add usage_...
838
  	&dev_attr_usage_count.attr,
7fe063268   Andrew Patterson   cciss: add cciss ...
839
840
841
842
843
844
  	NULL
  };
  
  static struct attribute_group cciss_dev_attr_group = {
  	.attrs = cciss_dev_attrs,
  };
a4dbd6740   David Brownell   driver model: con...
845
  static const struct attribute_group *cciss_dev_attr_groups[] = {
7fe063268   Andrew Patterson   cciss: add cciss ...
846
847
848
849
850
851
852
  	&cciss_dev_attr_group,
  	NULL
  };
  
  static struct device_type cciss_dev_type = {
  	.name		= "cciss_device",
  	.groups		= cciss_dev_attr_groups,
617e13442   Stephen M. Cameron   cciss: Dynamicall...
853
  	.release	= cciss_device_release,
7fe063268   Andrew Patterson   cciss: add cciss ...
854
855
856
857
858
  };
  
  static struct bus_type cciss_bus_type = {
  	.name		= "cciss",
  };
617e13442   Stephen M. Cameron   cciss: Dynamicall...
859
860
861
862
863
864
865
866
867
868
869
  /*
   * cciss_hba_release is called when the reference count
   * of h->dev goes to zero.
   */
  static void cciss_hba_release(struct device *dev)
  {
  	/*
  	 * nothing to do, but need this to avoid a warning
  	 * about not having a release handler from lib/kref.c.
  	 */
  }
7fe063268   Andrew Patterson   cciss: add cciss ...
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
  
  /*
   * Initialize sysfs entry for each controller.  This sets up and registers
   * the 'cciss#' directory for each individual controller under
   * /sys/bus/pci/devices/<dev>/.
   */
  static int cciss_create_hba_sysfs_entry(struct ctlr_info *h)
  {
  	device_initialize(&h->dev);
  	h->dev.type = &cciss_host_type;
  	h->dev.bus = &cciss_bus_type;
  	dev_set_name(&h->dev, "%s", h->devname);
  	h->dev.parent = &h->pdev->dev;
  
  	return device_add(&h->dev);
  }
  
  /*
   * Remove sysfs entries for an hba.
   */
  static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h)
  {
  	device_del(&h->dev);
617e13442   Stephen M. Cameron   cciss: Dynamicall...
893
894
895
896
  	put_device(&h->dev); /* final put. */
  }
  
  /* cciss_device_release is called when the reference count
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
897
   * of h->drv[x]dev goes to zero.
617e13442   Stephen M. Cameron   cciss: Dynamicall...
898
899
900
   */
  static void cciss_device_release(struct device *dev)
  {
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
901
902
  	drive_info_struct *drv = to_drv(dev);
  	kfree(drv);
7fe063268   Andrew Patterson   cciss: add cciss ...
903
904
905
906
907
908
909
910
  }
  
  /*
   * Initialize sysfs for each logical drive.  This sets up and registers
   * the 'c#d#' directory for each individual logical drive under
   * /sys/bus/pci/devices/<dev/ccis#/. We also create a link from
   * /sys/block/cciss!c#d# to this entry.
   */
617e13442   Stephen M. Cameron   cciss: Dynamicall...
911
  static long cciss_create_ld_sysfs_entry(struct ctlr_info *h,
7fe063268   Andrew Patterson   cciss: add cciss ...
912
913
  				       int drv_index)
  {
617e13442   Stephen M. Cameron   cciss: Dynamicall...
914
  	struct device *dev;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
915
  	if (h->drv[drv_index]->device_initialized)
8ce51966d   Stephen M. Cameron   cciss: Handle spe...
916
  		return 0;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
917
  	dev = &h->drv[drv_index]->dev;
617e13442   Stephen M. Cameron   cciss: Dynamicall...
918
919
920
921
922
  	device_initialize(dev);
  	dev->type = &cciss_dev_type;
  	dev->bus = &cciss_bus_type;
  	dev_set_name(dev, "c%dd%d", h->ctlr, drv_index);
  	dev->parent = &h->dev;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
923
  	h->drv[drv_index]->device_initialized = 1;
617e13442   Stephen M. Cameron   cciss: Dynamicall...
924
  	return device_add(dev);
7fe063268   Andrew Patterson   cciss: add cciss ...
925
926
927
928
929
  }
  
  /*
   * Remove sysfs entries for a logical drive.
   */
8ce51966d   Stephen M. Cameron   cciss: Handle spe...
930
931
  static void cciss_destroy_ld_sysfs_entry(struct ctlr_info *h, int drv_index,
  	int ctlr_exiting)
7fe063268   Andrew Patterson   cciss: add cciss ...
932
  {
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
933
  	struct device *dev = &h->drv[drv_index]->dev;
8ce51966d   Stephen M. Cameron   cciss: Handle spe...
934
935
936
937
  
  	/* special case for c*d0, we only destroy it on controller exit */
  	if (drv_index == 0 && !ctlr_exiting)
  		return;
617e13442   Stephen M. Cameron   cciss: Dynamicall...
938
939
  	device_del(dev);
  	put_device(dev); /* the "final" put. */
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
940
  	h->drv[drv_index] = NULL;
7fe063268   Andrew Patterson   cciss: add cciss ...
941
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
942
943
  /*
   * For operations that cannot sleep, a command block is allocated at init,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
   * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
6b4d96b87   Stephen M. Cameron   cciss: separate c...
945
   * which ones are free or in use.
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
946
   */
6b4d96b87   Stephen M. Cameron   cciss: separate c...
947
  static CommandList_struct *cmd_alloc(ctlr_info_t *h)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
949
  {
  	CommandList_struct *c;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
950
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
  	u64bit temp64;
  	dma_addr_t cmd_dma_handle, err_dma_handle;
6b4d96b87   Stephen M. Cameron   cciss: separate c...
953
954
955
  	do {
  		i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds);
  		if (i == h->nr_cmds)
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
956
  			return NULL;
1f118bc47   Akinobu Mita   cciss: cleanup bi...
957
  	} while (test_and_set_bit(i, h->cmd_pool_bits) != 0);
6b4d96b87   Stephen M. Cameron   cciss: separate c...
958
959
960
961
962
963
964
965
  	c = h->cmd_pool + i;
  	memset(c, 0, sizeof(CommandList_struct));
  	cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(CommandList_struct);
  	c->err_info = h->errinfo_pool + i;
  	memset(c->err_info, 0, sizeof(ErrorInfo_struct));
  	err_dma_handle = h->errinfo_pool_dhandle
  	    + i * sizeof(ErrorInfo_struct);
  	h->nr_allocs++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966

6b4d96b87   Stephen M. Cameron   cciss: separate c...
967
  	c->cmdindex = i;
33079b219   Mike Miller   [PATCH] cciss: di...
968

e6e1ee936   Jens Axboe   cciss: reinstate ...
969
  	INIT_LIST_HEAD(&c->list);
6b4d96b87   Stephen M. Cameron   cciss: separate c...
970
971
972
973
974
  	c->busaddr = (__u32) cmd_dma_handle;
  	temp64.val = (__u64) err_dma_handle;
  	c->ErrDesc.Addr.lower = temp64.val32.lower;
  	c->ErrDesc.Addr.upper = temp64.val32.upper;
  	c->ErrDesc.Len = sizeof(ErrorInfo_struct);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
975

6b4d96b87   Stephen M. Cameron   cciss: separate c...
976
977
978
  	c->ctlr = h->ctlr;
  	return c;
  }
33079b219   Mike Miller   [PATCH] cciss: di...
979

6b4d96b87   Stephen M. Cameron   cciss: separate c...
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
  /* allocate a command using pci_alloc_consistent, used for ioctls,
   * etc., not for the main i/o path.
   */
  static CommandList_struct *cmd_special_alloc(ctlr_info_t *h)
  {
  	CommandList_struct *c;
  	u64bit temp64;
  	dma_addr_t cmd_dma_handle, err_dma_handle;
  
  	c = (CommandList_struct *) pci_alloc_consistent(h->pdev,
  		sizeof(CommandList_struct), &cmd_dma_handle);
  	if (c == NULL)
  		return NULL;
  	memset(c, 0, sizeof(CommandList_struct));
  
  	c->cmdindex = -1;
  
  	c->err_info = (ErrorInfo_struct *)
  	    pci_alloc_consistent(h->pdev, sizeof(ErrorInfo_struct),
  		    &err_dma_handle);
  
  	if (c->err_info == NULL) {
  		pci_free_consistent(h->pdev,
  			sizeof(CommandList_struct), c, cmd_dma_handle);
  		return NULL;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1005
  	}
6b4d96b87   Stephen M. Cameron   cciss: separate c...
1006
  	memset(c->err_info, 0, sizeof(ErrorInfo_struct));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007

e6e1ee936   Jens Axboe   cciss: reinstate ...
1008
  	INIT_LIST_HEAD(&c->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
  	c->busaddr = (__u32) cmd_dma_handle;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1010
  	temp64.val = (__u64) err_dma_handle;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011
1012
1013
  	c->ErrDesc.Addr.lower = temp64.val32.lower;
  	c->ErrDesc.Addr.upper = temp64.val32.upper;
  	c->ErrDesc.Len = sizeof(ErrorInfo_struct);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014

7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1015
1016
  	c->ctlr = h->ctlr;
  	return c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
  }
6b4d96b87   Stephen M. Cameron   cciss: separate c...
1018
  static void cmd_free(ctlr_info_t *h, CommandList_struct *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
1020
  {
  	int i;
6b4d96b87   Stephen M. Cameron   cciss: separate c...
1021
1022
  
  	i = c - h->cmd_pool;
1f118bc47   Akinobu Mita   cciss: cleanup bi...
1023
  	clear_bit(i, h->cmd_pool_bits);
6b4d96b87   Stephen M. Cameron   cciss: separate c...
1024
1025
1026
1027
1028
  	h->nr_frees++;
  }
  
  static void cmd_special_free(ctlr_info_t *h, CommandList_struct *c)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
  	u64bit temp64;
6b4d96b87   Stephen M. Cameron   cciss: separate c...
1030
1031
1032
1033
  	temp64.val32.lower = c->ErrDesc.Addr.lower;
  	temp64.val32.upper = c->ErrDesc.Addr.upper;
  	pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct),
  			    c->err_info, (dma_addr_t) temp64.val);
16011131c   Stephen M. Cameron   cciss: Mask off e...
1034
1035
  	pci_free_consistent(h->pdev, sizeof(CommandList_struct), c,
  		(dma_addr_t) cciss_tag_discard_error_bits(h, (u32) c->busaddr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1036
1037
1038
1039
  }
  
  static inline ctlr_info_t *get_host(struct gendisk *disk)
  {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1040
  	return disk->queue->queuedata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
  }
  
  static inline drive_info_struct *get_drv(struct gendisk *disk)
  {
  	return disk->private_data;
  }
  
  /*
   * Open.  Make sure the device is really there.
   */
ef7822c2f   Al Viro   [PATCH] switch cciss
1051
  static int cciss_open(struct block_device *bdev, fmode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
  {
f70dba836   Stephen M. Cameron   cciss: use consis...
1053
  	ctlr_info_t *h = get_host(bdev->bd_disk);
ef7822c2f   Al Viro   [PATCH] switch cciss
1054
  	drive_info_struct *drv = get_drv(bdev->bd_disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055

b2a4a43db   Stephen M. Cameron   cciss: change pri...
1056
1057
  	dev_dbg(&h->pdev->dev, "cciss_open %s
  ", bdev->bd_disk->disk_name);
2e043986d   Stephen M. Cameron   cciss: Don't chec...
1058
  	if (drv->busy_configuring)
ddd474420   Mike Miller   [PATCH] cciss: ne...
1059
  		return -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
1062
1063
1064
1065
1066
1067
  	/*
  	 * Root is allowed to open raw volume zero even if it's not configured
  	 * so array config can still work. Root is also allowed to open any
  	 * volume that has a LUN ID, so it can issue IOCTL to reread the
  	 * disk information.  I don't think I really like this
  	 * but I'm already using way to many device nodes to claim another one
  	 * for "raw controller".
  	 */
7a06f789e   Mike Miller   [PATCH] cciss: ch...
1068
  	if (drv->heads == 0) {
ef7822c2f   Al Viro   [PATCH] switch cciss
1069
  		if (MINOR(bdev->bd_dev) != 0) {	/* not node 0? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
  			/* if not node 0 make sure it is a partition = 0 */
ef7822c2f   Al Viro   [PATCH] switch cciss
1071
  			if (MINOR(bdev->bd_dev) & 0x0f) {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1072
  				return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
  				/* if it is, make sure we have a LUN ID */
39ccf9a64   Stephen M. Cameron   cciss: Preserve a...
1074
1075
  			} else if (memcmp(drv->LunID, CTLR_LUNID,
  				sizeof(drv->LunID))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
1077
1078
1079
1080
1081
1082
  				return -ENXIO;
  			}
  		}
  		if (!capable(CAP_SYS_ADMIN))
  			return -EPERM;
  	}
  	drv->usage_count++;
f70dba836   Stephen M. Cameron   cciss: use consis...
1083
  	h->usage_count++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
1085
  	return 0;
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1086

6e9624b8c   Arnd Bergmann   block: push down ...
1087
1088
1089
  static int cciss_unlocked_open(struct block_device *bdev, fmode_t mode)
  {
  	int ret;
2a48fc0ab   Arnd Bergmann   block: autoconver...
1090
  	mutex_lock(&cciss_mutex);
6e9624b8c   Arnd Bergmann   block: push down ...
1091
  	ret = cciss_open(bdev, mode);
2a48fc0ab   Arnd Bergmann   block: autoconver...
1092
  	mutex_unlock(&cciss_mutex);
6e9624b8c   Arnd Bergmann   block: push down ...
1093
1094
1095
  
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
1097
1098
  /*
   * Close.  Sync first.
   */
db2a144be   Al Viro   block_device_oper...
1099
  static void cciss_release(struct gendisk *disk, fmode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
  {
f70dba836   Stephen M. Cameron   cciss: use consis...
1101
  	ctlr_info_t *h;
6e9624b8c   Arnd Bergmann   block: push down ...
1102
  	drive_info_struct *drv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103

2a48fc0ab   Arnd Bergmann   block: autoconver...
1104
  	mutex_lock(&cciss_mutex);
f70dba836   Stephen M. Cameron   cciss: use consis...
1105
  	h = get_host(disk);
6e9624b8c   Arnd Bergmann   block: push down ...
1106
  	drv = get_drv(disk);
b2a4a43db   Stephen M. Cameron   cciss: change pri...
1107
1108
  	dev_dbg(&h->pdev->dev, "cciss_release %s
  ", disk->disk_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
  	drv->usage_count--;
f70dba836   Stephen M. Cameron   cciss: use consis...
1110
  	h->usage_count--;
2a48fc0ab   Arnd Bergmann   block: autoconver...
1111
  	mutex_unlock(&cciss_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
  }
8a6cfeb6d   Arnd Bergmann   block: push down ...
1113
  #ifdef CONFIG_COMPAT
ef7822c2f   Al Viro   [PATCH] switch cciss
1114
1115
1116
1117
  static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode,
  				  unsigned cmd, unsigned long arg);
  static int cciss_ioctl32_big_passthru(struct block_device *bdev, fmode_t mode,
  				      unsigned cmd, unsigned long arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118

ef7822c2f   Al Viro   [PATCH] switch cciss
1119
1120
  static int cciss_compat_ioctl(struct block_device *bdev, fmode_t mode,
  			      unsigned cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  {
  	switch (cmd) {
  	case CCISS_GETPCIINFO:
  	case CCISS_GETINTINFO:
  	case CCISS_SETINTINFO:
  	case CCISS_GETNODENAME:
  	case CCISS_SETNODENAME:
  	case CCISS_GETHEARTBEAT:
  	case CCISS_GETBUSTYPES:
  	case CCISS_GETFIRMVER:
  	case CCISS_GETDRIVVER:
  	case CCISS_REVALIDVOLS:
  	case CCISS_DEREGDISK:
  	case CCISS_REGNEWDISK:
  	case CCISS_REGNEWD:
  	case CCISS_RESCANDISK:
  	case CCISS_GETLUNINFO:
03f47e888   Stephen M. Cameron   cciss: fix broken...
1138
  		return cciss_ioctl(bdev, mode, cmd, arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
1140
  
  	case CCISS_PASSTHRU32:
ef7822c2f   Al Viro   [PATCH] switch cciss
1141
  		return cciss_ioctl32_passthru(bdev, mode, cmd, arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
  	case CCISS_BIG_PASSTHRU32:
ef7822c2f   Al Viro   [PATCH] switch cciss
1143
  		return cciss_ioctl32_big_passthru(bdev, mode, cmd, arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1144
1145
1146
1147
1148
  
  	default:
  		return -ENOIOCTLCMD;
  	}
  }
ef7822c2f   Al Viro   [PATCH] switch cciss
1149
1150
  static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode,
  				  unsigned cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
1152
  {
  	IOCTL32_Command_struct __user *arg32 =
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1153
  	    (IOCTL32_Command_struct __user *) arg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
1155
1156
1157
  	IOCTL_Command_struct arg64;
  	IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
  	int err;
  	u32 cp;
58f09e00a   Dan Carpenter   cciss: fix info l...
1158
  	memset(&arg64, 0, sizeof(arg64));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
  	err = 0;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1160
1161
1162
1163
1164
1165
1166
1167
1168
  	err |=
  	    copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
  			   sizeof(arg64.LUN_info));
  	err |=
  	    copy_from_user(&arg64.Request, &arg32->Request,
  			   sizeof(arg64.Request));
  	err |=
  	    copy_from_user(&arg64.error_info, &arg32->error_info,
  			   sizeof(arg64.error_info));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
1170
1171
1172
1173
1174
1175
  	err |= get_user(arg64.buf_size, &arg32->buf_size);
  	err |= get_user(cp, &arg32->buf);
  	arg64.buf = compat_ptr(cp);
  	err |= copy_to_user(p, &arg64, sizeof(arg64));
  
  	if (err)
  		return -EFAULT;
03f47e888   Stephen M. Cameron   cciss: fix broken...
1176
  	err = cciss_ioctl(bdev, mode, CCISS_PASSTHRU, (unsigned long)p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1177
1178
  	if (err)
  		return err;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1179
1180
1181
  	err |=
  	    copy_in_user(&arg32->error_info, &p->error_info,
  			 sizeof(arg32->error_info));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
1183
1184
1185
  	if (err)
  		return -EFAULT;
  	return err;
  }
ef7822c2f   Al Viro   [PATCH] switch cciss
1186
1187
  static int cciss_ioctl32_big_passthru(struct block_device *bdev, fmode_t mode,
  				      unsigned cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1188
1189
  {
  	BIG_IOCTL32_Command_struct __user *arg32 =
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1190
  	    (BIG_IOCTL32_Command_struct __user *) arg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191
  	BIG_IOCTL_Command_struct arg64;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1192
1193
  	BIG_IOCTL_Command_struct __user *p =
  	    compat_alloc_user_space(sizeof(arg64));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
1195
  	int err;
  	u32 cp;
7ab5118d7   Vasiliy Kulikov   block: cciss: fix...
1196
  	memset(&arg64, 0, sizeof(arg64));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
  	err = 0;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1198
1199
1200
1201
1202
1203
1204
1205
1206
  	err |=
  	    copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
  			   sizeof(arg64.LUN_info));
  	err |=
  	    copy_from_user(&arg64.Request, &arg32->Request,
  			   sizeof(arg64.Request));
  	err |=
  	    copy_from_user(&arg64.error_info, &arg32->error_info,
  			   sizeof(arg64.error_info));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
1208
1209
1210
1211
1212
1213
  	err |= get_user(arg64.buf_size, &arg32->buf_size);
  	err |= get_user(arg64.malloc_size, &arg32->malloc_size);
  	err |= get_user(cp, &arg32->buf);
  	arg64.buf = compat_ptr(cp);
  	err |= copy_to_user(p, &arg64, sizeof(arg64));
  
  	if (err)
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1214
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1215

03f47e888   Stephen M. Cameron   cciss: fix broken...
1216
  	err = cciss_ioctl(bdev, mode, CCISS_BIG_PASSTHRU, (unsigned long)p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
1218
  	if (err)
  		return err;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1219
1220
1221
  	err |=
  	    copy_in_user(&arg32->error_info, &p->error_info,
  			 sizeof(arg32->error_info));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
1223
1224
1225
1226
  	if (err)
  		return -EFAULT;
  	return err;
  }
  #endif
a885c8c43   Christoph Hellwig   [PATCH] Add block...
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
  
  static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo)
  {
  	drive_info_struct *drv = get_drv(bdev->bd_disk);
  
  	if (!drv->cylinders)
  		return -ENXIO;
  
  	geo->heads = drv->heads;
  	geo->sectors = drv->sectors;
  	geo->cylinders = drv->cylinders;
  	return 0;
  }
f70dba836   Stephen M. Cameron   cciss: use consis...
1240
  static void check_ioctl_unit_attention(ctlr_info_t *h, CommandList_struct *c)
0a9279cc7   Mike Miller   cciss: kernel sca...
1241
1242
1243
  {
  	if (c->err_info->CommandStatus == CMD_TARGET_STATUS &&
  			c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION)
f70dba836   Stephen M. Cameron   cciss: use consis...
1244
  		(void)check_for_unit_attention(h, c);
0a9279cc7   Mike Miller   cciss: kernel sca...
1245
  }
0a25a5aee   Stephen M. Cameron   cciss: factor out...
1246
1247
  
  static int cciss_getpciinfo(ctlr_info_t *h, void __user *argp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1248
  {
0a25a5aee   Stephen M. Cameron   cciss: factor out...
1249
  	cciss_pci_info_struct pciinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250

0a25a5aee   Stephen M. Cameron   cciss: factor out...
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
  	if (!argp)
  		return -EINVAL;
  	pciinfo.domain = pci_domain_nr(h->pdev->bus);
  	pciinfo.bus = h->pdev->bus->number;
  	pciinfo.dev_fn = h->pdev->devfn;
  	pciinfo.board_id = h->board_id;
  	if (copy_to_user(argp, &pciinfo, sizeof(cciss_pci_info_struct)))
  		return -EFAULT;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261

576e661c6   Stephen M. Cameron   cciss: factor out...
1262
1263
1264
  static int cciss_getintinfo(ctlr_info_t *h, void __user *argp)
  {
  	cciss_coalint_struct intinfo;
03f47e888   Stephen M. Cameron   cciss: fix broken...
1265
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1266

576e661c6   Stephen M. Cameron   cciss: factor out...
1267
1268
  	if (!argp)
  		return -EINVAL;
03f47e888   Stephen M. Cameron   cciss: fix broken...
1269
  	spin_lock_irqsave(&h->lock, flags);
576e661c6   Stephen M. Cameron   cciss: factor out...
1270
1271
  	intinfo.delay = readl(&h->cfgtable->HostWrite.CoalIntDelay);
  	intinfo.count = readl(&h->cfgtable->HostWrite.CoalIntCount);
03f47e888   Stephen M. Cameron   cciss: fix broken...
1272
  	spin_unlock_irqrestore(&h->lock, flags);
576e661c6   Stephen M. Cameron   cciss: factor out...
1273
1274
1275
1276
1277
  	if (copy_to_user
  	    (argp, &intinfo, sizeof(cciss_coalint_struct)))
  		return -EFAULT;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278

4c800eed9   Stephen M. Cameron   cciss: factor out...
1279
1280
1281
1282
1283
  static int cciss_setintinfo(ctlr_info_t *h, void __user *argp)
  {
  	cciss_coalint_struct intinfo;
  	unsigned long flags;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284

4c800eed9   Stephen M. Cameron   cciss: factor out...
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
  	if (!argp)
  		return -EINVAL;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (copy_from_user(&intinfo, argp, sizeof(intinfo)))
  		return -EFAULT;
  	if ((intinfo.delay == 0) && (intinfo.count == 0))
  		return -EINVAL;
  	spin_lock_irqsave(&h->lock, flags);
  	/* Update the field, and then ring the doorbell */
  	writel(intinfo.delay, &(h->cfgtable->HostWrite.CoalIntDelay));
  	writel(intinfo.count, &(h->cfgtable->HostWrite.CoalIntCount));
  	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
  
  	for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
  		if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
  			break;
  		udelay(1000); /* delay and try again */
  	}
  	spin_unlock_irqrestore(&h->lock, flags);
  	if (i >= MAX_IOCTL_CONFIG_WAIT)
  		return -EAGAIN;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309

252161094   Stephen M. Cameron   cciss: factor out...
1310
1311
1312
  static int cciss_getnodename(ctlr_info_t *h, void __user *argp)
  {
  	NodeName_type NodeName;
03f47e888   Stephen M. Cameron   cciss: fix broken...
1313
  	unsigned long flags;
252161094   Stephen M. Cameron   cciss: factor out...
1314
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315

252161094   Stephen M. Cameron   cciss: factor out...
1316
1317
  	if (!argp)
  		return -EINVAL;
03f47e888   Stephen M. Cameron   cciss: fix broken...
1318
  	spin_lock_irqsave(&h->lock, flags);
252161094   Stephen M. Cameron   cciss: factor out...
1319
1320
  	for (i = 0; i < 16; i++)
  		NodeName[i] = readb(&h->cfgtable->ServerName[i]);
03f47e888   Stephen M. Cameron   cciss: fix broken...
1321
  	spin_unlock_irqrestore(&h->lock, flags);
252161094   Stephen M. Cameron   cciss: factor out...
1322
1323
1324
1325
  	if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
  		return -EFAULT;
  	return 0;
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1326

4f43f32cd   Stephen M. Cameron   cciss: factor out...
1327
1328
1329
1330
1331
  static int cciss_setnodename(ctlr_info_t *h, void __user *argp)
  {
  	NodeName_type NodeName;
  	unsigned long flags;
  	int i;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1332

4f43f32cd   Stephen M. Cameron   cciss: factor out...
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
  	if (!argp)
  		return -EINVAL;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (copy_from_user(NodeName, argp, sizeof(NodeName_type)))
  		return -EFAULT;
  	spin_lock_irqsave(&h->lock, flags);
  	/* Update the field, and then ring the doorbell */
  	for (i = 0; i < 16; i++)
  		writeb(NodeName[i], &h->cfgtable->ServerName[i]);
  	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
  	for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
  		if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
  			break;
  		udelay(1000); /* delay and try again */
  	}
  	spin_unlock_irqrestore(&h->lock, flags);
  	if (i >= MAX_IOCTL_CONFIG_WAIT)
  		return -EAGAIN;
  	return 0;
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1354

93c749311   Stephen M. Cameron   cciss: factor out...
1355
1356
1357
  static int cciss_getheartbeat(ctlr_info_t *h, void __user *argp)
  {
  	Heartbeat_type heartbeat;
03f47e888   Stephen M. Cameron   cciss: fix broken...
1358
  	unsigned long flags;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1359

93c749311   Stephen M. Cameron   cciss: factor out...
1360
1361
  	if (!argp)
  		return -EINVAL;
03f47e888   Stephen M. Cameron   cciss: fix broken...
1362
  	spin_lock_irqsave(&h->lock, flags);
93c749311   Stephen M. Cameron   cciss: factor out...
1363
  	heartbeat = readl(&h->cfgtable->HeartBeat);
03f47e888   Stephen M. Cameron   cciss: fix broken...
1364
  	spin_unlock_irqrestore(&h->lock, flags);
93c749311   Stephen M. Cameron   cciss: factor out...
1365
1366
1367
1368
  	if (copy_to_user(argp, &heartbeat, sizeof(Heartbeat_type)))
  		return -EFAULT;
  	return 0;
  }
0a9279cc7   Mike Miller   cciss: kernel sca...
1369

d18dfad4e   Stephen M. Cameron   cciss: factor out...
1370
1371
1372
  static int cciss_getbustypes(ctlr_info_t *h, void __user *argp)
  {
  	BusTypes_type BusTypes;
03f47e888   Stephen M. Cameron   cciss: fix broken...
1373
  	unsigned long flags;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1374

d18dfad4e   Stephen M. Cameron   cciss: factor out...
1375
1376
  	if (!argp)
  		return -EINVAL;
03f47e888   Stephen M. Cameron   cciss: fix broken...
1377
  	spin_lock_irqsave(&h->lock, flags);
d18dfad4e   Stephen M. Cameron   cciss: factor out...
1378
  	BusTypes = readl(&h->cfgtable->BusTypes);
03f47e888   Stephen M. Cameron   cciss: fix broken...
1379
  	spin_unlock_irqrestore(&h->lock, flags);
d18dfad4e   Stephen M. Cameron   cciss: factor out...
1380
1381
1382
1383
  	if (copy_to_user(argp, &BusTypes, sizeof(BusTypes_type)))
  		return -EFAULT;
  	return 0;
  }
8a4f7fbfd   Stephen M. Cameron   cciss: factor out...
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
  static int cciss_getfirmver(ctlr_info_t *h, void __user *argp)
  {
  	FirmwareVer_type firmware;
  
  	if (!argp)
  		return -EINVAL;
  	memcpy(firmware, h->firm_ver, 4);
  
  	if (copy_to_user
  	    (argp, firmware, sizeof(FirmwareVer_type)))
  		return -EFAULT;
  	return 0;
  }
c525919dd   Stephen M. Cameron   cciss: factor out...
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
  static int cciss_getdrivver(ctlr_info_t *h, void __user *argp)
  {
  	DriverVer_type DriverVer = DRIVER_VERSION;
  
  	if (!argp)
  		return -EINVAL;
  	if (copy_to_user(argp, &DriverVer, sizeof(DriverVer_type)))
  		return -EFAULT;
  	return 0;
  }
0894b32c5   Stephen M. Cameron   cciss: factor out...
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
  static int cciss_getluninfo(ctlr_info_t *h,
  	struct gendisk *disk, void __user *argp)
  {
  	LogvolInfo_struct luninfo;
  	drive_info_struct *drv = get_drv(disk);
  
  	if (!argp)
  		return -EINVAL;
  	memcpy(&luninfo.LunID, drv->LunID, sizeof(luninfo.LunID));
  	luninfo.num_opens = drv->usage_count;
  	luninfo.num_parts = 0;
  	if (copy_to_user(argp, &luninfo, sizeof(LogvolInfo_struct)))
  		return -EFAULT;
  	return 0;
  }
f32f125b1   Stephen M. Cameron   cciss: factor out...
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
  static int cciss_passthru(ctlr_info_t *h, void __user *argp)
  {
  	IOCTL_Command_struct iocommand;
  	CommandList_struct *c;
  	char *buff = NULL;
  	u64bit temp64;
  	DECLARE_COMPLETION_ONSTACK(wait);
  
  	if (!argp)
  		return -EINVAL;
  
  	if (!capable(CAP_SYS_RAWIO))
  		return -EPERM;
  
  	if (copy_from_user
  	    (&iocommand, argp, sizeof(IOCTL_Command_struct)))
  		return -EFAULT;
  	if ((iocommand.buf_size < 1) &&
  	    (iocommand.Request.Type.Direction != XFER_NONE)) {
  		return -EINVAL;
  	}
  	if (iocommand.buf_size > 0) {
  		buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
  		if (buff == NULL)
  			return -EFAULT;
  	}
  	if (iocommand.Request.Type.Direction == XFER_WRITE) {
  		/* Copy the data into the buffer we created */
  		if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) {
  			kfree(buff);
  			return -EFAULT;
  		}
  	} else {
  		memset(buff, 0, iocommand.buf_size);
  	}
  	c = cmd_special_alloc(h);
  	if (!c) {
  		kfree(buff);
  		return -ENOMEM;
  	}
  	/* Fill in the command type */
  	c->cmd_type = CMD_IOCTL_PEND;
  	/* Fill in Command Header */
  	c->Header.ReplyQueue = 0;   /* unused in simple mode */
  	if (iocommand.buf_size > 0) { /* buffer to fill */
  		c->Header.SGList = 1;
  		c->Header.SGTotal = 1;
  	} else { /* no buffers to fill */
  		c->Header.SGList = 0;
  		c->Header.SGTotal = 0;
  	}
  	c->Header.LUN = iocommand.LUN_info;
  	/* use the kernel address the cmd block for tag */
  	c->Header.Tag.lower = c->busaddr;
  
  	/* Fill in Request block */
  	c->Request = iocommand.Request;
  
  	/* Fill in the scatter gather information */
  	if (iocommand.buf_size > 0) {
  		temp64.val = pci_map_single(h->pdev, buff,
  			iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
  		c->SG[0].Addr.lower = temp64.val32.lower;
  		c->SG[0].Addr.upper = temp64.val32.upper;
  		c->SG[0].Len = iocommand.buf_size;
  		c->SG[0].Ext = 0;  /* we are not chaining */
  	}
  	c->waiting = &wait;
  
  	enqueue_cmd_and_start_io(h, c);
  	wait_for_completion(&wait);
  
  	/* unlock the buffers from DMA */
  	temp64.val32.lower = c->SG[0].Addr.lower;
  	temp64.val32.upper = c->SG[0].Addr.upper;
  	pci_unmap_single(h->pdev, (dma_addr_t) temp64.val, iocommand.buf_size,
  			 PCI_DMA_BIDIRECTIONAL);
  	check_ioctl_unit_attention(h, c);
  
  	/* Copy the error information out */
  	iocommand.error_info = *(c->err_info);
  	if (copy_to_user(argp, &iocommand, sizeof(IOCTL_Command_struct))) {
  		kfree(buff);
  		cmd_special_free(h, c);
  		return -EFAULT;
  	}
  
  	if (iocommand.Request.Type.Direction == XFER_READ) {
  		/* Copy the data out of the buffer we created */
  		if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1512
  			kfree(buff);
6b4d96b87   Stephen M. Cameron   cciss: separate c...
1513
  			cmd_special_free(h, c);
f32f125b1   Stephen M. Cameron   cciss: factor out...
1514
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1515
  		}
f32f125b1   Stephen M. Cameron   cciss: factor out...
1516
1517
1518
1519
1520
  	}
  	kfree(buff);
  	cmd_special_free(h, c);
  	return 0;
  }
0c9f5ba7c   Stephen M. Cameron   cciss: factor out...
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
  static int cciss_bigpassthru(ctlr_info_t *h, void __user *argp)
  {
  	BIG_IOCTL_Command_struct *ioc;
  	CommandList_struct *c;
  	unsigned char **buff = NULL;
  	int *buff_size = NULL;
  	u64bit temp64;
  	BYTE sg_used = 0;
  	int status = 0;
  	int i;
  	DECLARE_COMPLETION_ONSTACK(wait);
  	__u32 left;
  	__u32 sz;
  	BYTE __user *data_ptr;
  
  	if (!argp)
  		return -EINVAL;
  	if (!capable(CAP_SYS_RAWIO))
  		return -EPERM;
fcab1c112   Stephen M. Cameron   cciss: remove unn...
1540
  	ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);
0c9f5ba7c   Stephen M. Cameron   cciss: factor out...
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
  	if (!ioc) {
  		status = -ENOMEM;
  		goto cleanup1;
  	}
  	if (copy_from_user(ioc, argp, sizeof(*ioc))) {
  		status = -EFAULT;
  		goto cleanup1;
  	}
  	if ((ioc->buf_size < 1) &&
  	    (ioc->Request.Type.Direction != XFER_NONE)) {
  		status = -EINVAL;
  		goto cleanup1;
  	}
  	/* Check kmalloc limits  using all SGs */
  	if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
  		status = -EINVAL;
  		goto cleanup1;
  	}
  	if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
  		status = -EINVAL;
  		goto cleanup1;
  	}
  	buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
  	if (!buff) {
  		status = -ENOMEM;
  		goto cleanup1;
  	}
  	buff_size = kmalloc(MAXSGENTRIES * sizeof(int), GFP_KERNEL);
  	if (!buff_size) {
  		status = -ENOMEM;
  		goto cleanup1;
  	}
  	left = ioc->buf_size;
  	data_ptr = ioc->buf;
  	while (left) {
  		sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
  		buff_size[sg_used] = sz;
  		buff[sg_used] = kmalloc(sz, GFP_KERNEL);
  		if (buff[sg_used] == NULL) {
  			status = -ENOMEM;
  			goto cleanup1;
  		}
  		if (ioc->Request.Type.Direction == XFER_WRITE) {
  			if (copy_from_user(buff[sg_used], data_ptr, sz)) {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1585
1586
1587
  				status = -EFAULT;
  				goto cleanup1;
  			}
0c9f5ba7c   Stephen M. Cameron   cciss: factor out...
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
  		} else {
  			memset(buff[sg_used], 0, sz);
  		}
  		left -= sz;
  		data_ptr += sz;
  		sg_used++;
  	}
  	c = cmd_special_alloc(h);
  	if (!c) {
  		status = -ENOMEM;
  		goto cleanup1;
  	}
  	c->cmd_type = CMD_IOCTL_PEND;
  	c->Header.ReplyQueue = 0;
fcfb5c0ce   Stephen M. Cameron   cciss: remove som...
1602
1603
  	c->Header.SGList = sg_used;
  	c->Header.SGTotal = sg_used;
0c9f5ba7c   Stephen M. Cameron   cciss: factor out...
1604
1605
1606
1607
  	c->Header.LUN = ioc->LUN_info;
  	c->Header.Tag.lower = c->busaddr;
  
  	c->Request = ioc->Request;
fcfb5c0ce   Stephen M. Cameron   cciss: remove som...
1608
1609
  	for (i = 0; i < sg_used; i++) {
  		temp64.val = pci_map_single(h->pdev, buff[i], buff_size[i],
0c9f5ba7c   Stephen M. Cameron   cciss: factor out...
1610
  				    PCI_DMA_BIDIRECTIONAL);
fcfb5c0ce   Stephen M. Cameron   cciss: remove som...
1611
1612
1613
1614
  		c->SG[i].Addr.lower = temp64.val32.lower;
  		c->SG[i].Addr.upper = temp64.val32.upper;
  		c->SG[i].Len = buff_size[i];
  		c->SG[i].Ext = 0;	/* we are not chaining */
0c9f5ba7c   Stephen M. Cameron   cciss: factor out...
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
  	}
  	c->waiting = &wait;
  	enqueue_cmd_and_start_io(h, c);
  	wait_for_completion(&wait);
  	/* unlock the buffers from DMA */
  	for (i = 0; i < sg_used; i++) {
  		temp64.val32.lower = c->SG[i].Addr.lower;
  		temp64.val32.upper = c->SG[i].Addr.upper;
  		pci_unmap_single(h->pdev,
  			(dma_addr_t) temp64.val, buff_size[i],
  			PCI_DMA_BIDIRECTIONAL);
  	}
  	check_ioctl_unit_attention(h, c);
  	/* Copy the error information out */
  	ioc->error_info = *(c->err_info);
  	if (copy_to_user(argp, ioc, sizeof(*ioc))) {
  		cmd_special_free(h, c);
  		status = -EFAULT;
  		goto cleanup1;
  	}
  	if (ioc->Request.Type.Direction == XFER_READ) {
  		/* Copy the data out of the buffer we created */
  		BYTE __user *ptr = ioc->buf;
  		for (i = 0; i < sg_used; i++) {
  			if (copy_to_user(ptr, buff[i], buff_size[i])) {
6b4d96b87   Stephen M. Cameron   cciss: separate c...
1640
  				cmd_special_free(h, c);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1641
1642
1643
  				status = -EFAULT;
  				goto cleanup1;
  			}
0c9f5ba7c   Stephen M. Cameron   cciss: factor out...
1644
  			ptr += buff_size[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1645
  		}
0c9f5ba7c   Stephen M. Cameron   cciss: factor out...
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
  	}
  	cmd_special_free(h, c);
  	status = 0;
  cleanup1:
  	if (buff) {
  		for (i = 0; i < sg_used; i++)
  			kfree(buff[i]);
  		kfree(buff);
  	}
  	kfree(buff_size);
  	kfree(ioc);
  	return status;
  }
ef7822c2f   Al Viro   [PATCH] switch cciss
1659
  static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
c525919dd   Stephen M. Cameron   cciss: factor out...
1660
  	unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1661
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1662
  	struct gendisk *disk = bdev->bd_disk;
f70dba836   Stephen M. Cameron   cciss: use consis...
1663
  	ctlr_info_t *h = get_host(disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1664
  	void __user *argp = (void __user *)arg;
b2a4a43db   Stephen M. Cameron   cciss: change pri...
1665
1666
1667
  	dev_dbg(&h->pdev->dev, "cciss_ioctl: Called with cmd=%x %lx
  ",
  		cmd, arg);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1668
  	switch (cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1669
  	case CCISS_GETPCIINFO:
0a25a5aee   Stephen M. Cameron   cciss: factor out...
1670
  		return cciss_getpciinfo(h, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1671
  	case CCISS_GETINTINFO:
576e661c6   Stephen M. Cameron   cciss: factor out...
1672
  		return cciss_getintinfo(h, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1673
  	case CCISS_SETINTINFO:
4c800eed9   Stephen M. Cameron   cciss: factor out...
1674
  		return cciss_setintinfo(h, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1675
  	case CCISS_GETNODENAME:
252161094   Stephen M. Cameron   cciss: factor out...
1676
  		return cciss_getnodename(h, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
  	case CCISS_SETNODENAME:
4f43f32cd   Stephen M. Cameron   cciss: factor out...
1678
  		return cciss_setnodename(h, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679
  	case CCISS_GETHEARTBEAT:
93c749311   Stephen M. Cameron   cciss: factor out...
1680
  		return cciss_getheartbeat(h, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1681
  	case CCISS_GETBUSTYPES:
d18dfad4e   Stephen M. Cameron   cciss: factor out...
1682
  		return cciss_getbustypes(h, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1683
  	case CCISS_GETFIRMVER:
8a4f7fbfd   Stephen M. Cameron   cciss: factor out...
1684
  		return cciss_getfirmver(h, argp);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1685
  	case CCISS_GETDRIVVER:
c525919dd   Stephen M. Cameron   cciss: factor out...
1686
  		return cciss_getdrivver(h, argp);
6ae5ce8e8   Mike Miller   cciss: remove red...
1687
1688
  	case CCISS_DEREGDISK:
  	case CCISS_REGNEWD:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1689
  	case CCISS_REVALIDVOLS:
f70dba836   Stephen M. Cameron   cciss: use consis...
1690
  		return rebuild_lun_table(h, 0, 1);
0894b32c5   Stephen M. Cameron   cciss: factor out...
1691
1692
  	case CCISS_GETLUNINFO:
  		return cciss_getluninfo(h, disk, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1693
  	case CCISS_PASSTHRU:
f32f125b1   Stephen M. Cameron   cciss: factor out...
1694
  		return cciss_passthru(h, argp);
0c9f5ba7c   Stephen M. Cameron   cciss: factor out...
1695
1696
  	case CCISS_BIG_PASSTHRU:
  		return cciss_bigpassthru(h, argp);
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
1697

577ebb374   Paolo Bonzini   block: add and us...
1698
  	/* scsi_cmd_blk_ioctl handles these, below, though some are not */
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
  	/* very meaningful for cciss.  SG_IO is the main one people want. */
  
  	case SG_GET_VERSION_NUM:
  	case SG_SET_TIMEOUT:
  	case SG_GET_TIMEOUT:
  	case SG_GET_RESERVED_SIZE:
  	case SG_SET_RESERVED_SIZE:
  	case SG_EMULATED_HOST:
  	case SG_IO:
  	case SCSI_IOCTL_SEND_COMMAND:
577ebb374   Paolo Bonzini   block: add and us...
1709
  		return scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
1710

577ebb374   Paolo Bonzini   block: add and us...
1711
  	/* scsi_cmd_blk_ioctl would normally handle these, below, but */
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
1712
1713
1714
1715
1716
1717
1718
1719
1720
  	/* they aren't a good fit for cciss, as CD-ROMs are */
  	/* not supported, and we don't have any bus/target/lun */
  	/* which we present to the kernel. */
  
  	case CDROM_SEND_PACKET:
  	case CDROMCLOSETRAY:
  	case CDROMEJECT:
  	case SCSI_IOCTL_GET_IDLUN:
  	case SCSI_IOCTL_GET_BUS_NUMBER:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1721
1722
1723
  	default:
  		return -ENOTTY;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1724
  }
7b30f0924   Jens Axboe   [PATCH] cciss: fi...
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
  static void cciss_check_queues(ctlr_info_t *h)
  {
  	int start_queue = h->next_to_run;
  	int i;
  
  	/* check to see if we have maxed out the number of commands that can
  	 * be placed on the queue.  If so then exit.  We do this check here
  	 * in case the interrupt we serviced was from an ioctl and did not
  	 * free any new commands.
  	 */
f880632f9   Mike Miller   [PATCH] cciss: in...
1735
  	if ((find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds)) == h->nr_cmds)
7b30f0924   Jens Axboe   [PATCH] cciss: fi...
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
  		return;
  
  	/* We have room on the queue for more commands.  Now we need to queue
  	 * them up.  We will also keep track of the next queue to run so
  	 * that every queue gets a chance to be started first.
  	 */
  	for (i = 0; i < h->highest_lun + 1; i++) {
  		int curr_queue = (start_queue + i) % (h->highest_lun + 1);
  		/* make sure the disk has been added and the drive is real
  		 * because this can be called from the middle of init_one.
  		 */
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
1747
1748
1749
1750
  		if (!h->drv[curr_queue])
  			continue;
  		if (!(h->drv[curr_queue]->queue) ||
  			!(h->drv[curr_queue]->heads))
7b30f0924   Jens Axboe   [PATCH] cciss: fi...
1751
1752
1753
1754
1755
1756
  			continue;
  		blk_start_queue(h->gendisk[curr_queue]->queue);
  
  		/* check to see if we have maxed out the number of commands
  		 * that can be placed on the queue.
  		 */
f880632f9   Mike Miller   [PATCH] cciss: in...
1757
  		if ((find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds)) == h->nr_cmds) {
7b30f0924   Jens Axboe   [PATCH] cciss: fi...
1758
1759
1760
1761
1762
1763
1764
1765
  			if (curr_queue == start_queue) {
  				h->next_to_run =
  				    (start_queue + 1) % (h->highest_lun + 1);
  				break;
  			} else {
  				h->next_to_run = curr_queue;
  				break;
  			}
7b30f0924   Jens Axboe   [PATCH] cciss: fi...
1766
1767
1768
  		}
  	}
  }
ca1e0484d   Mike Miller   [PATCH] cciss: bu...
1769
1770
  static void cciss_softirq_done(struct request *rq)
  {
f70dba836   Stephen M. Cameron   cciss: use consis...
1771
1772
1773
  	CommandList_struct *c = rq->completion_data;
  	ctlr_info_t *h = hba[c->ctlr];
  	SGDescriptor_struct *curr_sg = c->SG;
ca1e0484d   Mike Miller   [PATCH] cciss: bu...
1774
  	u64bit temp64;
664a717d3   Mike Miller   cciss: enqueue an...
1775
  	unsigned long flags;
ca1e0484d   Mike Miller   [PATCH] cciss: bu...
1776
  	int i, ddir;
5c07a311a   Don Brace   cciss: Add enhanc...
1777
  	int sg_index = 0;
ca1e0484d   Mike Miller   [PATCH] cciss: bu...
1778

f70dba836   Stephen M. Cameron   cciss: use consis...
1779
  	if (c->Request.Type.Direction == XFER_READ)
ca1e0484d   Mike Miller   [PATCH] cciss: bu...
1780
1781
1782
1783
1784
1785
  		ddir = PCI_DMA_FROMDEVICE;
  	else
  		ddir = PCI_DMA_TODEVICE;
  
  	/* command did not need to be retried */
  	/* unmap the DMA mapping for all the scatter gather elements */
f70dba836   Stephen M. Cameron   cciss: use consis...
1786
  	for (i = 0; i < c->Header.SGList; i++) {
5c07a311a   Don Brace   cciss: Add enhanc...
1787
  		if (curr_sg[sg_index].Ext == CCISS_SG_CHAIN) {
f70dba836   Stephen M. Cameron   cciss: use consis...
1788
  			cciss_unmap_sg_chain_block(h, c);
5c07a311a   Don Brace   cciss: Add enhanc...
1789
  			/* Point to the next block */
f70dba836   Stephen M. Cameron   cciss: use consis...
1790
  			curr_sg = h->cmd_sg_list[c->cmdindex];
5c07a311a   Don Brace   cciss: Add enhanc...
1791
1792
1793
1794
1795
1796
1797
  			sg_index = 0;
  		}
  		temp64.val32.lower = curr_sg[sg_index].Addr.lower;
  		temp64.val32.upper = curr_sg[sg_index].Addr.upper;
  		pci_unmap_page(h->pdev, temp64.val, curr_sg[sg_index].Len,
  				ddir);
  		++sg_index;
ca1e0484d   Mike Miller   [PATCH] cciss: bu...
1798
  	}
b2a4a43db   Stephen M. Cameron   cciss: change pri...
1799
1800
  	dev_dbg(&h->pdev->dev, "Done with %p
  ", rq);
ca1e0484d   Mike Miller   [PATCH] cciss: bu...
1801

c3a4d78c5   Tejun Heo   block: add rq->re...
1802
  	/* set the residual count for pc requests */
33659ebba   Christoph Hellwig   block: remove wra...
1803
  	if (rq->cmd_type == REQ_TYPE_BLOCK_PC)
f70dba836   Stephen M. Cameron   cciss: use consis...
1804
  		rq->resid_len = c->err_info->ResidualCnt;
ac44e5b2e   Jens Axboe   cciss: fix residu...
1805

c3a4d78c5   Tejun Heo   block: add rq->re...
1806
  	blk_end_request_all(rq, (rq->errors == 0) ? 0 : -EIO);
3daeea29f   Kiyoshi Ueda   blk_end_request: ...
1807

ca1e0484d   Mike Miller   [PATCH] cciss: bu...
1808
  	spin_lock_irqsave(&h->lock, flags);
6b4d96b87   Stephen M. Cameron   cciss: separate c...
1809
  	cmd_free(h, c);
7b30f0924   Jens Axboe   [PATCH] cciss: fi...
1810
  	cciss_check_queues(h);
ca1e0484d   Mike Miller   [PATCH] cciss: bu...
1811
1812
  	spin_unlock_irqrestore(&h->lock, flags);
  }
39ccf9a64   Stephen M. Cameron   cciss: Preserve a...
1813
1814
  static inline void log_unit_to_scsi3addr(ctlr_info_t *h,
  	unsigned char scsi3addr[], uint32_t log_unit)
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
1815
  {
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
1816
1817
  	memcpy(scsi3addr, h->drv[log_unit]->LunID,
  		sizeof(h->drv[log_unit]->LunID));
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
1818
  }
7fe063268   Andrew Patterson   cciss: add cciss ...
1819
1820
1821
1822
  /* This function gets the SCSI vendor, model, and revision of a logical drive
   * via the inquiry page 0.  Model, vendor, and rev are set to empty strings if
   * they cannot be read.
   */
f70dba836   Stephen M. Cameron   cciss: use consis...
1823
  static void cciss_get_device_descr(ctlr_info_t *h, int logvol,
7fe063268   Andrew Patterson   cciss: add cciss ...
1824
1825
1826
1827
  				   char *vendor, char *model, char *rev)
  {
  	int rc;
  	InquiryData_struct *inq_buf;
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
1828
  	unsigned char scsi3addr[8];
7fe063268   Andrew Patterson   cciss: add cciss ...
1829
1830
1831
1832
1833
1834
1835
1836
  
  	*vendor = '\0';
  	*model = '\0';
  	*rev = '\0';
  
  	inq_buf = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL);
  	if (!inq_buf)
  		return;
f70dba836   Stephen M. Cameron   cciss: use consis...
1837
1838
  	log_unit_to_scsi3addr(h, scsi3addr, logvol);
  	rc = sendcmd_withirq(h, CISS_INQUIRY, inq_buf, sizeof(*inq_buf), 0,
7b838bde9   Stephen M. Cameron   cciss: Remove the...
1839
  			scsi3addr, TYPE_CMD);
7fe063268   Andrew Patterson   cciss: add cciss ...
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
  	if (rc == IO_OK) {
  		memcpy(vendor, &inq_buf->data_byte[8], VENDOR_LEN);
  		vendor[VENDOR_LEN] = '\0';
  		memcpy(model, &inq_buf->data_byte[16], MODEL_LEN);
  		model[MODEL_LEN] = '\0';
  		memcpy(rev, &inq_buf->data_byte[32], REV_LEN);
  		rev[REV_LEN] = '\0';
  	}
  
  	kfree(inq_buf);
  	return;
  }
a72da29b6   Mike Miller   cciss: make rebui...
1852
1853
1854
1855
1856
  /* This function gets the serial number of a logical drive via
   * inquiry page 0x83.  Serial no. is 16 bytes.  If the serial
   * number cannot be had, for whatever reason, 16 bytes of 0xff
   * are returned instead.
   */
f70dba836   Stephen M. Cameron   cciss: use consis...
1857
  static void cciss_get_serial_no(ctlr_info_t *h, int logvol,
a72da29b6   Mike Miller   cciss: make rebui...
1858
1859
1860
1861
1862
  				unsigned char *serial_no, int buflen)
  {
  #define PAGE_83_INQ_BYTES 64
  	int rc;
  	unsigned char *buf;
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
1863
  	unsigned char scsi3addr[8];
a72da29b6   Mike Miller   cciss: make rebui...
1864
1865
1866
1867
1868
1869
1870
1871
  
  	if (buflen > 16)
  		buflen = 16;
  	memset(serial_no, 0xff, buflen);
  	buf = kzalloc(PAGE_83_INQ_BYTES, GFP_KERNEL);
  	if (!buf)
  		return;
  	memset(serial_no, 0, buflen);
f70dba836   Stephen M. Cameron   cciss: use consis...
1872
1873
  	log_unit_to_scsi3addr(h, scsi3addr, logvol);
  	rc = sendcmd_withirq(h, CISS_INQUIRY, buf,
7b838bde9   Stephen M. Cameron   cciss: Remove the...
1874
  		PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD);
a72da29b6   Mike Miller   cciss: make rebui...
1875
1876
1877
1878
1879
  	if (rc == IO_OK)
  		memcpy(serial_no, &buf[8], buflen);
  	kfree(buf);
  	return;
  }
617e13442   Stephen M. Cameron   cciss: Dynamicall...
1880
1881
1882
1883
  /*
   * cciss_add_disk sets up the block device queue for a logical drive
   */
  static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
6ae5ce8e8   Mike Miller   cciss: remove red...
1884
1885
1886
  				int drv_index)
  {
  	disk->queue = blk_init_queue(do_cciss_request, &h->lock);
e8074f797   Stephen M. Cameron   cciss: Handle fai...
1887
1888
  	if (!disk->queue)
  		goto init_queue_failure;
6ae5ce8e8   Mike Miller   cciss: remove red...
1889
1890
1891
1892
  	sprintf(disk->disk_name, "cciss/c%dd%d", h->ctlr, drv_index);
  	disk->major = h->major;
  	disk->first_minor = drv_index << NWD_SHIFT;
  	disk->fops = &cciss_fops;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
1893
1894
1895
1896
  	if (cciss_create_ld_sysfs_entry(h, drv_index))
  		goto cleanup_queue;
  	disk->private_data = h->drv[drv_index];
  	disk->driverfs_dev = &h->drv[drv_index]->dev;
6ae5ce8e8   Mike Miller   cciss: remove red...
1897
1898
1899
1900
1901
  
  	/* Set up queue information */
  	blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask);
  
  	/* This is a hardware imposed limit. */
8a78362c4   Martin K. Petersen   block: Consolidat...
1902
  	blk_queue_max_segments(disk->queue, h->maxsgentries);
6ae5ce8e8   Mike Miller   cciss: remove red...
1903

086fa5ff0   Martin K. Petersen   block: Rename blk...
1904
  	blk_queue_max_hw_sectors(disk->queue, h->cciss_max_sectors);
6ae5ce8e8   Mike Miller   cciss: remove red...
1905
1906
1907
1908
  
  	blk_queue_softirq_done(disk->queue, cciss_softirq_done);
  
  	disk->queue->queuedata = h;
e1defc4ff   Martin K. Petersen   block: Do away wi...
1909
  	blk_queue_logical_block_size(disk->queue,
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
1910
  				     h->drv[drv_index]->block_size);
6ae5ce8e8   Mike Miller   cciss: remove red...
1911
1912
  
  	/* Make sure all queue data is written out before */
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
1913
  	/* setting h->drv[drv_index]->queue, as setting this */
6ae5ce8e8   Mike Miller   cciss: remove red...
1914
1915
  	/* allows the interrupt handler to start the queue */
  	wmb();
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
1916
  	h->drv[drv_index]->queue = disk->queue;
6ae5ce8e8   Mike Miller   cciss: remove red...
1917
  	add_disk(disk);
617e13442   Stephen M. Cameron   cciss: Dynamicall...
1918
1919
1920
1921
1922
  	return 0;
  
  cleanup_queue:
  	blk_cleanup_queue(disk->queue);
  	disk->queue = NULL;
e8074f797   Stephen M. Cameron   cciss: Handle fai...
1923
  init_queue_failure:
617e13442   Stephen M. Cameron   cciss: Dynamicall...
1924
  	return -1;
6ae5ce8e8   Mike Miller   cciss: remove red...
1925
  }
ddd474420   Mike Miller   [PATCH] cciss: ne...
1926
  /* This function will check the usage_count of the drive to be updated/added.
a72da29b6   Mike Miller   cciss: make rebui...
1927
1928
1929
1930
1931
1932
1933
1934
   * If the usage_count is zero and it is a heretofore unknown drive, or,
   * the drive's capacity, geometry, or serial number has changed,
   * then the drive information will be updated and the disk will be
   * re-registered with the kernel.  If these conditions don't hold,
   * then it will be left alone for the next reboot.  The exception to this
   * is disk 0 which will always be left registered with the kernel since it
   * is also the controller node.  Any changes to disk 0 will show up on
   * the next reboot.
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1935
   */
f70dba836   Stephen M. Cameron   cciss: use consis...
1936
1937
  static void cciss_update_drive_info(ctlr_info_t *h, int drv_index,
  	int first_time, int via_ioctl)
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
1938
  {
ddd474420   Mike Miller   [PATCH] cciss: ne...
1939
  	struct gendisk *disk;
ddd474420   Mike Miller   [PATCH] cciss: ne...
1940
1941
  	InquiryData_struct *inq_buff = NULL;
  	unsigned int block_size;
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
1942
  	sector_t total_size;
ddd474420   Mike Miller   [PATCH] cciss: ne...
1943
1944
  	unsigned long flags = 0;
  	int ret = 0;
a72da29b6   Mike Miller   cciss: make rebui...
1945
1946
1947
1948
  	drive_info_struct *drvinfo;
  
  	/* Get information about the disk and modify the driver structure */
  	inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
1949
  	drvinfo = kzalloc(sizeof(*drvinfo), GFP_KERNEL);
a72da29b6   Mike Miller   cciss: make rebui...
1950
1951
1952
1953
1954
  	if (inq_buff == NULL || drvinfo == NULL)
  		goto mem_msg;
  
  	/* testing to see if 16-byte CDBs are already being used */
  	if (h->cciss_read == CCISS_READ_16) {
f70dba836   Stephen M. Cameron   cciss: use consis...
1955
  		cciss_read_capacity_16(h, drv_index,
a72da29b6   Mike Miller   cciss: make rebui...
1956
1957
1958
  			&total_size, &block_size);
  
  	} else {
f70dba836   Stephen M. Cameron   cciss: use consis...
1959
  		cciss_read_capacity(h, drv_index, &total_size, &block_size);
a72da29b6   Mike Miller   cciss: make rebui...
1960
1961
1962
1963
  		/* if read_capacity returns all F's this volume is >2TB */
  		/* in size so we switch to 16-byte CDB's for all */
  		/* read/write ops */
  		if (total_size == 0xFFFFFFFFULL) {
f70dba836   Stephen M. Cameron   cciss: use consis...
1964
  			cciss_read_capacity_16(h, drv_index,
a72da29b6   Mike Miller   cciss: make rebui...
1965
1966
1967
1968
1969
1970
1971
1972
  			&total_size, &block_size);
  			h->cciss_read = CCISS_READ_16;
  			h->cciss_write = CCISS_WRITE_16;
  		} else {
  			h->cciss_read = CCISS_READ_10;
  			h->cciss_write = CCISS_WRITE_10;
  		}
  	}
f70dba836   Stephen M. Cameron   cciss: use consis...
1973
  	cciss_geometry_inquiry(h, drv_index, total_size, block_size,
a72da29b6   Mike Miller   cciss: make rebui...
1974
1975
1976
  			       inq_buff, drvinfo);
  	drvinfo->block_size = block_size;
  	drvinfo->nr_blocks = total_size + 1;
f70dba836   Stephen M. Cameron   cciss: use consis...
1977
  	cciss_get_device_descr(h, drv_index, drvinfo->vendor,
7fe063268   Andrew Patterson   cciss: add cciss ...
1978
  				drvinfo->model, drvinfo->rev);
f70dba836   Stephen M. Cameron   cciss: use consis...
1979
  	cciss_get_serial_no(h, drv_index, drvinfo->serial_no,
a72da29b6   Mike Miller   cciss: make rebui...
1980
  			sizeof(drvinfo->serial_no));
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
1981
1982
1983
  	/* Save the lunid in case we deregister the disk, below. */
  	memcpy(drvinfo->LunID, h->drv[drv_index]->LunID,
  		sizeof(drvinfo->LunID));
a72da29b6   Mike Miller   cciss: make rebui...
1984
1985
  
  	/* Is it the same disk we already know, and nothing's changed? */
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
1986
  	if (h->drv[drv_index]->raid_level != -1 &&
a72da29b6   Mike Miller   cciss: make rebui...
1987
  		((memcmp(drvinfo->serial_no,
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
1988
1989
1990
1991
1992
1993
  				h->drv[drv_index]->serial_no, 16) == 0) &&
  		drvinfo->block_size == h->drv[drv_index]->block_size &&
  		drvinfo->nr_blocks == h->drv[drv_index]->nr_blocks &&
  		drvinfo->heads == h->drv[drv_index]->heads &&
  		drvinfo->sectors == h->drv[drv_index]->sectors &&
  		drvinfo->cylinders == h->drv[drv_index]->cylinders))
a72da29b6   Mike Miller   cciss: make rebui...
1994
1995
  			/* The disk is unchanged, nothing to update */
  			goto freeret;
a72da29b6   Mike Miller   cciss: make rebui...
1996

6ae5ce8e8   Mike Miller   cciss: remove red...
1997
1998
1999
2000
2001
2002
  	/* If we get here it's not the same disk, or something's changed,
  	 * so we need to * deregister it, and re-register it, if it's not
  	 * in use.
  	 * If the disk already exists then deregister it before proceeding
  	 * (unless it's the first disk (for the controller node).
  	 */
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2003
  	if (h->drv[drv_index]->raid_level != -1 && drv_index != 0) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2004
2005
  		dev_warn(&h->pdev->dev, "disk %d has changed.
  ", drv_index);
f70dba836   Stephen M. Cameron   cciss: use consis...
2006
  		spin_lock_irqsave(&h->lock, flags);
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2007
  		h->drv[drv_index]->busy_configuring = 1;
f70dba836   Stephen M. Cameron   cciss: use consis...
2008
  		spin_unlock_irqrestore(&h->lock, flags);
e14ac6702   scameron@beardog.cca.cpqcorp.net   cciss: Fix race b...
2009

9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2010
  		/* deregister_disk sets h->drv[drv_index]->queue = NULL
6ae5ce8e8   Mike Miller   cciss: remove red...
2011
2012
2013
  		 * which keeps the interrupt handler from starting
  		 * the queue.
  		 */
2d11d9931   Stephen M. Cameron   cciss: Fix usage_...
2014
  		ret = deregister_disk(h, drv_index, 0, via_ioctl);
ddd474420   Mike Miller   [PATCH] cciss: ne...
2015
2016
2017
2018
  	}
  
  	/* If the disk is in use return */
  	if (ret)
a72da29b6   Mike Miller   cciss: make rebui...
2019
  		goto freeret;
6ae5ce8e8   Mike Miller   cciss: remove red...
2020
  	/* Save the new information from cciss_geometry_inquiry
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2021
2022
  	 * and serial number inquiry.  If the disk was deregistered
  	 * above, then h->drv[drv_index] will be NULL.
6ae5ce8e8   Mike Miller   cciss: remove red...
2023
  	 */
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
  	if (h->drv[drv_index] == NULL) {
  		drvinfo->device_initialized = 0;
  		h->drv[drv_index] = drvinfo;
  		drvinfo = NULL; /* so it won't be freed below. */
  	} else {
  		/* special case for cxd0 */
  		h->drv[drv_index]->block_size = drvinfo->block_size;
  		h->drv[drv_index]->nr_blocks = drvinfo->nr_blocks;
  		h->drv[drv_index]->heads = drvinfo->heads;
  		h->drv[drv_index]->sectors = drvinfo->sectors;
  		h->drv[drv_index]->cylinders = drvinfo->cylinders;
  		h->drv[drv_index]->raid_level = drvinfo->raid_level;
  		memcpy(h->drv[drv_index]->serial_no, drvinfo->serial_no, 16);
  		memcpy(h->drv[drv_index]->vendor, drvinfo->vendor,
  			VENDOR_LEN + 1);
  		memcpy(h->drv[drv_index]->model, drvinfo->model, MODEL_LEN + 1);
  		memcpy(h->drv[drv_index]->rev, drvinfo->rev, REV_LEN + 1);
  	}
ddd474420   Mike Miller   [PATCH] cciss: ne...
2042
2043
2044
  
  	++h->num_luns;
  	disk = h->gendisk[drv_index];
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2045
  	set_capacity(disk, h->drv[drv_index]->nr_blocks);
ddd474420   Mike Miller   [PATCH] cciss: ne...
2046

6ae5ce8e8   Mike Miller   cciss: remove red...
2047
2048
2049
2050
2051
2052
  	/* If it's not disk 0 (drv_index != 0)
  	 * or if it was disk 0, but there was previously
  	 * no actual corresponding configured logical drive
  	 * (raid_leve == -1) then we want to update the
  	 * logical drive's information.
  	 */
361e9b07d   Stephen M. Cameron   cciss: Handle cas...
2053
2054
2055
  	if (drv_index || first_time) {
  		if (cciss_add_disk(h, disk, drv_index) != 0) {
  			cciss_free_gendisk(h, drv_index);
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2056
  			cciss_free_drive_info(h, drv_index);
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2057
2058
2059
  			dev_warn(&h->pdev->dev, "could not update disk %d
  ",
  				drv_index);
361e9b07d   Stephen M. Cameron   cciss: Handle cas...
2060
2061
2062
  			--h->num_luns;
  		}
  	}
ddd474420   Mike Miller   [PATCH] cciss: ne...
2063

6ae5ce8e8   Mike Miller   cciss: remove red...
2064
  freeret:
ddd474420   Mike Miller   [PATCH] cciss: ne...
2065
  	kfree(inq_buff);
a72da29b6   Mike Miller   cciss: make rebui...
2066
  	kfree(drvinfo);
ddd474420   Mike Miller   [PATCH] cciss: ne...
2067
  	return;
6ae5ce8e8   Mike Miller   cciss: remove red...
2068
  mem_msg:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2069
2070
  	dev_err(&h->pdev->dev, "out of memory
  ");
ddd474420   Mike Miller   [PATCH] cciss: ne...
2071
2072
2073
2074
  	goto freeret;
  }
  
  /* This function will find the first index of the controllers drive array
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2075
2076
2077
2078
2079
2080
2081
2082
   * that has a null drv pointer and allocate the drive info struct and
   * will return that index   This is where new drives will be added.
   * If the index to be returned is greater than the highest_lun index for
   * the controller then highest_lun is set * to this new index.
   * If there are no available indexes or if tha allocation fails, then -1
   * is returned.  * "controller_node" is used to know if this is a real
   * logical drive, or just the controller node, which determines if this
   * counts towards highest_lun.
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2083
   */
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2084
  static int cciss_alloc_drive_info(ctlr_info_t *h, int controller_node)
ddd474420   Mike Miller   [PATCH] cciss: ne...
2085
2086
  {
  	int i;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2087
  	drive_info_struct *drv;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2088

9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2089
  	/* Search for an empty slot for our drive info */
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2090
  	for (i = 0; i < CISS_MAX_LUN; i++) {
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
  
  		/* if not cxd0 case, and it's occupied, skip it. */
  		if (h->drv[i] && i != 0)
  			continue;
  		/*
  		 * If it's cxd0 case, and drv is alloc'ed already, and a
  		 * disk is configured there, skip it.
  		 */
  		if (i == 0 && h->drv[i] && h->drv[i]->raid_level != -1)
  			continue;
  
  		/*
  		 * We've found an empty slot.  Update highest_lun
  		 * provided this isn't just the fake cxd0 controller node.
  		 */
  		if (i > h->highest_lun && !controller_node)
  			h->highest_lun = i;
  
  		/* If adding a real disk at cxd0, and it's already alloc'ed */
  		if (i == 0 && h->drv[i] != NULL)
ddd474420   Mike Miller   [PATCH] cciss: ne...
2111
  			return i;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
  
  		/*
  		 * Found an empty slot, not already alloc'ed.  Allocate it.
  		 * Mark it with raid_level == -1, so we know it's new later on.
  		 */
  		drv = kzalloc(sizeof(*drv), GFP_KERNEL);
  		if (!drv)
  			return -1;
  		drv->raid_level = -1; /* so we know it's new */
  		h->drv[i] = drv;
  		return i;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2123
2124
2125
  	}
  	return -1;
  }
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2126
2127
2128
2129
2130
  static void cciss_free_drive_info(ctlr_info_t *h, int drv_index)
  {
  	kfree(h->drv[drv_index]);
  	h->drv[drv_index] = NULL;
  }
361e9b07d   Stephen M. Cameron   cciss: Handle cas...
2131
2132
2133
2134
2135
  static void cciss_free_gendisk(ctlr_info_t *h, int drv_index)
  {
  	put_disk(h->gendisk[drv_index]);
  	h->gendisk[drv_index] = NULL;
  }
6ae5ce8e8   Mike Miller   cciss: remove red...
2136
2137
2138
2139
2140
2141
2142
2143
2144
  /* cciss_add_gendisk finds a free hba[]->drv structure
   * and allocates a gendisk if needed, and sets the lunid
   * in the drvinfo structure.   It returns the index into
   * the ->drv[] array, or -1 if none are free.
   * is_controller_node indicates whether highest_lun should
   * count this disk, or if it's only being added to provide
   * a means to talk to the controller in case no logical
   * drives have yet been configured.
   */
39ccf9a64   Stephen M. Cameron   cciss: Preserve a...
2145
2146
  static int cciss_add_gendisk(ctlr_info_t *h, unsigned char lunid[],
  	int controller_node)
6ae5ce8e8   Mike Miller   cciss: remove red...
2147
2148
  {
  	int drv_index;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2149
  	drv_index = cciss_alloc_drive_info(h, controller_node);
6ae5ce8e8   Mike Miller   cciss: remove red...
2150
2151
  	if (drv_index == -1)
  		return -1;
8ce51966d   Stephen M. Cameron   cciss: Handle spe...
2152

6ae5ce8e8   Mike Miller   cciss: remove red...
2153
2154
2155
2156
2157
  	/*Check if the gendisk needs to be allocated */
  	if (!h->gendisk[drv_index]) {
  		h->gendisk[drv_index] =
  			alloc_disk(1 << NWD_SHIFT);
  		if (!h->gendisk[drv_index]) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2158
2159
2160
2161
  			dev_err(&h->pdev->dev,
  				"could not allocate a new disk %d
  ",
  				drv_index);
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2162
  			goto err_free_drive_info;
6ae5ce8e8   Mike Miller   cciss: remove red...
2163
2164
  		}
  	}
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2165
2166
2167
  	memcpy(h->drv[drv_index]->LunID, lunid,
  		sizeof(h->drv[drv_index]->LunID));
  	if (cciss_create_ld_sysfs_entry(h, drv_index))
7fe063268   Andrew Patterson   cciss: add cciss ...
2168
  		goto err_free_disk;
6ae5ce8e8   Mike Miller   cciss: remove red...
2169
2170
2171
  	/* Don't need to mark this busy because nobody */
  	/* else knows about this disk yet to contend */
  	/* for access to it. */
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2172
  	h->drv[drv_index]->busy_configuring = 0;
6ae5ce8e8   Mike Miller   cciss: remove red...
2173
2174
  	wmb();
  	return drv_index;
7fe063268   Andrew Patterson   cciss: add cciss ...
2175
2176
  
  err_free_disk:
361e9b07d   Stephen M. Cameron   cciss: Handle cas...
2177
  	cciss_free_gendisk(h, drv_index);
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2178
2179
  err_free_drive_info:
  	cciss_free_drive_info(h, drv_index);
7fe063268   Andrew Patterson   cciss: add cciss ...
2180
  	return -1;
6ae5ce8e8   Mike Miller   cciss: remove red...
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
  }
  
  /* This is for the special case of a controller which
   * has no logical drives.  In this case, we still need
   * to register a disk so the controller can be accessed
   * by the Array Config Utility.
   */
  static void cciss_add_controller_node(ctlr_info_t *h)
  {
  	struct gendisk *disk;
  	int drv_index;
  
  	if (h->gendisk[0] != NULL) /* already did this? Then bail. */
  		return;
39ccf9a64   Stephen M. Cameron   cciss: Preserve a...
2195
  	drv_index = cciss_add_gendisk(h, CTLR_LUNID, 1);
361e9b07d   Stephen M. Cameron   cciss: Handle cas...
2196
2197
  	if (drv_index == -1)
  		goto error;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2198
2199
2200
2201
2202
2203
2204
  	h->drv[drv_index]->block_size = 512;
  	h->drv[drv_index]->nr_blocks = 0;
  	h->drv[drv_index]->heads = 0;
  	h->drv[drv_index]->sectors = 0;
  	h->drv[drv_index]->cylinders = 0;
  	h->drv[drv_index]->raid_level = -1;
  	memset(h->drv[drv_index]->serial_no, 0, 16);
6ae5ce8e8   Mike Miller   cciss: remove red...
2205
  	disk = h->gendisk[drv_index];
361e9b07d   Stephen M. Cameron   cciss: Handle cas...
2206
2207
2208
  	if (cciss_add_disk(h, disk, drv_index) == 0)
  		return;
  	cciss_free_gendisk(h, drv_index);
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2209
  	cciss_free_drive_info(h, drv_index);
361e9b07d   Stephen M. Cameron   cciss: Handle cas...
2210
  error:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2211
2212
  	dev_warn(&h->pdev->dev, "could not add disk 0.
  ");
361e9b07d   Stephen M. Cameron   cciss: Handle cas...
2213
  	return;
6ae5ce8e8   Mike Miller   cciss: remove red...
2214
  }
ddd474420   Mike Miller   [PATCH] cciss: ne...
2215
  /* This function will add and remove logical drives from the Logical
d14c4ab58   Bjorn Helgaas   [PATCH] CCISS: fi...
2216
   * drive array of the controller and maintain persistency of ordering
ddd474420   Mike Miller   [PATCH] cciss: ne...
2217
2218
2219
2220
2221
   * so that mount points are preserved until the next reboot.  This allows
   * for the removal of logical drives in the middle of the drive array
   * without a re-ordering of those drives.
   * INPUT
   * h		= The controller to perform the operations on
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2222
   */
2d11d9931   Stephen M. Cameron   cciss: Fix usage_...
2223
2224
  static int rebuild_lun_table(ctlr_info_t *h, int first_time,
  	int via_ioctl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2225
  {
ddd474420   Mike Miller   [PATCH] cciss: ne...
2226
2227
  	int num_luns;
  	ReportLunData_struct *ld_buff = NULL;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2228
2229
2230
2231
2232
  	int return_code;
  	int listlength = 0;
  	int i;
  	int drv_found;
  	int drv_index = 0;
39ccf9a64   Stephen M. Cameron   cciss: Preserve a...
2233
  	unsigned char lunid[8] = CTLR_LUNID;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2234
  	unsigned long flags;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2235

6ae5ce8e8   Mike Miller   cciss: remove red...
2236
2237
  	if (!capable(CAP_SYS_RAWIO))
  		return -EPERM;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2238
  	/* Set busy_configuring flag for this operation */
f70dba836   Stephen M. Cameron   cciss: use consis...
2239
  	spin_lock_irqsave(&h->lock, flags);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2240
  	if (h->busy_configuring) {
f70dba836   Stephen M. Cameron   cciss: use consis...
2241
  		spin_unlock_irqrestore(&h->lock, flags);
ddd474420   Mike Miller   [PATCH] cciss: ne...
2242
2243
2244
  		return -EBUSY;
  	}
  	h->busy_configuring = 1;
f70dba836   Stephen M. Cameron   cciss: use consis...
2245
  	spin_unlock_irqrestore(&h->lock, flags);
ddd474420   Mike Miller   [PATCH] cciss: ne...
2246

a72da29b6   Mike Miller   cciss: make rebui...
2247
2248
2249
  	ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
  	if (ld_buff == NULL)
  		goto mem_msg;
f70dba836   Stephen M. Cameron   cciss: use consis...
2250
  	return_code = sendcmd_withirq(h, CISS_REPORT_LOG, ld_buff,
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
2251
2252
  				      sizeof(ReportLunData_struct),
  				      0, CTLR_LUNID, TYPE_CMD);
ddd474420   Mike Miller   [PATCH] cciss: ne...
2253

a72da29b6   Mike Miller   cciss: make rebui...
2254
2255
2256
  	if (return_code == IO_OK)
  		listlength = be32_to_cpu(*(__be32 *) ld_buff->LUNListLength);
  	else {	/* reading number of logical volumes failed */
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2257
2258
2259
  		dev_warn(&h->pdev->dev,
  			"report logical volume command failed
  ");
a72da29b6   Mike Miller   cciss: make rebui...
2260
2261
2262
2263
2264
2265
2266
  		listlength = 0;
  		goto freeret;
  	}
  
  	num_luns = listlength / 8;	/* 8 bytes per entry */
  	if (num_luns > CISS_MAX_LUN) {
  		num_luns = CISS_MAX_LUN;
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2267
  		dev_warn(&h->pdev->dev, "more luns configured"
a72da29b6   Mike Miller   cciss: make rebui...
2268
2269
2270
2271
  		       " on controller than can be handled by"
  		       " this driver.
  ");
  	}
6ae5ce8e8   Mike Miller   cciss: remove red...
2272
2273
2274
2275
2276
2277
2278
2279
  	if (num_luns == 0)
  		cciss_add_controller_node(h);
  
  	/* Compare controller drive array to driver's drive array
  	 * to see if any drives are missing on the controller due
  	 * to action of Array Config Utility (user deletes drive)
  	 * and deregister logical drives which have disappeared.
  	 */
a72da29b6   Mike Miller   cciss: make rebui...
2280
2281
2282
  	for (i = 0; i <= h->highest_lun; i++) {
  		int j;
  		drv_found = 0;
d8a0be6ab   Stephen M. Cameron   cciss: fix proble...
2283
2284
  
  		/* skip holes in the array from already deleted drives */
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2285
  		if (h->drv[i] == NULL)
d8a0be6ab   Stephen M. Cameron   cciss: fix proble...
2286
  			continue;
a72da29b6   Mike Miller   cciss: make rebui...
2287
  		for (j = 0; j < num_luns; j++) {
39ccf9a64   Stephen M. Cameron   cciss: Preserve a...
2288
  			memcpy(lunid, &ld_buff->LUN[j][0], sizeof(lunid));
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2289
  			if (memcmp(h->drv[i]->LunID, lunid,
39ccf9a64   Stephen M. Cameron   cciss: Preserve a...
2290
  				sizeof(lunid)) == 0) {
a72da29b6   Mike Miller   cciss: make rebui...
2291
2292
2293
2294
2295
2296
  				drv_found = 1;
  				break;
  			}
  		}
  		if (!drv_found) {
  			/* Deregister it from the OS, it's gone. */
f70dba836   Stephen M. Cameron   cciss: use consis...
2297
  			spin_lock_irqsave(&h->lock, flags);
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2298
  			h->drv[i]->busy_configuring = 1;
f70dba836   Stephen M. Cameron   cciss: use consis...
2299
  			spin_unlock_irqrestore(&h->lock, flags);
2d11d9931   Stephen M. Cameron   cciss: Fix usage_...
2300
  			return_code = deregister_disk(h, i, 1, via_ioctl);
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2301
2302
  			if (h->drv[i] != NULL)
  				h->drv[i]->busy_configuring = 0;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2303
  		}
a72da29b6   Mike Miller   cciss: make rebui...
2304
  	}
ddd474420   Mike Miller   [PATCH] cciss: ne...
2305

a72da29b6   Mike Miller   cciss: make rebui...
2306
2307
2308
2309
2310
2311
2312
  	/* Compare controller drive array to driver's drive array.
  	 * Check for updates in the drive information and any new drives
  	 * on the controller due to ACU adding logical drives, or changing
  	 * a logical drive's size, etc.  Reregister any new/changed drives
  	 */
  	for (i = 0; i < num_luns; i++) {
  		int j;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2313

a72da29b6   Mike Miller   cciss: make rebui...
2314
  		drv_found = 0;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2315

39ccf9a64   Stephen M. Cameron   cciss: Preserve a...
2316
  		memcpy(lunid, &ld_buff->LUN[i][0], sizeof(lunid));
a72da29b6   Mike Miller   cciss: make rebui...
2317
2318
2319
2320
2321
2322
  		/* Find if the LUN is already in the drive array
  		 * of the driver.  If so then update its info
  		 * if not in use.  If it does not exist then find
  		 * the first free index and add it.
  		 */
  		for (j = 0; j <= h->highest_lun; j++) {
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2323
2324
2325
  			if (h->drv[j] != NULL &&
  				memcmp(h->drv[j]->LunID, lunid,
  					sizeof(h->drv[j]->LunID)) == 0) {
a72da29b6   Mike Miller   cciss: make rebui...
2326
2327
2328
  				drv_index = j;
  				drv_found = 1;
  				break;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2329
  			}
a72da29b6   Mike Miller   cciss: make rebui...
2330
  		}
ddd474420   Mike Miller   [PATCH] cciss: ne...
2331

a72da29b6   Mike Miller   cciss: make rebui...
2332
2333
  		/* check if the drive was found already in the array */
  		if (!drv_found) {
eece695f8   Mike Miller   cciss: fix negati...
2334
  			drv_index = cciss_add_gendisk(h, lunid, 0);
a72da29b6   Mike Miller   cciss: make rebui...
2335
2336
  			if (drv_index == -1)
  				goto freeret;
a72da29b6   Mike Miller   cciss: make rebui...
2337
  		}
f70dba836   Stephen M. Cameron   cciss: use consis...
2338
  		cciss_update_drive_info(h, drv_index, first_time, via_ioctl);
a72da29b6   Mike Miller   cciss: make rebui...
2339
  	}		/* end for */
ddd474420   Mike Miller   [PATCH] cciss: ne...
2340

6ae5ce8e8   Mike Miller   cciss: remove red...
2341
  freeret:
ddd474420   Mike Miller   [PATCH] cciss: ne...
2342
2343
2344
2345
2346
  	kfree(ld_buff);
  	h->busy_configuring = 0;
  	/* We return -1 here to tell the ACU that we have registered/updated
  	 * all of the drives that we can and to keep it from calling us
  	 * additional times.
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2347
  	 */
ddd474420   Mike Miller   [PATCH] cciss: ne...
2348
  	return -1;
6ae5ce8e8   Mike Miller   cciss: remove red...
2349
  mem_msg:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2350
2351
  	dev_err(&h->pdev->dev, "out of memory
  ");
a72da29b6   Mike Miller   cciss: make rebui...
2352
  	h->busy_configuring = 0;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2353
2354
  	goto freeret;
  }
9ddb27b44   Stephen M. Cameron   cciss: Clear all ...
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
  static void cciss_clear_drive_info(drive_info_struct *drive_info)
  {
  	/* zero out the disk size info */
  	drive_info->nr_blocks = 0;
  	drive_info->block_size = 0;
  	drive_info->heads = 0;
  	drive_info->sectors = 0;
  	drive_info->cylinders = 0;
  	drive_info->raid_level = -1;
  	memset(drive_info->serial_no, 0, sizeof(drive_info->serial_no));
  	memset(drive_info->model, 0, sizeof(drive_info->model));
  	memset(drive_info->rev, 0, sizeof(drive_info->rev));
  	memset(drive_info->vendor, 0, sizeof(drive_info->vendor));
  	/*
  	 * don't clear the LUNID though, we need to remember which
  	 * one this one is.
  	 */
  }
ddd474420   Mike Miller   [PATCH] cciss: ne...
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
  /* This function will deregister the disk and it's queue from the
   * kernel.  It must be called with the controller lock held and the
   * drv structures busy_configuring flag set.  It's parameters are:
   *
   * disk = This is the disk to be deregistered
   * drv  = This is the drive_info_struct associated with the disk to be
   *        deregistered.  It contains information about the disk used
   *        by the driver.
   * clear_all = This flag determines whether or not the disk information
   *             is going to be completely cleared out and the highest_lun
   *             reset.  Sometimes we want to clear out information about
d14c4ab58   Bjorn Helgaas   [PATCH] CCISS: fi...
2384
   *             the disk in preparation for re-adding it.  In this case
ddd474420   Mike Miller   [PATCH] cciss: ne...
2385
2386
   *             the highest_lun should be left unchanged and the LunID
   *             should not be cleared.
2d11d9931   Stephen M. Cameron   cciss: Fix usage_...
2387
2388
2389
2390
2391
2392
   * via_ioctl
   *    This indicates whether we've reached this path via ioctl.
   *    This affects the maximum usage count allowed for c0d0 to be messed with.
   *    If this path is reached via ioctl(), then the max_usage_count will
   *    be 1, as the process calling ioctl() has got to have the device open.
   *    If we get here via sysfs, then the max usage count will be zero.
ddd474420   Mike Miller   [PATCH] cciss: ne...
2393
  */
a0ea86229   Stephen M. Cameron   cciss: simplify p...
2394
  static int deregister_disk(ctlr_info_t *h, int drv_index,
2d11d9931   Stephen M. Cameron   cciss: Fix usage_...
2395
  			   int clear_all, int via_ioctl)
ddd474420   Mike Miller   [PATCH] cciss: ne...
2396
  {
799202cbd   Mike Miller   [PATCH] cciss: ad...
2397
  	int i;
a0ea86229   Stephen M. Cameron   cciss: simplify p...
2398
2399
  	struct gendisk *disk;
  	drive_info_struct *drv;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2400
  	int recalculate_highest_lun;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2401
2402
2403
  
  	if (!capable(CAP_SYS_RAWIO))
  		return -EPERM;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2404
  	drv = h->drv[drv_index];
a0ea86229   Stephen M. Cameron   cciss: simplify p...
2405
  	disk = h->gendisk[drv_index];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2406
  	/* make sure logical volume is NOT is use */
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2407
  	if (clear_all || (h->gendisk[0] == disk)) {
2d11d9931   Stephen M. Cameron   cciss: Fix usage_...
2408
  		if (drv->usage_count > via_ioctl)
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2409
2410
2411
  			return -EBUSY;
  	} else if (drv->usage_count > 0)
  		return -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2412

9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2413
  	recalculate_highest_lun = (drv == h->drv[h->highest_lun]);
ddd474420   Mike Miller   [PATCH] cciss: ne...
2414
2415
2416
  	/* invalidate the devices and deregister the disk.  If it is disk
  	 * zero do not deregister it but just zero out it's values.  This
  	 * allows us to delete disk zero but keep the controller registered.
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2417
2418
  	 */
  	if (h->gendisk[0] != disk) {
5a9df732b   Adrian Bunk   drivers/block/cci...
2419
  		struct request_queue *q = disk->queue;
097d02645   Stephen M. Cameron   cciss: Rearrange ...
2420
  		if (disk->flags & GENHD_FL_UP) {
8ce51966d   Stephen M. Cameron   cciss: Handle spe...
2421
  			cciss_destroy_ld_sysfs_entry(h, drv_index, 0);
5a9df732b   Adrian Bunk   drivers/block/cci...
2422
  			del_gendisk(disk);
5a9df732b   Adrian Bunk   drivers/block/cci...
2423
  		}
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2424
  		if (q)
5a9df732b   Adrian Bunk   drivers/block/cci...
2425
  			blk_cleanup_queue(q);
5a9df732b   Adrian Bunk   drivers/block/cci...
2426
2427
2428
2429
2430
  		/* If clear_all is set then we are deleting the logical
  		 * drive, not just refreshing its info.  For drives
  		 * other than disk 0 we will call put_disk.  We do not
  		 * do this for disk 0 as we need it to be able to
  		 * configure the controller.
a72da29b6   Mike Miller   cciss: make rebui...
2431
  		 */
5a9df732b   Adrian Bunk   drivers/block/cci...
2432
2433
2434
2435
2436
  		if (clear_all){
  			/* This isn't pretty, but we need to find the
  			 * disk in our array and NULL our the pointer.
  			 * This is so that we will call alloc_disk if
  			 * this index is used again later.
a72da29b6   Mike Miller   cciss: make rebui...
2437
  			 */
5a9df732b   Adrian Bunk   drivers/block/cci...
2438
  			for (i=0; i < CISS_MAX_LUN; i++){
a72da29b6   Mike Miller   cciss: make rebui...
2439
  				if (h->gendisk[i] == disk) {
5a9df732b   Adrian Bunk   drivers/block/cci...
2440
2441
  					h->gendisk[i] = NULL;
  					break;
799202cbd   Mike Miller   [PATCH] cciss: ad...
2442
  				}
799202cbd   Mike Miller   [PATCH] cciss: ad...
2443
  			}
5a9df732b   Adrian Bunk   drivers/block/cci...
2444
  			put_disk(disk);
ddd474420   Mike Miller   [PATCH] cciss: ne...
2445
  		}
799202cbd   Mike Miller   [PATCH] cciss: ad...
2446
2447
  	} else {
  		set_capacity(disk, 0);
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2448
  		cciss_clear_drive_info(drv);
ddd474420   Mike Miller   [PATCH] cciss: ne...
2449
2450
2451
  	}
  
  	--h->num_luns;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2452

9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2453
2454
  	/* if it was the last disk, find the new hightest lun */
  	if (clear_all && recalculate_highest_lun) {
c2d45b4da   Bill Pemberton   cciss: fix shadow...
2455
  		int newhighest = -1;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2456
2457
2458
2459
  		for (i = 0; i <= h->highest_lun; i++) {
  			/* if the disk has size > 0, it is available */
  			if (h->drv[i] && h->drv[i]->heads)
  				newhighest = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2460
  		}
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2461
  		h->highest_lun = newhighest;
ddd474420   Mike Miller   [PATCH] cciss: ne...
2462
  	}
e2019b58f   Bjorn Helgaas   [PATCH] CCISS: re...
2463
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2464
  }
ddd474420   Mike Miller   [PATCH] cciss: ne...
2465

f70dba836   Stephen M. Cameron   cciss: use consis...
2466
  static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
2467
2468
  		size_t size, __u8 page_code, unsigned char *scsi3addr,
  		int cmd_type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2469
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2470
2471
2472
2473
2474
  	u64bit buff_dma_handle;
  	int status = IO_OK;
  
  	c->cmd_type = CMD_IOCTL_PEND;
  	c->Header.ReplyQueue = 0;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2475
  	if (buff != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2476
  		c->Header.SGList = 1;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2477
  		c->Header.SGTotal = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2478
2479
  	} else {
  		c->Header.SGList = 0;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2480
  		c->Header.SGTotal = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2481
2482
  	}
  	c->Header.Tag.lower = c->busaddr;
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
2483
  	memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2484
2485
2486
  
  	c->Request.Type.Type = cmd_type;
  	if (cmd_type == TYPE_CMD) {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2487
2488
  		switch (cmd) {
  		case CISS_INQUIRY:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2489
  			/* are we trying to read a vital product page */
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2490
  			if (page_code != 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2491
2492
2493
2494
  				c->Request.CDB[1] = 0x01;
  				c->Request.CDB[2] = page_code;
  			}
  			c->Request.CDBLen = 6;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2495
  			c->Request.Type.Attribute = ATTR_SIMPLE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2496
2497
  			c->Request.Type.Direction = XFER_READ;
  			c->Request.Timeout = 0;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2498
2499
2500
  			c->Request.CDB[0] = CISS_INQUIRY;
  			c->Request.CDB[4] = size & 0xFF;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2501
2502
  		case CISS_REPORT_LOG:
  		case CISS_REPORT_PHYS:
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2503
  			/* Talking to controller so It's a physical command
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2504
  			   mode = 00 target = 0.  Nothing to write.
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2505
  			 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2506
2507
2508
2509
2510
  			c->Request.CDBLen = 12;
  			c->Request.Type.Attribute = ATTR_SIMPLE;
  			c->Request.Type.Direction = XFER_READ;
  			c->Request.Timeout = 0;
  			c->Request.CDB[0] = cmd;
b028461d6   dann frazier   cciss: remove C99...
2511
  			c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2512
2513
2514
2515
2516
2517
  			c->Request.CDB[7] = (size >> 16) & 0xFF;
  			c->Request.CDB[8] = (size >> 8) & 0xFF;
  			c->Request.CDB[9] = size & 0xFF;
  			break;
  
  		case CCISS_READ_CAPACITY:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2518
2519
2520
2521
2522
  			c->Request.CDBLen = 10;
  			c->Request.Type.Attribute = ATTR_SIMPLE;
  			c->Request.Type.Direction = XFER_READ;
  			c->Request.Timeout = 0;
  			c->Request.CDB[0] = cmd;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2523
  			break;
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2524
  		case CCISS_READ_CAPACITY_16:
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
  			c->Request.CDBLen = 16;
  			c->Request.Type.Attribute = ATTR_SIMPLE;
  			c->Request.Type.Direction = XFER_READ;
  			c->Request.Timeout = 0;
  			c->Request.CDB[0] = cmd;
  			c->Request.CDB[1] = 0x10;
  			c->Request.CDB[10] = (size >> 24) & 0xFF;
  			c->Request.CDB[11] = (size >> 16) & 0xFF;
  			c->Request.CDB[12] = (size >> 8) & 0xFF;
  			c->Request.CDB[13] = size & 0xFF;
  			c->Request.Timeout = 0;
  			c->Request.CDB[0] = cmd;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2538
2539
2540
2541
2542
2543
2544
  		case CCISS_CACHE_FLUSH:
  			c->Request.CDBLen = 12;
  			c->Request.Type.Attribute = ATTR_SIMPLE;
  			c->Request.Type.Direction = XFER_WRITE;
  			c->Request.Timeout = 0;
  			c->Request.CDB[0] = BMIC_WRITE;
  			c->Request.CDB[6] = BMIC_CACHE_FLUSH;
59bd71a81   Stephen M. Cameron   cciss: fix flush ...
2545
2546
  			c->Request.CDB[7] = (size >> 8) & 0xFF;
  			c->Request.CDB[8] = size & 0xFF;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2547
  			break;
88f627ae3   Stephen M. Cameron   cciss: fix SCSI d...
2548
  		case TEST_UNIT_READY:
88f627ae3   Stephen M. Cameron   cciss: fix SCSI d...
2549
2550
2551
2552
2553
  			c->Request.CDBLen = 6;
  			c->Request.Type.Attribute = ATTR_SIMPLE;
  			c->Request.Type.Direction = XFER_NONE;
  			c->Request.Timeout = 0;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2554
  		default:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2555
2556
  			dev_warn(&h->pdev->dev, "Unknown Command 0x%c
  ", cmd);
e2019b58f   Bjorn Helgaas   [PATCH] CCISS: re...
2557
  			return IO_ERROR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2558
2559
2560
  		}
  	} else if (cmd_type == TYPE_MSG) {
  		switch (cmd) {
8f71bb829   Stephen M. Cameron   cciss: get rid of...
2561
  		case CCISS_ABORT_MSG:
3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
2562
2563
2564
2565
  			c->Request.CDBLen = 12;
  			c->Request.Type.Attribute = ATTR_SIMPLE;
  			c->Request.Type.Direction = XFER_WRITE;
  			c->Request.Timeout = 0;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2566
2567
  			c->Request.CDB[0] = cmd;	/* abort */
  			c->Request.CDB[1] = 0;	/* abort a command */
3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
2568
2569
2570
  			/* buff contains the tag of the command to abort */
  			memcpy(&c->Request.CDB[4], buff, 8);
  			break;
8f71bb829   Stephen M. Cameron   cciss: get rid of...
2571
  		case CCISS_RESET_MSG:
88f627ae3   Stephen M. Cameron   cciss: fix SCSI d...
2572
  			c->Request.CDBLen = 16;
3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
2573
  			c->Request.Type.Attribute = ATTR_SIMPLE;
88f627ae3   Stephen M. Cameron   cciss: fix SCSI d...
2574
  			c->Request.Type.Direction = XFER_NONE;
3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
2575
2576
  			c->Request.Timeout = 0;
  			memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2577
  			c->Request.CDB[0] = cmd;	/* reset */
8f71bb829   Stephen M. Cameron   cciss: get rid of...
2578
  			c->Request.CDB[1] = CCISS_RESET_TYPE_TARGET;
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2579
  			break;
8f71bb829   Stephen M. Cameron   cciss: get rid of...
2580
  		case CCISS_NOOP_MSG:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2581
2582
2583
2584
2585
2586
2587
  			c->Request.CDBLen = 1;
  			c->Request.Type.Attribute = ATTR_SIMPLE;
  			c->Request.Type.Direction = XFER_WRITE;
  			c->Request.Timeout = 0;
  			c->Request.CDB[0] = cmd;
  			break;
  		default:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2588
2589
2590
  			dev_warn(&h->pdev->dev,
  				"unknown message type %d
  ", cmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2591
2592
2593
  			return IO_ERROR;
  		}
  	} else {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2594
2595
  		dev_warn(&h->pdev->dev, "unknown command type %d
  ", cmd_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2596
2597
2598
2599
2600
  		return IO_ERROR;
  	}
  	/* Fill in the scatter gather information */
  	if (size > 0) {
  		buff_dma_handle.val = (__u64) pci_map_single(h->pdev,
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2601
2602
  							     buff, size,
  							     PCI_DMA_BIDIRECTIONAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2603
2604
2605
  		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
  		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
  		c->SG[0].Len = size;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2606
  		c->SG[0].Ext = 0;	/* we are not chaining */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2607
2608
2609
  	}
  	return status;
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2610

8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
2611
2612
  static int cciss_send_reset(ctlr_info_t *h, unsigned char *scsi3addr,
  			    u8 reset_type)
edc83d47a   Jens Axboe   cciss: fix compil...
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
  {
  	CommandList_struct *c;
  	int return_status;
  
  	c = cmd_alloc(h);
  	if (!c)
  		return -ENOMEM;
  	return_status = fill_cmd(h, c, CCISS_RESET_MSG, NULL, 0, 0,
  		CTLR_LUNID, TYPE_MSG);
  	c->Request.CDB[1] = reset_type; /* fill_cmd defaults to target reset */
  	if (return_status != IO_OK) {
  		cmd_special_free(h, c);
  		return return_status;
  	}
  	c->waiting = NULL;
  	enqueue_cmd_and_start_io(h, c);
  	/* Don't wait for completion, the reset won't complete.  Don't free
  	 * the command either.  This is the last command we will send before
  	 * re-initializing everything, so it doesn't matter and won't leak.
  	 */
  	return 0;
  }
3c2ab4029   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
  static int check_target_status(ctlr_info_t *h, CommandList_struct *c)
  {
  	switch (c->err_info->ScsiStatus) {
  	case SAM_STAT_GOOD:
  		return IO_OK;
  	case SAM_STAT_CHECK_CONDITION:
  		switch (0xf & c->err_info->SenseInfo[2]) {
  		case 0: return IO_OK; /* no sense */
  		case 1: return IO_OK; /* recovered error */
  		default:
c08fac650   Stephen M. Cameron   cciss: Retry driv...
2645
2646
  			if (check_for_unit_attention(h, c))
  				return IO_NEEDS_RETRY;
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2647
  			dev_warn(&h->pdev->dev, "cmd 0x%02x "
3c2ab4029   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2648
2649
  				"check condition, sense key = 0x%02x
  ",
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2650
  				c->Request.CDB[0], c->err_info->SenseInfo[2]);
3c2ab4029   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2651
2652
2653
  		}
  		break;
  	default:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2654
2655
2656
  		dev_warn(&h->pdev->dev, "cmd 0x%02x"
  			"scsi status = 0x%02x
  ",
3c2ab4029   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2657
2658
2659
2660
2661
  			c->Request.CDB[0], c->err_info->ScsiStatus);
  		break;
  	}
  	return IO_ERROR;
  }
789a424ad   scameron@beardog.cca.cpqcorp.net   cciss: separate e...
2662
  static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2663
  {
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2664
  	int return_status = IO_OK;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2665

789a424ad   scameron@beardog.cca.cpqcorp.net   cciss: separate e...
2666
2667
  	if (c->err_info->CommandStatus == CMD_SUCCESS)
  		return IO_OK;
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2668
2669
2670
  
  	switch (c->err_info->CommandStatus) {
  	case CMD_TARGET_STATUS:
3c2ab4029   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2671
  		return_status = check_target_status(h, c);
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2672
2673
2674
2675
2676
2677
  		break;
  	case CMD_DATA_UNDERRUN:
  	case CMD_DATA_OVERRUN:
  		/* expected for inquiry and report lun commands */
  		break;
  	case CMD_INVALID:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2678
  		dev_warn(&h->pdev->dev, "cmd 0x%02x is "
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2679
2680
2681
2682
2683
  		       "reported invalid
  ", c->Request.CDB[0]);
  		return_status = IO_ERROR;
  		break;
  	case CMD_PROTOCOL_ERR:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2684
2685
2686
  		dev_warn(&h->pdev->dev, "cmd 0x%02x has "
  		       "protocol error
  ", c->Request.CDB[0]);
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2687
2688
2689
  		return_status = IO_ERROR;
  		break;
  	case CMD_HARDWARE_ERR:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2690
  		dev_warn(&h->pdev->dev, "cmd 0x%02x had "
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2691
2692
2693
2694
2695
  		       " hardware error
  ", c->Request.CDB[0]);
  		return_status = IO_ERROR;
  		break;
  	case CMD_CONNECTION_LOST:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2696
  		dev_warn(&h->pdev->dev, "cmd 0x%02x had "
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2697
2698
2699
2700
2701
  		       "connection lost
  ", c->Request.CDB[0]);
  		return_status = IO_ERROR;
  		break;
  	case CMD_ABORTED:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2702
  		dev_warn(&h->pdev->dev, "cmd 0x%02x was "
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2703
2704
2705
2706
2707
  		       "aborted
  ", c->Request.CDB[0]);
  		return_status = IO_ERROR;
  		break;
  	case CMD_ABORT_FAILED:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2708
  		dev_warn(&h->pdev->dev, "cmd 0x%02x reports "
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2709
2710
2711
2712
2713
  		       "abort failed
  ", c->Request.CDB[0]);
  		return_status = IO_ERROR;
  		break;
  	case CMD_UNSOLICITED_ABORT:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2714
2715
  		dev_warn(&h->pdev->dev, "unsolicited abort 0x%02x
  ",
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2716
  			c->Request.CDB[0]);
789a424ad   scameron@beardog.cca.cpqcorp.net   cciss: separate e...
2717
  		return_status = IO_NEEDS_RETRY;
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2718
  		break;
6d9a4f9e2   Stephen M. Cameron   cciss: fix missed...
2719
2720
2721
2722
2723
  	case CMD_UNABORTABLE:
  		dev_warn(&h->pdev->dev, "cmd unabortable
  ");
  		return_status = IO_ERROR;
  		break;
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2724
  	default:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2725
  		dev_warn(&h->pdev->dev, "cmd 0x%02x returned "
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2726
2727
2728
2729
  		       "unknown status %x
  ", c->Request.CDB[0],
  		       c->err_info->CommandStatus);
  		return_status = IO_ERROR;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2730
  	}
789a424ad   scameron@beardog.cca.cpqcorp.net   cciss: separate e...
2731
2732
2733
2734
2735
2736
2737
2738
  	return return_status;
  }
  
  static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
  	int attempt_retry)
  {
  	DECLARE_COMPLETION_ONSTACK(wait);
  	u64bit buff_dma_handle;
789a424ad   scameron@beardog.cca.cpqcorp.net   cciss: separate e...
2739
2740
2741
2742
  	int return_status = IO_OK;
  
  resend_cmd2:
  	c->waiting = &wait;
664a717d3   Mike Miller   cciss: enqueue an...
2743
  	enqueue_cmd_and_start_io(h, c);
789a424ad   scameron@beardog.cca.cpqcorp.net   cciss: separate e...
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
  
  	wait_for_completion(&wait);
  
  	if (c->err_info->CommandStatus == 0 || !attempt_retry)
  		goto command_done;
  
  	return_status = process_sendcmd_error(h, c);
  
  	if (return_status == IO_NEEDS_RETRY &&
  		c->retry_count < MAX_CMD_RETRIES) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2754
2755
  		dev_warn(&h->pdev->dev, "retrying 0x%02x
  ",
789a424ad   scameron@beardog.cca.cpqcorp.net   cciss: separate e...
2756
2757
2758
2759
2760
  			c->Request.CDB[0]);
  		c->retry_count++;
  		/* erase the old error information */
  		memset(c->err_info, 0, sizeof(ErrorInfo_struct));
  		return_status = IO_OK;
16735d022   Wolfram Sang   tree-wide: use re...
2761
  		reinit_completion(&wait);
789a424ad   scameron@beardog.cca.cpqcorp.net   cciss: separate e...
2762
2763
  		goto resend_cmd2;
  	}
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2764
2765
  
  command_done:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2766
  	/* unlock the buffers from DMA */
bb2a37bf4   Mike Miller   [PATCH] cciss: fi...
2767
2768
  	buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
  	buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2769
2770
  	pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val,
  			 c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2771
2772
  	return return_status;
  }
f70dba836   Stephen M. Cameron   cciss: use consis...
2773
  static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size,
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
2774
2775
  			   __u8 page_code, unsigned char scsi3addr[],
  			int cmd_type)
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2776
  {
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2777
2778
  	CommandList_struct *c;
  	int return_status;
6b4d96b87   Stephen M. Cameron   cciss: separate c...
2779
  	c = cmd_special_alloc(h);
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2780
2781
  	if (!c)
  		return -ENOMEM;
f70dba836   Stephen M. Cameron   cciss: use consis...
2782
  	return_status = fill_cmd(h, c, cmd, buff, size, page_code,
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
2783
  		scsi3addr, cmd_type);
5390cfc3f   scameron@beardog.cca.cpqcorp.net   cciss: factor out...
2784
  	if (return_status == IO_OK)
789a424ad   scameron@beardog.cca.cpqcorp.net   cciss: separate e...
2785
  		return_status = sendcmd_withirq_core(h, c, 1);
6b4d96b87   Stephen M. Cameron   cciss: separate c...
2786
  	cmd_special_free(h, c);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2787
  	return return_status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2788
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2789

f70dba836   Stephen M. Cameron   cciss: use consis...
2790
  static void cciss_geometry_inquiry(ctlr_info_t *h, int logvol,
7b838bde9   Stephen M. Cameron   cciss: Remove the...
2791
  				   sector_t total_size,
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2792
2793
2794
  				   unsigned int block_size,
  				   InquiryData_struct *inq_buff,
  				   drive_info_struct *drv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2795
2796
  {
  	int return_code;
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2797
  	unsigned long t;
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
2798
  	unsigned char scsi3addr[8];
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2799

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2800
  	memset(inq_buff, 0, sizeof(InquiryData_struct));
f70dba836   Stephen M. Cameron   cciss: use consis...
2801
2802
  	log_unit_to_scsi3addr(h, scsi3addr, logvol);
  	return_code = sendcmd_withirq(h, CISS_INQUIRY, inq_buff,
7b838bde9   Stephen M. Cameron   cciss: Remove the...
2803
  			sizeof(*inq_buff), 0xC1, scsi3addr, TYPE_CMD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2804
  	if (return_code == IO_OK) {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2805
  		if (inq_buff->data_byte[8] == 0xFF) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2806
2807
  			dev_warn(&h->pdev->dev,
  			       "reading geometry failed, volume "
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2808
2809
  			       "does not support reading geometry
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2810
  			drv->heads = 255;
b028461d6   dann frazier   cciss: remove C99...
2811
  			drv->sectors = 32;	/* Sectors per track */
7f42d3b8a   Mike Miller (OS Dev)   [PATCH] cciss: ad...
2812
  			drv->cylinders = total_size + 1;
89f97ad18   Mike Miller   [PATCH] cciss: se...
2813
  			drv->raid_level = RAID_UNKNOWN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2814
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2815
2816
2817
2818
2819
  			drv->heads = inq_buff->data_byte[6];
  			drv->sectors = inq_buff->data_byte[7];
  			drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8;
  			drv->cylinders += inq_buff->data_byte[5];
  			drv->raid_level = inq_buff->data_byte[8];
3f7705eab   Matthew Wilcox   [PATCH] cciss: Fi...
2820
2821
  		}
  		drv->block_size = block_size;
97c069785   Mike Miller (OS Dev)   [PATCH] cciss: fi...
2822
  		drv->nr_blocks = total_size + 1;
3f7705eab   Matthew Wilcox   [PATCH] cciss: Fi...
2823
2824
  		t = drv->heads * drv->sectors;
  		if (t > 1) {
97c069785   Mike Miller (OS Dev)   [PATCH] cciss: fi...
2825
2826
  			sector_t real_size = total_size + 1;
  			unsigned long rem = sector_div(real_size, t);
3f7705eab   Matthew Wilcox   [PATCH] cciss: Fi...
2827
  			if (rem)
97c069785   Mike Miller (OS Dev)   [PATCH] cciss: fi...
2828
2829
  				real_size++;
  			drv->cylinders = real_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2830
  		}
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2831
  	} else {		/* Get geometry failed */
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2832
2833
  		dev_warn(&h->pdev->dev, "reading geometry failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2834
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2835
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2836

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2837
  static void
f70dba836   Stephen M. Cameron   cciss: use consis...
2838
  cciss_read_capacity(ctlr_info_t *h, int logvol, sector_t *total_size,
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2839
  		    unsigned int *block_size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2840
  {
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2841
  	ReadCapdata_struct *buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2842
  	int return_code;
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
2843
  	unsigned char scsi3addr[8];
1aebe1878   Mariusz Kozlowski   drivers/block/cci...
2844
2845
2846
  
  	buf = kzalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
  	if (!buf) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2847
2848
  		dev_warn(&h->pdev->dev, "out of memory
  ");
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2849
2850
  		return;
  	}
1aebe1878   Mariusz Kozlowski   drivers/block/cci...
2851

f70dba836   Stephen M. Cameron   cciss: use consis...
2852
2853
  	log_unit_to_scsi3addr(h, scsi3addr, logvol);
  	return_code = sendcmd_withirq(h, CCISS_READ_CAPACITY, buf,
7b838bde9   Stephen M. Cameron   cciss: Remove the...
2854
  		sizeof(ReadCapdata_struct), 0, scsi3addr, TYPE_CMD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2855
  	if (return_code == IO_OK) {
4c1f2b316   Al Viro   [PATCH] cciss end...
2856
2857
  		*total_size = be32_to_cpu(*(__be32 *) buf->total_size);
  		*block_size = be32_to_cpu(*(__be32 *) buf->block_size);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2858
  	} else {		/* read capacity command failed */
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2859
2860
  		dev_warn(&h->pdev->dev, "read capacity failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2861
2862
2863
  		*total_size = 0;
  		*block_size = BLOCK_SIZE;
  	}
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2864
  	kfree(buf);
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2865
  }
f70dba836   Stephen M. Cameron   cciss: use consis...
2866
  static void cciss_read_capacity_16(ctlr_info_t *h, int logvol,
7b838bde9   Stephen M. Cameron   cciss: Remove the...
2867
  	sector_t *total_size, unsigned int *block_size)
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2868
2869
2870
  {
  	ReadCapdata_struct_16 *buf;
  	int return_code;
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
2871
  	unsigned char scsi3addr[8];
1aebe1878   Mariusz Kozlowski   drivers/block/cci...
2872
2873
2874
  
  	buf = kzalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
  	if (!buf) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2875
2876
  		dev_warn(&h->pdev->dev, "out of memory
  ");
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2877
2878
  		return;
  	}
1aebe1878   Mariusz Kozlowski   drivers/block/cci...
2879

f70dba836   Stephen M. Cameron   cciss: use consis...
2880
2881
2882
  	log_unit_to_scsi3addr(h, scsi3addr, logvol);
  	return_code = sendcmd_withirq(h, CCISS_READ_CAPACITY_16,
  		buf, sizeof(ReadCapdata_struct_16),
7b838bde9   Stephen M. Cameron   cciss: Remove the...
2883
  			0, scsi3addr, TYPE_CMD);
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2884
  	if (return_code == IO_OK) {
4c1f2b316   Al Viro   [PATCH] cciss end...
2885
2886
  		*total_size = be64_to_cpu(*(__be64 *) buf->total_size);
  		*block_size = be32_to_cpu(*(__be32 *) buf->block_size);
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2887
  	} else {		/* read capacity command failed */
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2888
2889
  		dev_warn(&h->pdev->dev, "read capacity failed
  ");
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2890
2891
2892
  		*total_size = 0;
  		*block_size = BLOCK_SIZE;
  	}
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2893
2894
  	dev_info(&h->pdev->dev, "      blocks= %llu block_size= %d
  ",
97c069785   Mike Miller (OS Dev)   [PATCH] cciss: fi...
2895
  	       (unsigned long long)*total_size+1, *block_size);
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2896
  	kfree(buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2897
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2898
2899
2900
2901
2902
  static int cciss_revalidate(struct gendisk *disk)
  {
  	ctlr_info_t *h = get_host(disk);
  	drive_info_struct *drv = get_drv(disk);
  	int logvol;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2903
  	int FOUND = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2904
  	unsigned int block_size;
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2905
  	sector_t total_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2906
  	InquiryData_struct *inq_buff = NULL;
68264e9d6   Stephen M. Cameron   cciss: make cciss...
2907
  	for (logvol = 0; logvol <= h->highest_lun; logvol++) {
0fc13c899   Stephen M. Cameron   cciss: fix cciss_...
2908
  		if (!h->drv[logvol])
453434cf3   Linus Torvalds   Fix build error i...
2909
  			continue;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
2910
  		if (memcmp(h->drv[logvol]->LunID, drv->LunID,
39ccf9a64   Stephen M. Cameron   cciss: Preserve a...
2911
  			sizeof(drv->LunID)) == 0) {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2912
  			FOUND = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2913
2914
2915
  			break;
  		}
  	}
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2916
2917
  	if (!FOUND)
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2918

7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2919
2920
  	inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
  	if (inq_buff == NULL) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2921
2922
  		dev_warn(&h->pdev->dev, "out of memory
  ");
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2923
2924
  		return 1;
  	}
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2925
  	if (h->cciss_read == CCISS_READ_10) {
f70dba836   Stephen M. Cameron   cciss: use consis...
2926
  		cciss_read_capacity(h, logvol,
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2927
2928
  					&total_size, &block_size);
  	} else {
f70dba836   Stephen M. Cameron   cciss: use consis...
2929
  		cciss_read_capacity_16(h, logvol,
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
2930
2931
  					&total_size, &block_size);
  	}
f70dba836   Stephen M. Cameron   cciss: use consis...
2932
  	cciss_geometry_inquiry(h, logvol, total_size, block_size,
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2933
  			       inq_buff, drv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2934

e1defc4ff   Martin K. Petersen   block: Do away wi...
2935
  	blk_queue_logical_block_size(drv->queue, drv->block_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2936
  	set_capacity(disk, drv->nr_blocks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2937
2938
2939
2940
2941
  	kfree(inq_buff);
  	return 0;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2942
2943
2944
2945
   * Map (physical) PCI mem into (virtual) kernel space
   */
  static void __iomem *remap_pci_mem(ulong base, ulong size)
  {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2946
2947
2948
  	ulong page_base = ((ulong) base) & PAGE_MASK;
  	ulong page_offs = ((ulong) base) - page_base;
  	void __iomem *page_remapped = ioremap(page_base, page_offs + size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2949

7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2950
  	return page_remapped ? (page_remapped + page_offs) : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2951
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2952
2953
2954
2955
2956
  /*
   * Takes jobs of the Q and sends them to the hardware, then puts it on
   * the Q to wait for completion.
   */
  static void start_io(ctlr_info_t *h)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2957
2958
  {
  	CommandList_struct *c;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2959

e6e1ee936   Jens Axboe   cciss: reinstate ...
2960
2961
  	while (!list_empty(&h->reqQ)) {
  		c = list_entry(h->reqQ.next, CommandList_struct, list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2962
2963
  		/* can't do anything if fifo is full */
  		if ((h->access.fifo_full(h))) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
2964
2965
  			dev_warn(&h->pdev->dev, "fifo full
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2966
2967
  			break;
  		}
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2968
  		/* Get the first entry from the Request Q */
8a3173de4   Jens Axboe   cciss: switch to ...
2969
  		removeQ(c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2970
  		h->Qdepth--;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2971
2972
  
  		/* Tell the controller execute command */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2973
  		h->access.submit_command(h, c);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2974
2975
  
  		/* Put job onto the completed Q */
8a3173de4   Jens Axboe   cciss: switch to ...
2976
  		addQ(&h->cmpQ, c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2977
2978
  	}
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2979

f70dba836   Stephen M. Cameron   cciss: use consis...
2980
  /* Assumes that h->lock is held. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2981
2982
  /* Zeros out the error record and then resends the command back */
  /* to the controller */
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2983
  static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2984
2985
2986
2987
2988
  {
  	/* erase the old error information */
  	memset(c->err_info, 0, sizeof(ErrorInfo_struct));
  
  	/* add it to software queue and then send it to the controller */
8a3173de4   Jens Axboe   cciss: switch to ...
2989
  	addQ(&h->reqQ, c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2990
  	h->Qdepth++;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
2991
  	if (h->Qdepth > h->maxQsinceinit)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2992
2993
2994
2995
  		h->maxQsinceinit = h->Qdepth;
  
  	start_io(h);
  }
a9925a06e   Jens Axboe   [BLOCK] CCISS: up...
2996

1a614f505   Steve Cameron   cciss: fix error ...
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
  static inline unsigned int make_status_bytes(unsigned int scsi_status_byte,
  	unsigned int msg_byte, unsigned int host_byte,
  	unsigned int driver_byte)
  {
  	/* inverse of macros in scsi.h */
  	return (scsi_status_byte & 0xff) |
  		((msg_byte & 0xff) << 8) |
  		((host_byte & 0xff) << 16) |
  		((driver_byte & 0xff) << 24);
  }
0a9279cc7   Mike Miller   cciss: kernel sca...
3007
3008
  static inline int evaluate_target_status(ctlr_info_t *h,
  			CommandList_struct *cmd, int *retry_cmd)
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3009
3010
  {
  	unsigned char sense_key;
1a614f505   Steve Cameron   cciss: fix error ...
3011
3012
  	unsigned char status_byte, msg_byte, host_byte, driver_byte;
  	int error_value;
0a9279cc7   Mike Miller   cciss: kernel sca...
3013
  	*retry_cmd = 0;
1a614f505   Steve Cameron   cciss: fix error ...
3014
3015
3016
3017
  	/* If we get in here, it means we got "target status", that is, scsi status */
  	status_byte = cmd->err_info->ScsiStatus;
  	driver_byte = DRIVER_OK;
  	msg_byte = cmd->err_info->CommandStatus; /* correct?  seems too device specific */
33659ebba   Christoph Hellwig   block: remove wra...
3018
  	if (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC)
1a614f505   Steve Cameron   cciss: fix error ...
3019
3020
3021
3022
3023
3024
  		host_byte = DID_PASSTHROUGH;
  	else
  		host_byte = DID_OK;
  
  	error_value = make_status_bytes(status_byte, msg_byte,
  		host_byte, driver_byte);
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3025

1a614f505   Steve Cameron   cciss: fix error ...
3026
  	if (cmd->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) {
33659ebba   Christoph Hellwig   block: remove wra...
3027
  		if (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC)
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3028
  			dev_warn(&h->pdev->dev, "cmd %p "
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3029
3030
3031
  			       "has SCSI Status 0x%x
  ",
  			       cmd, cmd->err_info->ScsiStatus);
1a614f505   Steve Cameron   cciss: fix error ...
3032
  		return error_value;
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3033
3034
3035
3036
3037
  	}
  
  	/* check the sense key */
  	sense_key = 0xf & cmd->err_info->SenseInfo[2];
  	/* no status or recovered error */
33659ebba   Christoph Hellwig   block: remove wra...
3038
3039
  	if (((sense_key == 0x0) || (sense_key == 0x1)) &&
  	    (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC))
1a614f505   Steve Cameron   cciss: fix error ...
3040
  		error_value = 0;
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3041

0a9279cc7   Mike Miller   cciss: kernel sca...
3042
  	if (check_for_unit_attention(h, cmd)) {
33659ebba   Christoph Hellwig   block: remove wra...
3043
  		*retry_cmd = !(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC);
0a9279cc7   Mike Miller   cciss: kernel sca...
3044
3045
  		return 0;
  	}
33659ebba   Christoph Hellwig   block: remove wra...
3046
3047
  	/* Not SG_IO or similar? */
  	if (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC) {
1a614f505   Steve Cameron   cciss: fix error ...
3048
  		if (error_value != 0)
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3049
  			dev_warn(&h->pdev->dev, "cmd %p has CHECK CONDITION"
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3050
3051
  			       " sense key = 0x%x
  ", cmd, sense_key);
1a614f505   Steve Cameron   cciss: fix error ...
3052
  		return error_value;
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
  	}
  
  	/* SG_IO or similar, copy sense data back */
  	if (cmd->rq->sense) {
  		if (cmd->rq->sense_len > cmd->err_info->SenseLen)
  			cmd->rq->sense_len = cmd->err_info->SenseLen;
  		memcpy(cmd->rq->sense, cmd->err_info->SenseInfo,
  			cmd->rq->sense_len);
  	} else
  		cmd->rq->sense_len = 0;
1a614f505   Steve Cameron   cciss: fix error ...
3063
  	return error_value;
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3064
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3065
  /* checks the status of the job and calls complete buffers to mark all
a9925a06e   Jens Axboe   [BLOCK] CCISS: up...
3066
3067
   * buffers for the completed job. Note that this function does not need
   * to hold the hba/queue lock.
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3068
3069
3070
   */
  static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
  				    int timeout)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3071
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3072
  	int retry_cmd = 0;
198b76601   Mike Miller (OS Dev)   cciss: set rq->er...
3073
3074
3075
  	struct request *rq = cmd->rq;
  
  	rq->errors = 0;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3076

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3077
  	if (timeout)
1a614f505   Steve Cameron   cciss: fix error ...
3078
  		rq->errors = make_status_bytes(0, 0, 0, DRIVER_TIMEOUT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3079

d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3080
3081
  	if (cmd->err_info->CommandStatus == 0)	/* no error has occurred */
  		goto after_error_processing;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3082

d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3083
  	switch (cmd->err_info->CommandStatus) {
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3084
  	case CMD_TARGET_STATUS:
0a9279cc7   Mike Miller   cciss: kernel sca...
3085
  		rq->errors = evaluate_target_status(h, cmd, &retry_cmd);
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3086
3087
  		break;
  	case CMD_DATA_UNDERRUN:
33659ebba   Christoph Hellwig   block: remove wra...
3088
  		if (cmd->rq->cmd_type == REQ_TYPE_FS) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3089
  			dev_warn(&h->pdev->dev, "cmd %p has"
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3090
3091
3092
  			       " completed with data underrun "
  			       "reported
  ", cmd);
c3a4d78c5   Tejun Heo   block: add rq->re...
3093
  			cmd->rq->resid_len = cmd->err_info->ResidualCnt;
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3094
  		}
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3095
3096
  		break;
  	case CMD_DATA_OVERRUN:
33659ebba   Christoph Hellwig   block: remove wra...
3097
  		if (cmd->rq->cmd_type == REQ_TYPE_FS)
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3098
  			dev_warn(&h->pdev->dev, "cciss: cmd %p has"
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3099
3100
3101
  			       " completed with data overrun "
  			       "reported
  ", cmd);
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3102
3103
  		break;
  	case CMD_INVALID:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3104
  		dev_warn(&h->pdev->dev, "cciss: cmd %p is "
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3105
3106
  		       "reported invalid
  ", cmd);
1a614f505   Steve Cameron   cciss: fix error ...
3107
3108
  		rq->errors = make_status_bytes(SAM_STAT_GOOD,
  			cmd->err_info->CommandStatus, DRIVER_OK,
33659ebba   Christoph Hellwig   block: remove wra...
3109
3110
  			(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
  				DID_PASSTHROUGH : DID_ERROR);
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3111
3112
  		break;
  	case CMD_PROTOCOL_ERR:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3113
3114
3115
  		dev_warn(&h->pdev->dev, "cciss: cmd %p has "
  		       "protocol error
  ", cmd);
1a614f505   Steve Cameron   cciss: fix error ...
3116
3117
  		rq->errors = make_status_bytes(SAM_STAT_GOOD,
  			cmd->err_info->CommandStatus, DRIVER_OK,
33659ebba   Christoph Hellwig   block: remove wra...
3118
3119
  			(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
  				DID_PASSTHROUGH : DID_ERROR);
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3120
3121
  		break;
  	case CMD_HARDWARE_ERR:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3122
  		dev_warn(&h->pdev->dev, "cciss: cmd %p had "
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3123
3124
  		       " hardware error
  ", cmd);
1a614f505   Steve Cameron   cciss: fix error ...
3125
3126
  		rq->errors = make_status_bytes(SAM_STAT_GOOD,
  			cmd->err_info->CommandStatus, DRIVER_OK,
33659ebba   Christoph Hellwig   block: remove wra...
3127
3128
  			(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
  				DID_PASSTHROUGH : DID_ERROR);
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3129
3130
  		break;
  	case CMD_CONNECTION_LOST:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3131
  		dev_warn(&h->pdev->dev, "cciss: cmd %p had "
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3132
3133
  		       "connection lost
  ", cmd);
1a614f505   Steve Cameron   cciss: fix error ...
3134
3135
  		rq->errors = make_status_bytes(SAM_STAT_GOOD,
  			cmd->err_info->CommandStatus, DRIVER_OK,
33659ebba   Christoph Hellwig   block: remove wra...
3136
3137
  			(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
  				DID_PASSTHROUGH : DID_ERROR);
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3138
3139
  		break;
  	case CMD_ABORTED:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3140
  		dev_warn(&h->pdev->dev, "cciss: cmd %p was "
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3141
3142
  		       "aborted
  ", cmd);
1a614f505   Steve Cameron   cciss: fix error ...
3143
3144
  		rq->errors = make_status_bytes(SAM_STAT_GOOD,
  			cmd->err_info->CommandStatus, DRIVER_OK,
33659ebba   Christoph Hellwig   block: remove wra...
3145
3146
  			(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
  				DID_PASSTHROUGH : DID_ABORT);
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3147
3148
  		break;
  	case CMD_ABORT_FAILED:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3149
  		dev_warn(&h->pdev->dev, "cciss: cmd %p reports "
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3150
3151
  		       "abort failed
  ", cmd);
1a614f505   Steve Cameron   cciss: fix error ...
3152
3153
  		rq->errors = make_status_bytes(SAM_STAT_GOOD,
  			cmd->err_info->CommandStatus, DRIVER_OK,
33659ebba   Christoph Hellwig   block: remove wra...
3154
3155
  			(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
  				DID_PASSTHROUGH : DID_ERROR);
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3156
3157
  		break;
  	case CMD_UNSOLICITED_ABORT:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3158
  		dev_warn(&h->pdev->dev, "cciss%d: unsolicited "
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3159
3160
3161
3162
  		       "abort %p
  ", h->ctlr, cmd);
  		if (cmd->retry_count < MAX_CMD_RETRIES) {
  			retry_cmd = 1;
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3163
3164
  			dev_warn(&h->pdev->dev, "retrying %p
  ", cmd);
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3165
3166
  			cmd->retry_count++;
  		} else
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3167
3168
3169
  			dev_warn(&h->pdev->dev,
  				"%p retried too many times
  ", cmd);
1a614f505   Steve Cameron   cciss: fix error ...
3170
3171
  		rq->errors = make_status_bytes(SAM_STAT_GOOD,
  			cmd->err_info->CommandStatus, DRIVER_OK,
33659ebba   Christoph Hellwig   block: remove wra...
3172
3173
  			(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
  				DID_PASSTHROUGH : DID_ABORT);
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3174
3175
  		break;
  	case CMD_TIMEOUT:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3176
3177
  		dev_warn(&h->pdev->dev, "cmd %p timedout
  ", cmd);
1a614f505   Steve Cameron   cciss: fix error ...
3178
3179
  		rq->errors = make_status_bytes(SAM_STAT_GOOD,
  			cmd->err_info->CommandStatus, DRIVER_OK,
33659ebba   Christoph Hellwig   block: remove wra...
3180
3181
  			(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
  				DID_PASSTHROUGH : DID_ERROR);
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3182
  		break;
6d9a4f9e2   Stephen M. Cameron   cciss: fix missed...
3183
3184
3185
3186
3187
3188
3189
3190
  	case CMD_UNABORTABLE:
  		dev_warn(&h->pdev->dev, "cmd %p unabortable
  ", cmd);
  		rq->errors = make_status_bytes(SAM_STAT_GOOD,
  			cmd->err_info->CommandStatus, DRIVER_OK,
  			cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC ?
  				DID_PASSTHROUGH : DID_ERROR);
  		break;
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3191
  	default:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3192
  		dev_warn(&h->pdev->dev, "cmd %p returned "
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3193
3194
3195
  		       "unknown status %x
  ", cmd,
  		       cmd->err_info->CommandStatus);
1a614f505   Steve Cameron   cciss: fix error ...
3196
3197
  		rq->errors = make_status_bytes(SAM_STAT_GOOD,
  			cmd->err_info->CommandStatus, DRIVER_OK,
33659ebba   Christoph Hellwig   block: remove wra...
3198
3199
  			(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
  				DID_PASSTHROUGH : DID_ERROR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3200
  	}
d38ae168b   Mike Miller (OS Dev)   cciss: reformat e...
3201
3202
  
  after_error_processing:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3203
  	/* We need to return this command */
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3204
3205
  	if (retry_cmd) {
  		resend_cciss_cmd(h, cmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3206
  		return;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3207
  	}
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3208
  	cmd->rq->completion_data = cmd;
a9925a06e   Jens Axboe   [BLOCK] CCISS: up...
3209
  	blk_complete_request(cmd->rq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3210
  }
0c2b39087   Mike Miller   cciss: clean up i...
3211
3212
  static inline u32 cciss_tag_contains_index(u32 tag)
  {
5e216153c   Mike Miller   cciss: add perfor...
3213
  #define DIRECT_LOOKUP_BIT 0x10
0c2b39087   Mike Miller   cciss: clean up i...
3214
3215
3216
3217
3218
  	return tag & DIRECT_LOOKUP_BIT;
  }
  
  static inline u32 cciss_tag_to_index(u32 tag)
  {
5e216153c   Mike Miller   cciss: add perfor...
3219
  #define DIRECT_LOOKUP_SHIFT 5
0c2b39087   Mike Miller   cciss: clean up i...
3220
3221
  	return tag >> DIRECT_LOOKUP_SHIFT;
  }
0498cc2a9   Stephen M. Cameron   cciss: Inform con...
3222
  static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag)
0c2b39087   Mike Miller   cciss: clean up i...
3223
  {
0498cc2a9   Stephen M. Cameron   cciss: Inform con...
3224
3225
3226
3227
3228
  #define CCISS_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1)
  #define CCISS_SIMPLE_ERROR_BITS 0x03
  	if (likely(h->transMethod & CFGTBL_Trans_Performant))
  		return tag & ~CCISS_PERF_ERROR_BITS;
  	return tag & ~CCISS_SIMPLE_ERROR_BITS;
0c2b39087   Mike Miller   cciss: clean up i...
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
  }
  
  static inline void cciss_mark_tag_indexed(u32 *tag)
  {
  	*tag |= DIRECT_LOOKUP_BIT;
  }
  
  static inline void cciss_set_tag_index(u32 *tag, u32 index)
  {
  	*tag |= (index << DIRECT_LOOKUP_SHIFT);
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3240
3241
  /*
   * Get a request and submit it to the controller.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3242
   */
165125e1e   Jens Axboe   [BLOCK] Get rid o...
3243
  static void do_cciss_request(struct request_queue *q)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3244
  {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3245
  	ctlr_info_t *h = q->queuedata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3246
  	CommandList_struct *c;
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
3247
3248
  	sector_t start_blk;
  	int seg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3249
3250
  	struct request *creq;
  	u64bit temp64;
5c07a311a   Don Brace   cciss: Add enhanc...
3251
3252
  	struct scatterlist *tmp_sg;
  	SGDescriptor_struct *curr_sg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3253
3254
  	drive_info_struct *drv;
  	int i, dir;
5c07a311a   Don Brace   cciss: Add enhanc...
3255
3256
  	int sg_index = 0;
  	int chained = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3257

7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3258
        queue:
9934c8c04   Tejun Heo   block: implement ...
3259
  	creq = blk_peek_request(q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3260
3261
  	if (!creq)
  		goto startio;
5c07a311a   Don Brace   cciss: Add enhanc...
3262
  	BUG_ON(creq->nr_phys_segments > h->maxsgentries);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3263

6b4d96b87   Stephen M. Cameron   cciss: separate c...
3264
3265
  	c = cmd_alloc(h);
  	if (!c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3266
  		goto full;
9934c8c04   Tejun Heo   block: implement ...
3267
  	blk_start_request(creq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3268

5c07a311a   Don Brace   cciss: Add enhanc...
3269
  	tmp_sg = h->scatter_list[c->cmdindex];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3270
3271
3272
3273
  	spin_unlock_irq(q->queue_lock);
  
  	c->cmd_type = CMD_RWREQ;
  	c->rq = creq;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3274
3275
  
  	/* fill in the request */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3276
  	drv = creq->rq_disk->private_data;
b028461d6   dann frazier   cciss: remove C99...
3277
  	c->Header.ReplyQueue = 0;	/* unused in simple mode */
33079b219   Mike Miller   [PATCH] cciss: di...
3278
3279
3280
  	/* got command from pool, so use the command block index instead */
  	/* for direct lookups. */
  	/* The first 2 bits are reserved for controller error reporting. */
0c2b39087   Mike Miller   cciss: clean up i...
3281
3282
  	cciss_set_tag_index(&c->Header.Tag.lower, c->cmdindex);
  	cciss_mark_tag_indexed(&c->Header.Tag.lower);
39ccf9a64   Stephen M. Cameron   cciss: Preserve a...
3283
  	memcpy(&c->Header.LUN, drv->LunID, sizeof(drv->LunID));
b028461d6   dann frazier   cciss: remove C99...
3284
3285
  	c->Request.CDBLen = 10;	/* 12 byte commands not in FW yet; */
  	c->Request.Type.Type = TYPE_CMD;	/* It is a command. */
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3286
3287
  	c->Request.Type.Attribute = ATTR_SIMPLE;
  	c->Request.Type.Direction =
a52de245e   Mike Miller   [PATCH] cciss: fi...
3288
  	    (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE;
b028461d6   dann frazier   cciss: remove C99...
3289
  	c->Request.Timeout = 0;	/* Don't time out */
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3290
  	c->Request.CDB[0] =
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
3291
  	    (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
83096ebf1   Tejun Heo   block: convert to...
3292
  	start_blk = blk_rq_pos(creq);
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3293
3294
  	dev_dbg(&h->pdev->dev, "sector =%d nr_sectors=%d
  ",
83096ebf1   Tejun Heo   block: convert to...
3295
  	       (int)blk_rq_pos(creq), (int)blk_rq_sectors(creq));
5c07a311a   Don Brace   cciss: Add enhanc...
3296
  	sg_init_table(tmp_sg, h->maxsgentries);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3297
  	seg = blk_rq_map_sg(q, creq, tmp_sg);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3298
  	/* get the DMA records for the setup */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3299
3300
3301
3302
  	if (c->Request.Type.Direction == XFER_READ)
  		dir = PCI_DMA_FROMDEVICE;
  	else
  		dir = PCI_DMA_TODEVICE;
5c07a311a   Don Brace   cciss: Add enhanc...
3303
3304
3305
  	curr_sg = c->SG;
  	sg_index = 0;
  	chained = 0;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3306
  	for (i = 0; i < seg; i++) {
5c07a311a   Don Brace   cciss: Add enhanc...
3307
3308
  		if (((sg_index+1) == (h->max_cmd_sgentries)) &&
  			!chained && ((seg - i) > 1)) {
5c07a311a   Don Brace   cciss: Add enhanc...
3309
  			/* Point to next chain block. */
dccc9b563   Stephen M. Cameron   cciss: simplify s...
3310
  			curr_sg = h->cmd_sg_list[c->cmdindex];
5c07a311a   Don Brace   cciss: Add enhanc...
3311
3312
3313
3314
  			sg_index = 0;
  			chained = 1;
  		}
  		curr_sg[sg_index].Len = tmp_sg[i].length;
45711f1af   Jens Axboe   [SG] Update drive...
3315
  		temp64.val = (__u64) pci_map_page(h->pdev, sg_page(&tmp_sg[i]),
5c07a311a   Don Brace   cciss: Add enhanc...
3316
3317
3318
3319
3320
  						tmp_sg[i].offset,
  						tmp_sg[i].length, dir);
  		curr_sg[sg_index].Addr.lower = temp64.val32.lower;
  		curr_sg[sg_index].Addr.upper = temp64.val32.upper;
  		curr_sg[sg_index].Ext = 0;  /* we are not chaining */
5c07a311a   Don Brace   cciss: Add enhanc...
3321
  		++sg_index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3322
  	}
d45033ef5   Stephen M. Cameron   cciss: factor out...
3323
3324
3325
3326
  	if (chained)
  		cciss_map_sg_chain_block(h, c, h->cmd_sg_list[c->cmdindex],
  			(seg - (h->max_cmd_sgentries - 1)) *
  				sizeof(SGDescriptor_struct));
5c07a311a   Don Brace   cciss: Add enhanc...
3327

7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3328
3329
3330
  	/* track how many SG entries we are using */
  	if (seg > h->maxSG)
  		h->maxSG = seg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3331

b2a4a43db   Stephen M. Cameron   cciss: change pri...
3332
  	dev_dbg(&h->pdev->dev, "Submitting %u sectors in %d segments "
5c07a311a   Don Brace   cciss: Add enhanc...
3333
3334
3335
  			"chained[%d]
  ",
  			blk_rq_sectors(creq), seg, chained);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3336

5e216153c   Mike Miller   cciss: add perfor...
3337
3338
3339
3340
  	c->Header.SGTotal = seg + chained;
  	if (seg <= h->max_cmd_sgentries)
  		c->Header.SGList = c->Header.SGTotal;
  	else
5c07a311a   Don Brace   cciss: Add enhanc...
3341
  		c->Header.SGList = h->max_cmd_sgentries;
5e216153c   Mike Miller   cciss: add perfor...
3342
  	set_performant_mode(h, c);
5c07a311a   Don Brace   cciss: Add enhanc...
3343

33659ebba   Christoph Hellwig   block: remove wra...
3344
  	if (likely(creq->cmd_type == REQ_TYPE_FS)) {
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3345
3346
  		if(h->cciss_read == CCISS_READ_10) {
  			c->Request.CDB[1] = 0;
b028461d6   dann frazier   cciss: remove C99...
3347
  			c->Request.CDB[2] = (start_blk >> 24) & 0xff; /* MSB */
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3348
3349
3350
  			c->Request.CDB[3] = (start_blk >> 16) & 0xff;
  			c->Request.CDB[4] = (start_blk >> 8) & 0xff;
  			c->Request.CDB[5] = start_blk & 0xff;
b028461d6   dann frazier   cciss: remove C99...
3351
  			c->Request.CDB[6] = 0; /* (sect >> 24) & 0xff; MSB */
83096ebf1   Tejun Heo   block: convert to...
3352
3353
  			c->Request.CDB[7] = (blk_rq_sectors(creq) >> 8) & 0xff;
  			c->Request.CDB[8] = blk_rq_sectors(creq) & 0xff;
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3354
3355
  			c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
  		} else {
582539e5a   Randy Dunlap   cciss: use upper_...
3356
  			u32 upper32 = upper_32_bits(start_blk);
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3357
3358
  			c->Request.CDBLen = 16;
  			c->Request.CDB[1]= 0;
b028461d6   dann frazier   cciss: remove C99...
3359
  			c->Request.CDB[2]= (upper32 >> 24) & 0xff; /* MSB */
582539e5a   Randy Dunlap   cciss: use upper_...
3360
3361
3362
  			c->Request.CDB[3]= (upper32 >> 16) & 0xff;
  			c->Request.CDB[4]= (upper32 >>  8) & 0xff;
  			c->Request.CDB[5]= upper32 & 0xff;
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3363
3364
3365
3366
  			c->Request.CDB[6]= (start_blk >> 24) & 0xff;
  			c->Request.CDB[7]= (start_blk >> 16) & 0xff;
  			c->Request.CDB[8]= (start_blk >>  8) & 0xff;
  			c->Request.CDB[9]= start_blk & 0xff;
83096ebf1   Tejun Heo   block: convert to...
3367
3368
3369
3370
  			c->Request.CDB[10]= (blk_rq_sectors(creq) >> 24) & 0xff;
  			c->Request.CDB[11]= (blk_rq_sectors(creq) >> 16) & 0xff;
  			c->Request.CDB[12]= (blk_rq_sectors(creq) >>  8) & 0xff;
  			c->Request.CDB[13]= blk_rq_sectors(creq) & 0xff;
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3371
3372
  			c->Request.CDB[14] = c->Request.CDB[15] = 0;
  		}
33659ebba   Christoph Hellwig   block: remove wra...
3373
  	} else if (creq->cmd_type == REQ_TYPE_BLOCK_PC) {
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3374
3375
  		c->Request.CDBLen = creq->cmd_len;
  		memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB);
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
3376
  	} else {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3377
3378
3379
  		dev_warn(&h->pdev->dev, "bad request type %d
  ",
  			creq->cmd_type);
03bbfee58   Mike Miller (OS Dev)   cciss: add SG_IO ...
3380
  		BUG();
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
3381
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3382
3383
  
  	spin_lock_irq(q->queue_lock);
8a3173de4   Jens Axboe   cciss: switch to ...
3384
  	addQ(&h->reqQ, c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3385
  	h->Qdepth++;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3386
3387
  	if (h->Qdepth > h->maxQsinceinit)
  		h->maxQsinceinit = h->Qdepth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3388
3389
  
  	goto queue;
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
3390
  full:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3391
  	blk_stop_queue(q);
00988a351   Mike Miller (OS Dev)   [PATCH] cciss: su...
3392
  startio:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3393
3394
  	/* We will already have the driver lock here so not need
  	 * to lock it.
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3395
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3396
3397
  	start_io(h);
  }
3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
3398
3399
  static inline unsigned long get_next_completion(ctlr_info_t *h)
  {
3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
3400
  	return h->access.command_completed(h);
3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
3401
3402
3403
3404
  }
  
  static inline int interrupt_pending(ctlr_info_t *h)
  {
3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
3405
  	return h->access.intr_pending(h);
3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
3406
3407
3408
3409
  }
  
  static inline long interrupt_not_for_us(ctlr_info_t *h)
  {
811258606   Stephen M. Cameron   cciss: cleanup in...
3410
  	return ((h->access.intr_pending(h) == 0) ||
2cf3af1c9   Mike Miller   cciss: check for ...
3411
  		(h->interrupts_enabled == 0));
3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
3412
  }
0c2b39087   Mike Miller   cciss: clean up i...
3413
3414
  static inline int bad_tag(ctlr_info_t *h, u32 tag_index,
  			u32 raw_tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3415
  {
0c2b39087   Mike Miller   cciss: clean up i...
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
  	if (unlikely(tag_index >= h->nr_cmds)) {
  		dev_warn(&h->pdev->dev, "bad tag 0x%08x ignored.
  ", raw_tag);
  		return 1;
  	}
  	return 0;
  }
  
  static inline void finish_cmd(ctlr_info_t *h, CommandList_struct *c,
  				u32 raw_tag)
  {
  	removeQ(c);
  	if (likely(c->cmd_type == CMD_RWREQ))
  		complete_command(h, c, 0);
  	else if (c->cmd_type == CMD_IOCTL_PEND)
  		complete(c->waiting);
  #ifdef CONFIG_CISS_SCSI_TAPE
  	else if (c->cmd_type == CMD_SCSI)
  		complete_scsi_command(c, 0, raw_tag);
  #endif
  }
29979a712   Mike Miller   cciss: move next_...
3437
3438
3439
  static inline u32 next_command(ctlr_info_t *h)
  {
  	u32 a;
0498cc2a9   Stephen M. Cameron   cciss: Inform con...
3440
  	if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
29979a712   Mike Miller   cciss: move next_...
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
  		return h->access.command_completed(h);
  
  	if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
  		a = *(h->reply_pool_head); /* Next cmd in ring buffer */
  		(h->reply_pool_head)++;
  		h->commands_outstanding--;
  	} else {
  		a = FIFO_EMPTY;
  	}
  	/* Check for wraparound */
  	if (h->reply_pool_head == (h->reply_pool + h->max_commands)) {
  		h->reply_pool_head = h->reply_pool;
  		h->reply_pool_wraparound ^= 1;
  	}
  	return a;
  }
0c2b39087   Mike Miller   cciss: clean up i...
3457
3458
3459
3460
  /* process completion of an indexed ("direct lookup") command */
  static inline u32 process_indexed_cmd(ctlr_info_t *h, u32 raw_tag)
  {
  	u32 tag_index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3461
  	CommandList_struct *c;
0c2b39087   Mike Miller   cciss: clean up i...
3462
3463
3464
  
  	tag_index = cciss_tag_to_index(raw_tag);
  	if (bad_tag(h, tag_index, raw_tag))
5e216153c   Mike Miller   cciss: add perfor...
3465
  		return next_command(h);
0c2b39087   Mike Miller   cciss: clean up i...
3466
3467
  	c = h->cmd_pool + tag_index;
  	finish_cmd(h, c, raw_tag);
5e216153c   Mike Miller   cciss: add perfor...
3468
  	return next_command(h);
0c2b39087   Mike Miller   cciss: clean up i...
3469
3470
3471
3472
3473
  }
  
  /* process completion of a non-indexed command */
  static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag)
  {
0c2b39087   Mike Miller   cciss: clean up i...
3474
  	CommandList_struct *c = NULL;
0c2b39087   Mike Miller   cciss: clean up i...
3475
  	__u32 busaddr_masked, tag_masked;
0498cc2a9   Stephen M. Cameron   cciss: Inform con...
3476
  	tag_masked = cciss_tag_discard_error_bits(h, raw_tag);
e6e1ee936   Jens Axboe   cciss: reinstate ...
3477
  	list_for_each_entry(c, &h->cmpQ, list) {
0498cc2a9   Stephen M. Cameron   cciss: Inform con...
3478
  		busaddr_masked = cciss_tag_discard_error_bits(h, c->busaddr);
0c2b39087   Mike Miller   cciss: clean up i...
3479
3480
  		if (busaddr_masked == tag_masked) {
  			finish_cmd(h, c, raw_tag);
5e216153c   Mike Miller   cciss: add perfor...
3481
  			return next_command(h);
0c2b39087   Mike Miller   cciss: clean up i...
3482
3483
3484
  		}
  	}
  	bad_tag(h, h->nr_cmds + 1, raw_tag);
5e216153c   Mike Miller   cciss: add perfor...
3485
  	return next_command(h);
0c2b39087   Mike Miller   cciss: clean up i...
3486
  }
5afe27811   Stephen M. Cameron   cciss: do soft re...
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
  /* Some controllers, like p400, will give us one interrupt
   * after a soft reset, even if we turned interrupts off.
   * Only need to check for this in the cciss_xxx_discard_completions
   * functions.
   */
  static int ignore_bogus_interrupt(ctlr_info_t *h)
  {
  	if (likely(!reset_devices))
  		return 0;
  
  	if (likely(h->interrupts_enabled))
  		return 0;
  
  	dev_info(&h->pdev->dev, "Received interrupt while interrupts disabled "
  		"(known firmware bug.)  Ignoring.
  ");
  
  	return 1;
  }
  
  static irqreturn_t cciss_intx_discard_completions(int irq, void *dev_id)
  {
  	ctlr_info_t *h = dev_id;
  	unsigned long flags;
  	u32 raw_tag;
  
  	if (ignore_bogus_interrupt(h))
  		return IRQ_NONE;
  
  	if (interrupt_not_for_us(h))
  		return IRQ_NONE;
  	spin_lock_irqsave(&h->lock, flags);
  	while (interrupt_pending(h)) {
  		raw_tag = get_next_completion(h);
  		while (raw_tag != FIFO_EMPTY)
  			raw_tag = next_command(h);
  	}
  	spin_unlock_irqrestore(&h->lock, flags);
  	return IRQ_HANDLED;
  }
  
  static irqreturn_t cciss_msix_discard_completions(int irq, void *dev_id)
  {
  	ctlr_info_t *h = dev_id;
  	unsigned long flags;
  	u32 raw_tag;
  
  	if (ignore_bogus_interrupt(h))
  		return IRQ_NONE;
  
  	spin_lock_irqsave(&h->lock, flags);
  	raw_tag = get_next_completion(h);
  	while (raw_tag != FIFO_EMPTY)
  		raw_tag = next_command(h);
  	spin_unlock_irqrestore(&h->lock, flags);
  	return IRQ_HANDLED;
  }
0c2b39087   Mike Miller   cciss: clean up i...
3544
3545
3546
  static irqreturn_t do_cciss_intx(int irq, void *dev_id)
  {
  	ctlr_info_t *h = dev_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3547
  	unsigned long flags;
0c2b39087   Mike Miller   cciss: clean up i...
3548
  	u32 raw_tag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3549

3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
3550
  	if (interrupt_not_for_us(h))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3551
  		return IRQ_NONE;
f70dba836   Stephen M. Cameron   cciss: use consis...
3552
  	spin_lock_irqsave(&h->lock, flags);
3da8b713d   mike.miller@hp.com   [SCSI] cciss: scs...
3553
  	while (interrupt_pending(h)) {
0c2b39087   Mike Miller   cciss: clean up i...
3554
3555
3556
3557
3558
3559
  		raw_tag = get_next_completion(h);
  		while (raw_tag != FIFO_EMPTY) {
  			if (cciss_tag_contains_index(raw_tag))
  				raw_tag = process_indexed_cmd(h, raw_tag);
  			else
  				raw_tag = process_nonindexed_cmd(h, raw_tag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3560
3561
  		}
  	}
f70dba836   Stephen M. Cameron   cciss: use consis...
3562
  	spin_unlock_irqrestore(&h->lock, flags);
0c2b39087   Mike Miller   cciss: clean up i...
3563
3564
  	return IRQ_HANDLED;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3565

0c2b39087   Mike Miller   cciss: clean up i...
3566
3567
3568
3569
3570
3571
3572
3573
  /* Add a second interrupt handler for MSI/MSI-X mode. In this mode we never
   * check the interrupt pending register because it is not set.
   */
  static irqreturn_t do_cciss_msix_intr(int irq, void *dev_id)
  {
  	ctlr_info_t *h = dev_id;
  	unsigned long flags;
  	u32 raw_tag;
8a3173de4   Jens Axboe   cciss: switch to ...
3574

f70dba836   Stephen M. Cameron   cciss: use consis...
3575
  	spin_lock_irqsave(&h->lock, flags);
0c2b39087   Mike Miller   cciss: clean up i...
3576
3577
3578
3579
3580
3581
  	raw_tag = get_next_completion(h);
  	while (raw_tag != FIFO_EMPTY) {
  		if (cciss_tag_contains_index(raw_tag))
  			raw_tag = process_indexed_cmd(h, raw_tag);
  		else
  			raw_tag = process_nonindexed_cmd(h, raw_tag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3582
  	}
f70dba836   Stephen M. Cameron   cciss: use consis...
3583
  	spin_unlock_irqrestore(&h->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3584
3585
  	return IRQ_HANDLED;
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3586

b368c9dd6   Andrew Patterson   cciss: Use one sc...
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
  /**
   * add_to_scan_list() - add controller to rescan queue
   * @h:		      Pointer to the controller.
   *
   * Adds the controller to the rescan queue if not already on the queue.
   *
   * returns 1 if added to the queue, 0 if skipped (could be on the
   * queue already, or the controller could be initializing or shutting
   * down).
   **/
  static int add_to_scan_list(struct ctlr_info *h)
  {
  	struct ctlr_info *test_h;
  	int found = 0;
  	int ret = 0;
  
  	if (h->busy_initializing)
  		return 0;
  
  	if (!mutex_trylock(&h->busy_shutting_down))
  		return 0;
  
  	mutex_lock(&scan_mutex);
  	list_for_each_entry(test_h, &scan_q, scan_list) {
  		if (test_h == h) {
  			found = 1;
  			break;
  		}
  	}
  	if (!found && !h->busy_scanning) {
16735d022   Wolfram Sang   tree-wide: use re...
3617
  		reinit_completion(&h->scan_wait);
b368c9dd6   Andrew Patterson   cciss: Use one sc...
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
  		list_add_tail(&h->scan_list, &scan_q);
  		ret = 1;
  	}
  	mutex_unlock(&scan_mutex);
  	mutex_unlock(&h->busy_shutting_down);
  
  	return ret;
  }
  
  /**
   * remove_from_scan_list() - remove controller from rescan queue
   * @h:			   Pointer to the controller.
   *
   * Removes the controller from the rescan queue if present. Blocks if
fd8489cff   Stephen M. Cameron   cciss: Fix proble...
3632
3633
3634
3635
3636
3637
3638
   * the controller is currently conducting a rescan.  The controller
   * can be in one of three states:
   * 1. Doesn't need a scan
   * 2. On the scan list, but not scanning yet (we remove it)
   * 3. Busy scanning (and not on the list). In this case we want to wait for
   *    the scan to complete to make sure the scanning thread for this
   *    controller is completely idle.
b368c9dd6   Andrew Patterson   cciss: Use one sc...
3639
3640
3641
3642
   **/
  static void remove_from_scan_list(struct ctlr_info *h)
  {
  	struct ctlr_info *test_h, *tmp_h;
b368c9dd6   Andrew Patterson   cciss: Use one sc...
3643
3644
3645
  
  	mutex_lock(&scan_mutex);
  	list_for_each_entry_safe(test_h, tmp_h, &scan_q, scan_list) {
fd8489cff   Stephen M. Cameron   cciss: Fix proble...
3646
  		if (test_h == h) { /* state 2. */
b368c9dd6   Andrew Patterson   cciss: Use one sc...
3647
3648
3649
3650
3651
3652
  			list_del(&h->scan_list);
  			complete_all(&h->scan_wait);
  			mutex_unlock(&scan_mutex);
  			return;
  		}
  	}
fd8489cff   Stephen M. Cameron   cciss: Fix proble...
3653
3654
  	if (h->busy_scanning) { /* state 3. */
  		mutex_unlock(&scan_mutex);
b368c9dd6   Andrew Patterson   cciss: Use one sc...
3655
  		wait_for_completion(&h->scan_wait);
fd8489cff   Stephen M. Cameron   cciss: Fix proble...
3656
3657
3658
  	} else { /* state 1, nothing to do. */
  		mutex_unlock(&scan_mutex);
  	}
b368c9dd6   Andrew Patterson   cciss: Use one sc...
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
  }
  
  /**
   * scan_thread() - kernel thread used to rescan controllers
   * @data:	 Ignored.
   *
   * A kernel thread used scan for drive topology changes on
   * controllers. The thread processes only one controller at a time
   * using a queue.  Controllers are added to the queue using
   * add_to_scan_list() and removed from the queue either after done
   * processing or using remove_from_scan_list().
   *
   * returns 0.
   **/
0a9279cc7   Mike Miller   cciss: kernel sca...
3673
3674
  static int scan_thread(void *data)
  {
b368c9dd6   Andrew Patterson   cciss: Use one sc...
3675
  	struct ctlr_info *h;
0a9279cc7   Mike Miller   cciss: kernel sca...
3676

b368c9dd6   Andrew Patterson   cciss: Use one sc...
3677
3678
3679
  	while (1) {
  		set_current_state(TASK_INTERRUPTIBLE);
  		schedule();
0a9279cc7   Mike Miller   cciss: kernel sca...
3680
3681
  		if (kthread_should_stop())
  			break;
b368c9dd6   Andrew Patterson   cciss: Use one sc...
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
  
  		while (1) {
  			mutex_lock(&scan_mutex);
  			if (list_empty(&scan_q)) {
  				mutex_unlock(&scan_mutex);
  				break;
  			}
  
  			h = list_entry(scan_q.next,
  				       struct ctlr_info,
  				       scan_list);
  			list_del(&h->scan_list);
  			h->busy_scanning = 1;
  			mutex_unlock(&scan_mutex);
d06dfbd23   Stephen M. Cameron   cciss: Remove unn...
3696
3697
3698
3699
3700
  			rebuild_lun_table(h, 0, 0);
  			complete_all(&h->scan_wait);
  			mutex_lock(&scan_mutex);
  			h->busy_scanning = 0;
  			mutex_unlock(&scan_mutex);
b368c9dd6   Andrew Patterson   cciss: Use one sc...
3701
  		}
0a9279cc7   Mike Miller   cciss: kernel sca...
3702
  	}
b368c9dd6   Andrew Patterson   cciss: Use one sc...
3703

0a9279cc7   Mike Miller   cciss: kernel sca...
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
  	return 0;
  }
  
  static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c)
  {
  	if (c->err_info->SenseInfo[2] != UNIT_ATTENTION)
  		return 0;
  
  	switch (c->err_info->SenseInfo[12]) {
  	case STATE_CHANGED:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3714
3715
3716
  		dev_warn(&h->pdev->dev, "a state change "
  			"detected, command retried
  ");
0a9279cc7   Mike Miller   cciss: kernel sca...
3717
3718
3719
  		return 1;
  	break;
  	case LUN_FAILED:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3720
3721
3722
  		dev_warn(&h->pdev->dev, "LUN failure "
  			"detected, action required
  ");
0a9279cc7   Mike Miller   cciss: kernel sca...
3723
3724
3725
  		return 1;
  	break;
  	case REPORT_LUNS_CHANGED:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3726
3727
  		dev_warn(&h->pdev->dev, "report LUN data changed
  ");
da0021841   Stephen M. Cameron   cciss: Do not aut...
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
  	/*
  	 * Here, we could call add_to_scan_list and wake up the scan thread,
  	 * except that it's quite likely that we will get more than one
  	 * REPORT_LUNS_CHANGED condition in quick succession, which means
  	 * that those which occur after the first one will likely happen
  	 * *during* the scan_thread's rescan.  And the rescan code is not
  	 * robust enough to restart in the middle, undoing what it has already
  	 * done, and it's not clear that it's even possible to do this, since
  	 * part of what it does is notify the block layer, which starts
  	 * doing it's own i/o to read partition tables and so on, and the
  	 * driver doesn't have visibility to know what might need undoing.
  	 * In any event, if possible, it is horribly complicated to get right
  	 * so we just don't do it for now.
  	 *
  	 * Note: this REPORT_LUNS_CHANGED condition only occurs on the MSA2012.
  	 */
0a9279cc7   Mike Miller   cciss: kernel sca...
3744
3745
3746
  		return 1;
  	break;
  	case POWER_OR_RESET:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3747
3748
3749
  		dev_warn(&h->pdev->dev,
  			"a power on or device reset detected
  ");
0a9279cc7   Mike Miller   cciss: kernel sca...
3750
3751
3752
  		return 1;
  	break;
  	case UNIT_ATTENTION_CLEARED:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3753
3754
3755
  		dev_warn(&h->pdev->dev,
  			"unit attention cleared by another initiator
  ");
0a9279cc7   Mike Miller   cciss: kernel sca...
3756
3757
3758
  		return 1;
  	break;
  	default:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3759
3760
3761
  		dev_warn(&h->pdev->dev, "unknown unit attention detected
  ");
  		return 1;
0a9279cc7   Mike Miller   cciss: kernel sca...
3762
3763
  	}
  }
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3764
  /*
d14c4ab58   Bjorn Helgaas   [PATCH] CCISS: fi...
3765
   *  We cannot read the structure directly, for portability we must use
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3766
   *   the io functions.
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3767
   *   This is for debug only.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3768
   */
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3769
  static void print_cfg_table(ctlr_info_t *h)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3770
3771
3772
  {
  	int i;
  	char temp_name[17];
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3773
  	CfgTable_struct *tb = h->cfgtable;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3774

b2a4a43db   Stephen M. Cameron   cciss: change pri...
3775
3776
3777
3778
  	dev_dbg(&h->pdev->dev, "Controller Configuration information
  ");
  	dev_dbg(&h->pdev->dev, "------------------------------------
  ");
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3779
  	for (i = 0; i < 4; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3780
  		temp_name[i] = readb(&(tb->Signature[i]));
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3781
  	temp_name[4] = '\0';
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3782
3783
3784
3785
3786
3787
3788
  	dev_dbg(&h->pdev->dev, "   Signature = %s
  ", temp_name);
  	dev_dbg(&h->pdev->dev, "   Spec Number = %d
  ",
  		readl(&(tb->SpecValence)));
  	dev_dbg(&h->pdev->dev, "   Transport methods supported = 0x%x
  ",
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3789
  	       readl(&(tb->TransportSupport)));
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3790
3791
  	dev_dbg(&h->pdev->dev, "   Transport methods active = 0x%x
  ",
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3792
  	       readl(&(tb->TransportActive)));
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3793
3794
  	dev_dbg(&h->pdev->dev, "   Requested transport Method = 0x%x
  ",
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3795
  	       readl(&(tb->HostWrite.TransportRequest)));
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3796
3797
  	dev_dbg(&h->pdev->dev, "   Coalesce Interrupt Delay = 0x%x
  ",
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3798
  	       readl(&(tb->HostWrite.CoalIntDelay)));
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3799
3800
  	dev_dbg(&h->pdev->dev, "   Coalesce Interrupt Count = 0x%x
  ",
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3801
  	       readl(&(tb->HostWrite.CoalIntCount)));
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3802
3803
  	dev_dbg(&h->pdev->dev, "   Max outstanding commands = 0x%d
  ",
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3804
  	       readl(&(tb->CmdsOutMax)));
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3805
3806
3807
  	dev_dbg(&h->pdev->dev, "   Bus Types = 0x%x
  ",
  		readl(&(tb->BusTypes)));
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3808
  	for (i = 0; i < 16; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3809
3810
  		temp_name[i] = readb(&(tb->ServerName[i]));
  	temp_name[16] = '\0';
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3811
3812
3813
3814
3815
3816
3817
  	dev_dbg(&h->pdev->dev, "   Server Name = %s
  ", temp_name);
  	dev_dbg(&h->pdev->dev, "   Heartbeat Counter = 0x%x
  
  
  ",
  		readl(&(tb->HeartBeat)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3818
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3819

7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3820
  static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3821
3822
  {
  	int i, offset, mem_type, bar_type;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3823
  	if (pci_bar_addr == PCI_BASE_ADDRESS_0)	/* looking for BAR zero? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3824
3825
  		return 0;
  	offset = 0;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3826
3827
  	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
  		bar_type = pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3828
3829
3830
3831
  		if (bar_type == PCI_BASE_ADDRESS_SPACE_IO)
  			offset += 4;
  		else {
  			mem_type = pci_resource_flags(pdev, i) &
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3832
  			    PCI_BASE_ADDRESS_MEM_TYPE_MASK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3833
  			switch (mem_type) {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3834
3835
3836
3837
3838
3839
3840
3841
  			case PCI_BASE_ADDRESS_MEM_TYPE_32:
  			case PCI_BASE_ADDRESS_MEM_TYPE_1M:
  				offset += 4;	/* 32 bit */
  				break;
  			case PCI_BASE_ADDRESS_MEM_TYPE_64:
  				offset += 8;
  				break;
  			default:	/* reserved in PCI 2.2 */
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3842
  				dev_warn(&pdev->dev,
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3843
3844
3845
  				       "Base address is invalid
  ");
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3846
3847
3848
  				break;
  			}
  		}
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
3849
3850
  		if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
  			return i + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3851
3852
3853
  	}
  	return -1;
  }
5e216153c   Mike Miller   cciss: add perfor...
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
  /* Fill in bucket_map[], given nsgs (the max number of
   * scatter gather elements supported) and bucket[],
   * which is an array of 8 integers.  The bucket[] array
   * contains 8 different DMA transfer sizes (in 16
   * byte increments) which the controller uses to fetch
   * commands.  This function fills in bucket_map[], which
   * maps a given number of scatter gather elements to one of
   * the 8 DMA transfer sizes.  The point of it is to allow the
   * controller to only do as much DMA as needed to fetch the
   * command, with the DMA transfer size encoded in the lower
   * bits of the command address.
   */
  static void  calc_bucket_map(int bucket[], int num_buckets,
  	int nsgs, int *bucket_map)
  {
  	int i, j, b, size;
  
  	/* even a command with 0 SGs requires 4 blocks */
  #define MINIMUM_TRANSFER_BLOCKS 4
  #define NUM_BUCKETS 8
  	/* Note, bucket_map must have nsgs+1 entries. */
  	for (i = 0; i <= nsgs; i++) {
  		/* Compute size of a command with i SG entries */
  		size = i + MINIMUM_TRANSFER_BLOCKS;
  		b = num_buckets; /* Assume the biggest bucket */
  		/* Find the bucket that is just big enough */
  		for (j = 0; j < 8; j++) {
  			if (bucket[j] >= size) {
  				b = j;
  				break;
  			}
  		}
  		/* for a command with i SG entries, use bucket b. */
  		bucket_map[i] = b;
  	}
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
3890
  static void cciss_wait_for_mode_change_ack(ctlr_info_t *h)
0f8a6a1e7   Stephen M. Cameron   cciss: factor out...
3891
3892
3893
3894
3895
3896
3897
3898
3899
  {
  	int i;
  
  	/* under certain very rare conditions, this can take awhile.
  	 * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
  	 * as we enter this code.) */
  	for (i = 0; i < MAX_CONFIG_WAIT; i++) {
  		if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
  			break;
332c2f80a   Stephen M. Cameron   cciss: use usleep...
3900
  		usleep_range(10000, 20000);
0f8a6a1e7   Stephen M. Cameron   cciss: factor out...
3901
3902
  	}
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
3903
  static void cciss_enter_performant_mode(ctlr_info_t *h, u32 use_short_tags)
b99331354   Stephen M. Cameron   cciss: factor out...
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
  {
  	/* This is a bit complicated.  There are 8 registers on
  	 * the controller which we write to to tell it 8 different
  	 * sizes of commands which there may be.  It's a way of
  	 * reducing the DMA done to fetch each command.  Encoded into
  	 * each command's tag are 3 bits which communicate to the controller
  	 * which of the eight sizes that command fits within.  The size of
  	 * each command depends on how many scatter gather entries there are.
  	 * Each SG entry requires 16 bytes.  The eight registers are programmed
  	 * with the number of 16-byte blocks a command of that size requires.
  	 * The smallest command possible requires 5 such 16 byte blocks.
  	 * the largest command possible requires MAXSGENTRIES + 4 16-byte
  	 * blocks.  Note, this only extends to the SG entries contained
  	 * within the command block, and does not extend to chained blocks
  	 * of SG elements.   bft[] contains the eight values we write to
  	 * the registers.  They are not evenly distributed, but have more
  	 * sizes for small commands, and fewer sizes for larger commands.
  	 */
5e216153c   Mike Miller   cciss: add perfor...
3922
  	__u32 trans_offset;
b99331354   Stephen M. Cameron   cciss: factor out...
3923
  	int bft[8] = { 5, 6, 8, 10, 12, 20, 28, MAXSGENTRIES + 4};
5e216153c   Mike Miller   cciss: add perfor...
3924
3925
3926
3927
3928
3929
  			/*
  			 *  5 = 1 s/g entry or 4k
  			 *  6 = 2 s/g entry or 8k
  			 *  8 = 4 s/g entry or 16k
  			 * 10 = 6 s/g entry or 24k
  			 */
5e216153c   Mike Miller   cciss: add perfor...
3930
  	unsigned long register_value;
5e216153c   Mike Miller   cciss: add perfor...
3931
  	BUILD_BUG_ON(28 > MAXSGENTRIES + 4);
5e216153c   Mike Miller   cciss: add perfor...
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
  	h->reply_pool_wraparound = 1; /* spec: init to 1 */
  
  	/* Controller spec: zero out this buffer. */
  	memset(h->reply_pool, 0, h->max_commands * sizeof(__u64));
  	h->reply_pool_head = h->reply_pool;
  
  	trans_offset = readl(&(h->cfgtable->TransMethodOffset));
  	calc_bucket_map(bft, ARRAY_SIZE(bft), h->maxsgentries,
  				h->blockFetchTable);
  	writel(bft[0], &h->transtable->BlockFetch0);
  	writel(bft[1], &h->transtable->BlockFetch1);
  	writel(bft[2], &h->transtable->BlockFetch2);
  	writel(bft[3], &h->transtable->BlockFetch3);
  	writel(bft[4], &h->transtable->BlockFetch4);
  	writel(bft[5], &h->transtable->BlockFetch5);
  	writel(bft[6], &h->transtable->BlockFetch6);
  	writel(bft[7], &h->transtable->BlockFetch7);
  
  	/* size of controller ring buffer */
  	writel(h->max_commands, &h->transtable->RepQSize);
  	writel(1, &h->transtable->RepQCount);
  	writel(0, &h->transtable->RepQCtrAddrLow32);
  	writel(0, &h->transtable->RepQCtrAddrHigh32);
  	writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32);
  	writel(0, &h->transtable->RepQAddr0High32);
0498cc2a9   Stephen M. Cameron   cciss: Inform con...
3957
  	writel(CFGTBL_Trans_Performant | use_short_tags,
5e216153c   Mike Miller   cciss: add perfor...
3958
  			&(h->cfgtable->HostWrite.TransportRequest));
5e216153c   Mike Miller   cciss: add perfor...
3959
  	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
0f8a6a1e7   Stephen M. Cameron   cciss: factor out...
3960
  	cciss_wait_for_mode_change_ack(h);
5e216153c   Mike Miller   cciss: add perfor...
3961
  	register_value = readl(&(h->cfgtable->TransportActive));
b99331354   Stephen M. Cameron   cciss: factor out...
3962
  	if (!(register_value & CFGTBL_Trans_Performant))
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3963
  		dev_warn(&h->pdev->dev, "cciss: unable to get board into"
5e216153c   Mike Miller   cciss: add perfor...
3964
3965
  					" performant mode
  ");
b99331354   Stephen M. Cameron   cciss: factor out...
3966
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
3967
  static void cciss_put_controller_into_performant_mode(ctlr_info_t *h)
b99331354   Stephen M. Cameron   cciss: factor out...
3968
3969
  {
  	__u32 trans_support;
130495370   Joseph Handzik   cciss: Adds simpl...
3970
3971
  	if (cciss_simple_mode)
  		return;
b99331354   Stephen M. Cameron   cciss: factor out...
3972
3973
3974
3975
3976
3977
3978
  	dev_dbg(&h->pdev->dev, "Trying to put board into Performant mode
  ");
  	/* Attempt to put controller into performant mode if supported */
  	/* Does board support performant mode? */
  	trans_support = readl(&(h->cfgtable->TransportSupport));
  	if (!(trans_support & PERFORMANT_MODE))
  		return;
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3979
3980
  	dev_dbg(&h->pdev->dev, "Placing controller into performant mode
  ");
b99331354   Stephen M. Cameron   cciss: factor out...
3981
3982
3983
3984
3985
  	/* Performant mode demands commands on a 32 byte boundary
  	 * pci_alloc_consistent aligns on page boundarys already.
  	 * Just need to check if divisible by 32
  	 */
  	if ((sizeof(CommandList_struct) % 32) != 0) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
3986
3987
  		dev_warn(&h->pdev->dev, "%s %d %s
  ",
b99331354   Stephen M. Cameron   cciss: factor out...
3988
3989
3990
3991
  			"cciss info: command size[",
  			(int)sizeof(CommandList_struct),
  			"] not divisible by 32, no performant mode..
  ");
5e216153c   Mike Miller   cciss: add perfor...
3992
3993
  		return;
  	}
b99331354   Stephen M. Cameron   cciss: factor out...
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
  	/* Performant mode ring buffer and supporting data structures */
  	h->reply_pool = (__u64 *)pci_alloc_consistent(
  		h->pdev, h->max_commands * sizeof(__u64),
  		&(h->reply_pool_dhandle));
  
  	/* Need a block fetch table for performant mode */
  	h->blockFetchTable = kmalloc(((h->maxsgentries+1) *
  		sizeof(__u32)), GFP_KERNEL);
  
  	if ((h->reply_pool == NULL) || (h->blockFetchTable == NULL))
  		goto clean_up;
0498cc2a9   Stephen M. Cameron   cciss: Inform con...
4005
4006
  	cciss_enter_performant_mode(h,
  		trans_support & CFGTBL_Trans_use_short_tags);
b99331354   Stephen M. Cameron   cciss: factor out...
4007

5e216153c   Mike Miller   cciss: add perfor...
4008
4009
  	/* Change the access methods to the performant access methods */
  	h->access = SA5_performant_access;
b99331354   Stephen M. Cameron   cciss: factor out...
4010
  	h->transMethod = CFGTBL_Trans_Performant;
5e216153c   Mike Miller   cciss: add perfor...
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
  
  	return;
  clean_up:
  	kfree(h->blockFetchTable);
  	if (h->reply_pool)
  		pci_free_consistent(h->pdev,
  				h->max_commands * sizeof(__u64),
  				h->reply_pool,
  				h->reply_pool_dhandle);
  	return;
  
  } /* cciss_put_controller_into_performant_mode */
fb86a35b9   Mike Miller   [PATCH] cciss: ad...
4023
4024
4025
  /* If MSI/MSI-X is supported by the kernel we will try to enable it on
   * controllers that are capable. If not, we use IO-APIC mode.
   */
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4026
  static void cciss_interrupt_mode(ctlr_info_t *h)
fb86a35b9   Mike Miller   [PATCH] cciss: ad...
4027
4028
  {
  #ifdef CONFIG_PCI_MSI
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4029
4030
4031
4032
  	int err;
  	struct msix_entry cciss_msix_entries[4] = { {0, 0}, {0, 1},
  	{0, 2}, {0, 3}
  	};
fb86a35b9   Mike Miller   [PATCH] cciss: ad...
4033
4034
  
  	/* Some boards advertise MSI but don't really support it */
f70dba836   Stephen M. Cameron   cciss: use consis...
4035
4036
  	if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) ||
  	    (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11))
fb86a35b9   Mike Miller   [PATCH] cciss: ad...
4037
  		goto default_int_mode;
f70dba836   Stephen M. Cameron   cciss: use consis...
4038
4039
  	if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
  		err = pci_enable_msix(h->pdev, cciss_msix_entries, 4);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4040
  		if (!err) {
f70dba836   Stephen M. Cameron   cciss: use consis...
4041
4042
4043
4044
4045
  			h->intr[0] = cciss_msix_entries[0].vector;
  			h->intr[1] = cciss_msix_entries[1].vector;
  			h->intr[2] = cciss_msix_entries[2].vector;
  			h->intr[3] = cciss_msix_entries[3].vector;
  			h->msix_vector = 1;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4046
4047
4048
  			return;
  		}
  		if (err > 0) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4049
4050
4051
  			dev_warn(&h->pdev->dev,
  				"only %d MSI-X vectors available
  ", err);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4052
  		} else {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4053
4054
4055
  			dev_warn(&h->pdev->dev,
  				"MSI-X init failed %d
  ", err);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4056
4057
  		}
  	}
f70dba836   Stephen M. Cameron   cciss: use consis...
4058
4059
4060
4061
  	if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
  		if (!pci_enable_msi(h->pdev))
  			h->msi_vector = 1;
  		else
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4062
4063
  			dev_warn(&h->pdev->dev, "MSI init failed
  ");
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4064
  	}
1ecb9c0f3   Mike Miller   [PATCH] cciss: cl...
4065
  default_int_mode:
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4066
  #endif				/* CONFIG_PCI_MSI */
fb86a35b9   Mike Miller   [PATCH] cciss: ad...
4067
  	/* if we get here we're going to use the default interrupt mode */
130495370   Joseph Handzik   cciss: Adds simpl...
4068
  	h->intr[h->intr_mode] = h->pdev->irq;
fb86a35b9   Mike Miller   [PATCH] cciss: ad...
4069
4070
  	return;
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4071
  static int cciss_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4072
  {
6539fa9b2   Stephen M. Cameron   cciss: factor out...
4073
4074
  	int i;
  	u32 subsystem_vendor_id, subsystem_device_id;
2ec24ff1d   Stephen M. Cameron   cciss: Add cciss_...
4075
4076
4077
  
  	subsystem_vendor_id = pdev->subsystem_vendor;
  	subsystem_device_id = pdev->subsystem_device;
6539fa9b2   Stephen M. Cameron   cciss: factor out...
4078
4079
  	*board_id = ((subsystem_device_id << 16) & 0xffff0000) |
  			subsystem_vendor_id;
2ec24ff1d   Stephen M. Cameron   cciss: Add cciss_...
4080

e4292e05d   Mike Miller   cciss: add cciss_...
4081
4082
4083
4084
  	for (i = 0; i < ARRAY_SIZE(products); i++) {
  		/* Stand aside for hpsa driver on request */
  		if (cciss_allow_hpsa)
  			return -ENODEV;
6539fa9b2   Stephen M. Cameron   cciss: factor out...
4085
4086
  		if (*board_id == products[i].board_id)
  			return i;
e4292e05d   Mike Miller   cciss: add cciss_...
4087
  	}
6539fa9b2   Stephen M. Cameron   cciss: factor out...
4088
4089
4090
4091
4092
  	dev_warn(&pdev->dev, "unrecognized board ID: 0x%08x, ignoring.
  ",
  		*board_id);
  	return -ENODEV;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4093

dd9c426e9   Stephen M. Cameron   cciss: factor out...
4094
4095
4096
  static inline bool cciss_board_disabled(ctlr_info_t *h)
  {
  	u16 command;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4097

dd9c426e9   Stephen M. Cameron   cciss: factor out...
4098
4099
4100
  	(void) pci_read_config_word(h->pdev, PCI_COMMAND, &command);
  	return ((command & PCI_COMMAND_MEMORY) == 0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4101

8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4102
4103
  static int cciss_pci_find_memory_BAR(struct pci_dev *pdev,
  				     unsigned long *memory_bar)
d474830da   Stephen M. Cameron   cciss: factor out...
4104
4105
  {
  	int i;
4e570309e   Bjorn Helgaas   [PATCH] CCISS: re...
4106

d474830da   Stephen M. Cameron   cciss: factor out...
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
  	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
  		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
  			/* addressing mode bits already removed */
  			*memory_bar = pci_resource_start(pdev, i);
  			dev_dbg(&pdev->dev, "memory BAR = %lx
  ",
  				*memory_bar);
  			return 0;
  		}
  	dev_warn(&pdev->dev, "no memory BAR found
  ");
  	return -ENODEV;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4120

8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4121
4122
  static int cciss_wait_for_board_state(struct pci_dev *pdev,
  				      void __iomem *vaddr, int wait_for_ready)
afa842fa6   Stephen M. Cameron   cciss: fix board ...
4123
4124
  #define BOARD_READY 1
  #define BOARD_NOT_READY 0
e99ba1362   Stephen M. Cameron   cciss: factor out...
4125
  {
afa842fa6   Stephen M. Cameron   cciss: fix board ...
4126
  	int i, iterations;
e99ba1362   Stephen M. Cameron   cciss: factor out...
4127
  	u32 scratchpad;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4128

afa842fa6   Stephen M. Cameron   cciss: fix board ...
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
  	if (wait_for_ready)
  		iterations = CCISS_BOARD_READY_ITERATIONS;
  	else
  		iterations = CCISS_BOARD_NOT_READY_ITERATIONS;
  
  	for (i = 0; i < iterations; i++) {
  		scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET);
  		if (wait_for_ready) {
  			if (scratchpad == CCISS_FIRMWARE_READY)
  				return 0;
  		} else {
  			if (scratchpad != CCISS_FIRMWARE_READY)
  				return 0;
  		}
e99ba1362   Stephen M. Cameron   cciss: factor out...
4143
  		msleep(CCISS_BOARD_READY_POLL_INTERVAL_MSECS);
e14385810   Mike Miller   cciss: change to ...
4144
  	}
afa842fa6   Stephen M. Cameron   cciss: fix board ...
4145
4146
  	dev_warn(&pdev->dev, "board not ready, timed out.
  ");
e99ba1362   Stephen M. Cameron   cciss: factor out...
4147
4148
  	return -ENODEV;
  }
e14385810   Mike Miller   cciss: change to ...
4149

8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4150
4151
4152
  static int cciss_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
  				u32 *cfg_base_addr, u64 *cfg_base_addr_index,
  				u64 *cfg_offset)
8e93bf6d6   Stephen M. Cameron   cciss: factor out...
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
  {
  	*cfg_base_addr = readl(vaddr + SA5_CTCFG_OFFSET);
  	*cfg_offset = readl(vaddr + SA5_CTMEM_OFFSET);
  	*cfg_base_addr &= (u32) 0x0000ffff;
  	*cfg_base_addr_index = find_PCI_BAR_index(pdev, *cfg_base_addr);
  	if (*cfg_base_addr_index == -1) {
  		dev_warn(&pdev->dev, "cannot find cfg_base_addr_index, "
  			"*cfg_base_addr = 0x%08x
  ", *cfg_base_addr);
  		return -ENODEV;
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4166

8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4167
  static int cciss_find_cfgtables(ctlr_info_t *h)
4809d0988   Stephen M. Cameron   cciss: factor out...
4168
4169
4170
4171
4172
  {
  	u64 cfg_offset;
  	u32 cfg_base_addr;
  	u64 cfg_base_addr_index;
  	u32 trans_offset;
8e93bf6d6   Stephen M. Cameron   cciss: factor out...
4173
  	int rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4174

8e93bf6d6   Stephen M. Cameron   cciss: factor out...
4175
4176
4177
4178
  	rc = cciss_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
  		&cfg_base_addr_index, &cfg_offset);
  	if (rc)
  		return rc;
4809d0988   Stephen M. Cameron   cciss: factor out...
4179
  	h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev,
d2b805d89   Wei Yongjun   cciss: fix invali...
4180
  		cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
4809d0988   Stephen M. Cameron   cciss: factor out...
4181
4182
  	if (!h->cfgtable)
  		return -ENOMEM;
62710ae1c   Stephen M. Cameron   cciss: do a bette...
4183
4184
4185
  	rc = write_driver_ver_to_cfgtable(h->cfgtable);
  	if (rc)
  		return rc;
4809d0988   Stephen M. Cameron   cciss: factor out...
4186
  	/* Find performant mode table. */
8e93bf6d6   Stephen M. Cameron   cciss: factor out...
4187
  	trans_offset = readl(&h->cfgtable->TransMethodOffset);
4809d0988   Stephen M. Cameron   cciss: factor out...
4188
4189
4190
4191
4192
4193
4194
  	h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
  				cfg_base_addr_index)+cfg_offset+trans_offset,
  				sizeof(*h->transtable));
  	if (!h->transtable)
  		return -ENOMEM;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4195

8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4196
  static void cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
adfbc1ff3   Stephen M. Cameron   cciss: sanitize m...
4197
4198
  {
  	h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
186fb9cf6   Stephen M. Cameron   cciss: limit comm...
4199
4200
4201
4202
  
  	/* Limit commands in memory limited kdump scenario. */
  	if (reset_devices && h->max_commands > 32)
  		h->max_commands = 32;
adfbc1ff3   Stephen M. Cameron   cciss: sanitize m...
4203
4204
4205
4206
4207
4208
4209
  	if (h->max_commands < 16) {
  		dev_warn(&h->pdev->dev, "Controller reports "
  			"max supported commands of %d, an obvious lie. "
  			"Using 16.  Ensure that firmware is up to date.
  ",
  			h->max_commands);
  		h->max_commands = 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4210
  	}
adfbc1ff3   Stephen M. Cameron   cciss: sanitize m...
4211
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4212

afadbf4b9   Stephen M. Cameron   cciss: factor out...
4213
4214
4215
4216
  /* Interrogate the hardware for some limits:
   * max commands, max SG elements without chaining, and with chaining,
   * SG chain block size, etc.
   */
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4217
  static void cciss_find_board_params(ctlr_info_t *h)
afadbf4b9   Stephen M. Cameron   cciss: factor out...
4218
  {
adfbc1ff3   Stephen M. Cameron   cciss: sanitize m...
4219
  	cciss_get_max_perf_mode_cmds(h);
8a4ec67bd   Stephen M. Cameron   cciss: add cciss_...
4220
  	h->nr_cmds = h->max_commands - 4 - cciss_tape_cmds;
afadbf4b9   Stephen M. Cameron   cciss: factor out...
4221
  	h->maxsgentries = readl(&(h->cfgtable->MaxSGElements));
5c07a311a   Don Brace   cciss: Add enhanc...
4222
  	/*
e7b18ede4   Mike Miller   cciss: set max sc...
4223
4224
4225
4226
4227
4228
4229
  	 * The P600 may exhibit poor performnace under some workloads
  	 * if we use the value in the configuration table. Limit this
  	 * controller to MAXSGENTRIES (32) instead.
  	 */
  	if (h->board_id == 0x3225103C)
  		h->maxsgentries = MAXSGENTRIES;
  	/*
afadbf4b9   Stephen M. Cameron   cciss: factor out...
4230
  	 * Limit in-command s/g elements to 32 save dma'able memory.
5c07a311a   Don Brace   cciss: Add enhanc...
4231
4232
  	 * Howvever spec says if 0, use 31
  	 */
afadbf4b9   Stephen M. Cameron   cciss: factor out...
4233
4234
4235
4236
4237
  	h->max_cmd_sgentries = 31;
  	if (h->maxsgentries > 512) {
  		h->max_cmd_sgentries = 32;
  		h->chainsize = h->maxsgentries - h->max_cmd_sgentries + 1;
  		h->maxsgentries--; /* save one for chain pointer */
5c07a311a   Don Brace   cciss: Add enhanc...
4238
  	} else {
afadbf4b9   Stephen M. Cameron   cciss: factor out...
4239
4240
  		h->maxsgentries = 31; /* default to traditional values */
  		h->chainsize = 0;
5c07a311a   Don Brace   cciss: Add enhanc...
4241
  	}
afadbf4b9   Stephen M. Cameron   cciss: factor out...
4242
  }
5c07a311a   Don Brace   cciss: Add enhanc...
4243

501b92cd6   Stephen M. Cameron   cciss: factor out...
4244
4245
  static inline bool CISS_signature_present(ctlr_info_t *h)
  {
d48c152a4   Akinobu Mita   cciss: use check_...
4246
  	if (!check_signature(h->cfgtable->Signature, "CISS", 4)) {
501b92cd6   Stephen M. Cameron   cciss: factor out...
4247
4248
4249
  		dev_warn(&h->pdev->dev, "not a valid CISS config table
  ");
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4250
  	}
501b92cd6   Stephen M. Cameron   cciss: factor out...
4251
4252
  	return true;
  }
322e304c4   Stephen M. Cameron   cciss: factor out...
4253
4254
4255
  /* Need to enable prefetch in the SCSI core for 6400 in x86 */
  static inline void cciss_enable_scsi_prefetch(ctlr_info_t *h)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4256
  #ifdef CONFIG_X86
322e304c4   Stephen M. Cameron   cciss: factor out...
4257
4258
4259
4260
4261
  	u32 prefetch;
  
  	prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
  	prefetch |= 0x100;
  	writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4262
  #endif
322e304c4   Stephen M. Cameron   cciss: factor out...
4263
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4264

bfd63ee57   Stephen M. Cameron   cciss: factor out...
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
  /* Disable DMA prefetch for the P600.  Otherwise an ASIC bug may result
   * in a prefetch beyond physical memory.
   */
  static inline void cciss_p600_dma_prefetch_quirk(ctlr_info_t *h)
  {
  	u32 dma_prefetch;
  	__u32 dma_refetch;
  
  	if (h->board_id != 0x3225103C)
  		return;
  	dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
  	dma_prefetch |= 0x8000;
  	writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
  	pci_read_config_dword(h->pdev, PCI_COMMAND_PARITY, &dma_refetch);
  	dma_refetch |= 0x1;
  	pci_write_config_dword(h->pdev, PCI_COMMAND_PARITY, dma_refetch);
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4282
  static int cciss_pci_init(ctlr_info_t *h)
6539fa9b2   Stephen M. Cameron   cciss: factor out...
4283
  {
4809d0988   Stephen M. Cameron   cciss: factor out...
4284
  	int prod_index, err;
6539fa9b2   Stephen M. Cameron   cciss: factor out...
4285

f70dba836   Stephen M. Cameron   cciss: use consis...
4286
  	prod_index = cciss_lookup_board_id(h->pdev, &h->board_id);
6539fa9b2   Stephen M. Cameron   cciss: factor out...
4287
  	if (prod_index < 0)
2ec24ff1d   Stephen M. Cameron   cciss: Add cciss_...
4288
  		return -ENODEV;
f70dba836   Stephen M. Cameron   cciss: use consis...
4289
4290
  	h->product_name = products[prod_index].product_name;
  	h->access = *(products[prod_index].access);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4291

f70dba836   Stephen M. Cameron   cciss: use consis...
4292
  	if (cciss_board_disabled(h)) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4293
4294
  		dev_warn(&h->pdev->dev, "controller appears to be disabled
  ");
c33ac89bc   Bjorn Helgaas   [PATCH] CCISS: di...
4295
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4296
  	}
193733585   Matthew Garrett   The Windows drive...
4297
4298
4299
  
  	pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S |
  				PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
f70dba836   Stephen M. Cameron   cciss: use consis...
4300
  	err = pci_enable_device(h->pdev);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4301
  	if (err) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4302
4303
  		dev_warn(&h->pdev->dev, "Unable to Enable PCI device
  ");
c33ac89bc   Bjorn Helgaas   [PATCH] CCISS: di...
4304
  		return err;
f92e2f5f8   Mike Miller   [PATCH] cciss: di...
4305
  	}
f70dba836   Stephen M. Cameron   cciss: use consis...
4306
  	err = pci_request_regions(h->pdev, "cciss");
4e570309e   Bjorn Helgaas   [PATCH] CCISS: re...
4307
  	if (err) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4308
4309
4310
  		dev_warn(&h->pdev->dev,
  			"Cannot obtain PCI resources, aborting
  ");
872225ca7   Mike Miller   [PATCH] cciss: re...
4311
  		return err;
4e570309e   Bjorn Helgaas   [PATCH] CCISS: re...
4312
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4313

b2a4a43db   Stephen M. Cameron   cciss: change pri...
4314
4315
4316
4317
  	dev_dbg(&h->pdev->dev, "irq = %x
  ", h->pdev->irq);
  	dev_dbg(&h->pdev->dev, "board_id = %x
  ", h->board_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4318

fb86a35b9   Mike Miller   [PATCH] cciss: ad...
4319
4320
4321
  /* If the kernel supports MSI/MSI-X we will try to enable that functionality,
   * else we use the IO-APIC interrupt assigned to us by system ROM.
   */
f70dba836   Stephen M. Cameron   cciss: use consis...
4322
4323
  	cciss_interrupt_mode(h);
  	err = cciss_pci_find_memory_BAR(h->pdev, &h->paddr);
d474830da   Stephen M. Cameron   cciss: factor out...
4324
  	if (err)
e14385810   Mike Miller   cciss: change to ...
4325
  		goto err_out_free_res;
f70dba836   Stephen M. Cameron   cciss: use consis...
4326
4327
  	h->vaddr = remap_pci_mem(h->paddr, 0x250);
  	if (!h->vaddr) {
da5503217   Stephen M. Cameron   cciss: fix leak o...
4328
4329
  		err = -ENOMEM;
  		goto err_out_free_res;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4330
  	}
afa842fa6   Stephen M. Cameron   cciss: fix board ...
4331
  	err = cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
e99ba1362   Stephen M. Cameron   cciss: factor out...
4332
  	if (err)
4e570309e   Bjorn Helgaas   [PATCH] CCISS: re...
4333
  		goto err_out_free_res;
f70dba836   Stephen M. Cameron   cciss: use consis...
4334
  	err = cciss_find_cfgtables(h);
4809d0988   Stephen M. Cameron   cciss: factor out...
4335
  	if (err)
4e570309e   Bjorn Helgaas   [PATCH] CCISS: re...
4336
  		goto err_out_free_res;
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4337
  	print_cfg_table(h);
f70dba836   Stephen M. Cameron   cciss: use consis...
4338
  	cciss_find_board_params(h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4339

f70dba836   Stephen M. Cameron   cciss: use consis...
4340
  	if (!CISS_signature_present(h)) {
c33ac89bc   Bjorn Helgaas   [PATCH] CCISS: di...
4341
  		err = -ENODEV;
4e570309e   Bjorn Helgaas   [PATCH] CCISS: re...
4342
  		goto err_out_free_res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4343
  	}
f70dba836   Stephen M. Cameron   cciss: use consis...
4344
4345
  	cciss_enable_scsi_prefetch(h);
  	cciss_p600_dma_prefetch_quirk(h);
130495370   Joseph Handzik   cciss: Adds simpl...
4346
4347
4348
  	err = cciss_enter_simple_mode(h);
  	if (err)
  		goto err_out_free_res;
f70dba836   Stephen M. Cameron   cciss: use consis...
4349
  	cciss_put_controller_into_performant_mode(h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4350
  	return 0;
5faad6202   Linus Torvalds   Merge branch 'for...
4351
  err_out_free_res:
872225ca7   Mike Miller   [PATCH] cciss: re...
4352
4353
4354
4355
  	/*
  	 * Deliberately omit pci_disable_device(): it does something nasty to
  	 * Smart Array controllers that pci_enable_device does not undo
  	 */
f70dba836   Stephen M. Cameron   cciss: use consis...
4356
4357
4358
4359
4360
4361
4362
  	if (h->transtable)
  		iounmap(h->transtable);
  	if (h->cfgtable)
  		iounmap(h->cfgtable);
  	if (h->vaddr)
  		iounmap(h->vaddr);
  	pci_release_regions(h->pdev);
c33ac89bc   Bjorn Helgaas   [PATCH] CCISS: di...
4363
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4364
  }
6ae5ce8e8   Mike Miller   cciss: remove red...
4365
4366
  /* Function to find the first free pointer into our hba[] array
   * Returns -1 if no free entries are left.
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4367
   */
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4368
  static int alloc_cciss_hba(struct pci_dev *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4369
  {
799202cbd   Mike Miller   [PATCH] cciss: ad...
4370
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4371

7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4372
  	for (i = 0; i < MAX_CTLR; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4373
  		if (!hba[i]) {
f70dba836   Stephen M. Cameron   cciss: use consis...
4374
  			ctlr_info_t *h;
f2912a122   Jesper Juhl   cciss: fix memory...
4375

f70dba836   Stephen M. Cameron   cciss: use consis...
4376
4377
  			h = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
  			if (!h)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4378
  				goto Enomem;
f70dba836   Stephen M. Cameron   cciss: use consis...
4379
  			hba[i] = h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4380
4381
4382
  			return i;
  		}
  	}
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4383
  	dev_warn(&pdev->dev, "This driver supports a maximum"
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4384
4385
  	       " of %d controllers.
  ", MAX_CTLR);
799202cbd   Mike Miller   [PATCH] cciss: ad...
4386
4387
  	return -1;
  Enomem:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4388
4389
  	dev_warn(&pdev->dev, "out of memory.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4390
4391
  	return -1;
  }
f70dba836   Stephen M. Cameron   cciss: use consis...
4392
  static void free_hba(ctlr_info_t *h)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4393
  {
2c935593a   Stephen M. Cameron   cciss: Fix excess...
4394
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4395

f70dba836   Stephen M. Cameron   cciss: use consis...
4396
  	hba[h->ctlr] = NULL;
2c935593a   Stephen M. Cameron   cciss: Fix excess...
4397
4398
4399
4400
  	for (i = 0; i < h->highest_lun + 1; i++)
  		if (h->gendisk[i] != NULL)
  			put_disk(h->gendisk[i]);
  	kfree(h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4401
  }
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4402
  /* Send a message CDB to the firmware. */
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4403
4404
  static int cciss_message(struct pci_dev *pdev, unsigned char opcode,
  			 unsigned char type)
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
  {
  	typedef struct {
  		CommandListHeader_struct CommandHeader;
  		RequestBlock_struct Request;
  		ErrDescriptor_struct ErrorDescriptor;
  	} Command;
  	static const size_t cmd_sz = sizeof(Command) + sizeof(ErrorInfo_struct);
  	Command *cmd;
  	dma_addr_t paddr64;
  	uint32_t paddr32, tag;
  	void __iomem *vaddr;
  	int i, err;
  
  	vaddr = ioremap_nocache(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
  	if (vaddr == NULL)
  		return -ENOMEM;
  
  	/* The Inbound Post Queue only accepts 32-bit physical addresses for the
  	   CCISS commands, so they must be allocated from the lower 4GiB of
  	   memory. */
e930438c4   Yang Hongyang   Replace all DMA_n...
4425
  	err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
  	if (err) {
  		iounmap(vaddr);
  		return -ENOMEM;
  	}
  
  	cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64);
  	if (cmd == NULL) {
  		iounmap(vaddr);
  		return -ENOMEM;
  	}
  
  	/* This must fit, because of the 32-bit consistent DMA mask.  Also,
  	   although there's no guarantee, we assume that the address is at
  	   least 4-byte aligned (most likely, it's page-aligned). */
  	paddr32 = paddr64;
  
  	cmd->CommandHeader.ReplyQueue = 0;
  	cmd->CommandHeader.SGList = 0;
  	cmd->CommandHeader.SGTotal = 0;
  	cmd->CommandHeader.Tag.lower = paddr32;
  	cmd->CommandHeader.Tag.upper = 0;
  	memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8);
  
  	cmd->Request.CDBLen = 16;
  	cmd->Request.Type.Type = TYPE_MSG;
  	cmd->Request.Type.Attribute = ATTR_HEADOFQUEUE;
  	cmd->Request.Type.Direction = XFER_NONE;
  	cmd->Request.Timeout = 0; /* Don't time out */
  	cmd->Request.CDB[0] = opcode;
  	cmd->Request.CDB[1] = type;
  	memset(&cmd->Request.CDB[2], 0, 14); /* the rest of the CDB is reserved */
  
  	cmd->ErrorDescriptor.Addr.lower = paddr32 + sizeof(Command);
  	cmd->ErrorDescriptor.Addr.upper = 0;
  	cmd->ErrorDescriptor.Len = sizeof(ErrorInfo_struct);
  
  	writel(paddr32, vaddr + SA5_REQUEST_PORT_OFFSET);
  
  	for (i = 0; i < 10; i++) {
  		tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
  		if ((tag & ~3) == paddr32)
  			break;
3e28601fd   Stephen M. Cameron   cciss: increase t...
4468
  		msleep(CCISS_POST_RESET_NOOP_TIMEOUT_MSECS);
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4469
4470
4471
4472
4473
4474
4475
  	}
  
  	iounmap(vaddr);
  
  	/* we leak the DMA buffer here ... no choice since the controller could
  	   still complete the command. */
  	if (i == 10) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4476
4477
4478
  		dev_err(&pdev->dev,
  			"controller message %02x:%02x timed out
  ",
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4479
4480
4481
4482
4483
4484
4485
  			opcode, type);
  		return -ETIMEDOUT;
  	}
  
  	pci_free_consistent(pdev, cmd_sz, cmd, paddr64);
  
  	if (tag & 2) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4486
4487
  		dev_err(&pdev->dev, "controller message %02x:%02x failed
  ",
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4488
4489
4490
  			opcode, type);
  		return -EIO;
  	}
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4491
4492
  	dev_info(&pdev->dev, "controller message %02x:%02x succeeded
  ",
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4493
4494
4495
  		opcode, type);
  	return 0;
  }
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4496
  #define cciss_noop(p) cciss_message(p, 3, 0)
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4497
  static int cciss_controller_hard_reset(struct pci_dev *pdev,
bf2e2e6b8   Stephen M. Cameron   cciss: use new do...
4498
  	void * __iomem vaddr, u32 use_doorbell)
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4499
  {
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4500
4501
  	u16 pmcsr;
  	int pos;
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4502

a6528d017   Stephen M. Cameron   cciss: fix hard r...
4503
4504
4505
4506
4507
4508
4509
  	if (use_doorbell) {
  		/* For everything after the P600, the PCI power state method
  		 * of resetting the controller doesn't work, so we have this
  		 * other way using the doorbell register.
  		 */
  		dev_info(&pdev->dev, "using doorbell to reset controller
  ");
bf2e2e6b8   Stephen M. Cameron   cciss: use new do...
4510
  		writel(use_doorbell, vaddr + SA5_DOORBELL);
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
  	} else { /* Try to do it the PCI power state way */
  
  		/* Quoting from the Open CISS Specification: "The Power
  		 * Management Control/Status Register (CSR) controls the power
  		 * state of the device.  The normal operating state is D0,
  		 * CSR=00h.  The software off state is D3, CSR=03h.  To reset
  		 * the controller, place the interface device in D3 then to D0,
  		 * this causes a secondary PCI reset which will reset the
  		 * controller." */
  
  		pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
  		if (pos == 0) {
  			dev_err(&pdev->dev,
  				"cciss_controller_hard_reset: "
  				"PCI PM not supported
  ");
  			return -ENODEV;
  		}
  		dev_info(&pdev->dev, "using PCI PM to reset controller
  ");
  		/* enter the D3hot power management state */
  		pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
  		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
  		pmcsr |= PCI_D3hot;
  		pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4536

a6528d017   Stephen M. Cameron   cciss: fix hard r...
4537
  		msleep(500);
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4538

a6528d017   Stephen M. Cameron   cciss: fix hard r...
4539
4540
4541
4542
  		/* enter the D0 power management state */
  		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
  		pmcsr |= PCI_D0;
  		pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
ab5dbebe3   Mike Miller   cciss: add small ...
4543
4544
4545
4546
4547
4548
4549
  
  		/*
  		 * The P600 requires a small delay when changing states.
  		 * Otherwise we may think the board did not reset and we bail.
  		 * This for kdump only and is particular to the P600.
  		 */
  		msleep(500);
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4550
4551
4552
  	}
  	return 0;
  }
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4553

8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4554
  static void init_driver_version(char *driver_version, int len)
62710ae1c   Stephen M. Cameron   cciss: do a bette...
4555
4556
4557
4558
  {
  	memset(driver_version, 0, len);
  	strncpy(driver_version, "cciss " DRIVER_NAME, len - 1);
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4559
  static int write_driver_ver_to_cfgtable(CfgTable_struct __iomem *cfgtable)
62710ae1c   Stephen M. Cameron   cciss: do a bette...
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
  {
  	char *driver_version;
  	int i, size = sizeof(cfgtable->driver_version);
  
  	driver_version = kmalloc(size, GFP_KERNEL);
  	if (!driver_version)
  		return -ENOMEM;
  
  	init_driver_version(driver_version, size);
  	for (i = 0; i < size; i++)
  		writeb(driver_version[i], &cfgtable->driver_version[i]);
  	kfree(driver_version);
  	return 0;
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4574
4575
  static void read_driver_ver_from_cfgtable(CfgTable_struct __iomem *cfgtable,
  					  unsigned char *driver_ver)
62710ae1c   Stephen M. Cameron   cciss: do a bette...
4576
4577
4578
4579
4580
4581
  {
  	int i;
  
  	for (i = 0; i < sizeof(cfgtable->driver_version); i++)
  		driver_ver[i] = readb(&cfgtable->driver_version[i]);
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4582
  static int controller_reset_failed(CfgTable_struct __iomem *cfgtable)
62710ae1c   Stephen M. Cameron   cciss: do a bette...
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
  {
  
  	char *driver_ver, *old_driver_ver;
  	int rc, size = sizeof(cfgtable->driver_version);
  
  	old_driver_ver = kmalloc(2 * size, GFP_KERNEL);
  	if (!old_driver_ver)
  		return -ENOMEM;
  	driver_ver = old_driver_ver + size;
  
  	/* After a reset, the 32 bytes of "driver version" in the cfgtable
  	 * should have been changed, otherwise we know the reset failed.
  	 */
  	init_driver_version(old_driver_ver, size);
  	read_driver_ver_from_cfgtable(cfgtable, driver_ver);
  	rc = !memcmp(driver_ver, old_driver_ver, size);
  	kfree(old_driver_ver);
  	return rc;
  }
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4602
4603
  /* This does a hard reset of the controller using PCI power management
   * states or using the doorbell register. */
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4604
  static int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4605
  {
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4606
4607
4608
4609
4610
  	u64 cfg_offset;
  	u32 cfg_base_addr;
  	u64 cfg_base_addr_index;
  	void __iomem *vaddr;
  	unsigned long paddr;
62710ae1c   Stephen M. Cameron   cciss: do a bette...
4611
  	u32 misc_fw_support;
f442e64b9   Stephen M. Cameron   cciss: Use kernel...
4612
  	int rc;
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4613
  	CfgTable_struct __iomem *cfgtable;
bf2e2e6b8   Stephen M. Cameron   cciss: use new do...
4614
  	u32 use_doorbell;
058a0f9f3   Stephen M. Cameron   cciss: forbid har...
4615
  	u32 board_id;
f442e64b9   Stephen M. Cameron   cciss: Use kernel...
4616
  	u16 command_register;
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4617
4618
4619
4620
4621
4622
4623
4624
4625
  
  	/* For controllers as old a the p600, this is very nearly
  	 * the same thing as
  	 *
  	 * pci_save_state(pci_dev);
  	 * pci_set_power_state(pci_dev, PCI_D3hot);
  	 * pci_set_power_state(pci_dev, PCI_D0);
  	 * pci_restore_state(pci_dev);
  	 *
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4626
4627
4628
4629
  	 * For controllers newer than the P600, the pci power state
  	 * method of resetting doesn't work so we have another way
  	 * using the doorbell register.
  	 */
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4630

058a0f9f3   Stephen M. Cameron   cciss: forbid har...
4631
4632
4633
4634
4635
4636
4637
  	/* Exclude 640x boards.  These are two pci devices in one slot
  	 * which share a battery backed cache module.  One controls the
  	 * cache, the other accesses the cache through the one that controls
  	 * it.  If we reset the one controlling the cache, the other will
  	 * likely not be happy.  Just forbid resetting this conjoined mess.
  	 */
  	cciss_lookup_board_id(pdev, &board_id);
ec52d5f1c   Stephen M. Cameron   cciss: do not att...
4638
  	if (!ctlr_is_resettable(board_id)) {
058a0f9f3   Stephen M. Cameron   cciss: forbid har...
4639
4640
  		dev_warn(&pdev->dev, "Cannot reset Smart Array 640x "
  				"due to shared cache module.");
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4641
4642
  		return -ENODEV;
  	}
ec52d5f1c   Stephen M. Cameron   cciss: do not att...
4643
4644
4645
  	/* if controller is soft- but not hard resettable... */
  	if (!ctlr_is_hard_resettable(board_id))
  		return -ENOTSUPP; /* try soft reset later. */
f442e64b9   Stephen M. Cameron   cciss: Use kernel...
4646
4647
4648
4649
4650
4651
4652
  	/* Save the PCI command register */
  	pci_read_config_word(pdev, 4, &command_register);
  	/* Turn the board off.  This is so that later pci_restore_state()
  	 * won't turn the board on before the rest of config space is ready.
  	 */
  	pci_disable_device(pdev);
  	pci_save_state(pdev);
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4653

a6528d017   Stephen M. Cameron   cciss: fix hard r...
4654
4655
4656
4657
4658
4659
4660
  	/* find the first memory BAR, so we can find the cfg table */
  	rc = cciss_pci_find_memory_BAR(pdev, &paddr);
  	if (rc)
  		return rc;
  	vaddr = remap_pci_mem(paddr, 0x250);
  	if (!vaddr)
  		return -ENOMEM;
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4661

a6528d017   Stephen M. Cameron   cciss: fix hard r...
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
  	/* find cfgtable in order to check if reset via doorbell is supported */
  	rc = cciss_find_cfg_addrs(pdev, vaddr, &cfg_base_addr,
  					&cfg_base_addr_index, &cfg_offset);
  	if (rc)
  		goto unmap_vaddr;
  	cfgtable = remap_pci_mem(pci_resource_start(pdev,
  		       cfg_base_addr_index) + cfg_offset, sizeof(*cfgtable));
  	if (!cfgtable) {
  		rc = -ENOMEM;
  		goto unmap_vaddr;
  	}
62710ae1c   Stephen M. Cameron   cciss: do a bette...
4673
4674
4675
  	rc = write_driver_ver_to_cfgtable(cfgtable);
  	if (rc)
  		goto unmap_vaddr;
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4676

bf2e2e6b8   Stephen M. Cameron   cciss: use new do...
4677
4678
  	/* If reset via doorbell register is supported, use that.
  	 * There are two such methods.  Favor the newest method.
75230ff27   Stephen M. Cameron   cciss: disable do...
4679
  	 */
bf2e2e6b8   Stephen M. Cameron   cciss: use new do...
4680
4681
4682
4683
4684
4685
  	misc_fw_support = readl(&cfgtable->misc_fw_support);
  	use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET2;
  	if (use_doorbell) {
  		use_doorbell = DOORBELL_CTLR_RESET2;
  	} else {
  		use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
063d2cf72   Stephen M. Cameron   cciss: do not use...
4686
4687
4688
4689
4690
4691
4692
4693
4694
  		if (use_doorbell) {
  			dev_warn(&pdev->dev, "Controller claims that "
  				"'Bit 2 doorbell reset' is "
  				"supported, but not 'bit 5 doorbell reset'.  "
  				"Firmware update is recommended.
  ");
  			rc = -ENOTSUPP; /* use the soft reset */
  			goto unmap_cfgtable;
  		}
bf2e2e6b8   Stephen M. Cameron   cciss: use new do...
4695
  	}
75230ff27   Stephen M. Cameron   cciss: disable do...
4696

a6528d017   Stephen M. Cameron   cciss: fix hard r...
4697
4698
4699
  	rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
  	if (rc)
  		goto unmap_cfgtable;
f442e64b9   Stephen M. Cameron   cciss: Use kernel...
4700
4701
4702
4703
4704
4705
  	pci_restore_state(pdev);
  	rc = pci_enable_device(pdev);
  	if (rc) {
  		dev_warn(&pdev->dev, "failed to enable device.
  ");
  		goto unmap_cfgtable;
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4706
  	}
f442e64b9   Stephen M. Cameron   cciss: Use kernel...
4707
  	pci_write_config_word(pdev, 4, command_register);
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4708

a6528d017   Stephen M. Cameron   cciss: fix hard r...
4709
4710
4711
  	/* Some devices (notably the HP Smart Array 5i Controller)
  	   need a little pause here */
  	msleep(CCISS_POST_RESET_PAUSE_MSECS);
afa842fa6   Stephen M. Cameron   cciss: fix board ...
4712
  	/* Wait for board to become not ready, then ready. */
59ec86bb9   Stephen M. Cameron   cciss: clarify me...
4713
4714
  	dev_info(&pdev->dev, "Waiting for board to reset.
  ");
afa842fa6   Stephen M. Cameron   cciss: fix board ...
4715
  	rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
5afe27811   Stephen M. Cameron   cciss: do soft re...
4716
4717
4718
4719
4720
4721
4722
  	if (rc) {
  		dev_warn(&pdev->dev, "Failed waiting for board to hard reset."
  				"  Will try soft reset.
  ");
  		rc = -ENOTSUPP; /* Not expected, but try soft reset later */
  		goto unmap_cfgtable;
  	}
afa842fa6   Stephen M. Cameron   cciss: fix board ...
4723
4724
4725
  	rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_READY);
  	if (rc) {
  		dev_warn(&pdev->dev,
5afe27811   Stephen M. Cameron   cciss: do soft re...
4726
4727
4728
  			"failed waiting for board to become ready "
  			"after hard reset
  ");
afa842fa6   Stephen M. Cameron   cciss: fix board ...
4729
4730
  		goto unmap_cfgtable;
  	}
afa842fa6   Stephen M. Cameron   cciss: fix board ...
4731

62710ae1c   Stephen M. Cameron   cciss: do a bette...
4732
4733
4734
4735
  	rc = controller_reset_failed(vaddr);
  	if (rc < 0)
  		goto unmap_cfgtable;
  	if (rc) {
5afe27811   Stephen M. Cameron   cciss: do soft re...
4736
4737
4738
4739
  		dev_warn(&pdev->dev, "Unable to successfully hard reset "
  			"controller. Will try soft reset.
  ");
  		rc = -ENOTSUPP; /* Not expected, but try soft reset later */
62710ae1c   Stephen M. Cameron   cciss: do a bette...
4740
  	} else {
5afe27811   Stephen M. Cameron   cciss: do soft re...
4741
4742
  		dev_info(&pdev->dev, "Board ready after hard reset.
  ");
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4743
4744
4745
4746
4747
4748
4749
4750
  	}
  
  unmap_cfgtable:
  	iounmap(cfgtable);
  
  unmap_vaddr:
  	iounmap(vaddr);
  	return rc;
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4751
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4752
  static int cciss_init_reset_devices(struct pci_dev *pdev)
83123cb11   Stephen M. Cameron   cciss: factor out...
4753
  {
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4754
  	int rc, i;
83123cb11   Stephen M. Cameron   cciss: factor out...
4755
4756
4757
  
  	if (!reset_devices)
  		return 0;
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4758
4759
  	/* Reset the controller with a PCI power-cycle or via doorbell */
  	rc = cciss_kdump_hard_reset_controller(pdev);
83123cb11   Stephen M. Cameron   cciss: factor out...
4760

a6528d017   Stephen M. Cameron   cciss: fix hard r...
4761
4762
  	/* -ENOTSUPP here means we cannot reset the controller
  	 * but it's already (and still) up and running in
058a0f9f3   Stephen M. Cameron   cciss: forbid har...
4763
4764
  	 * "performant mode".  Or, it might be 640x, which can't reset
  	 * due to concerns about shared bbwc between 6402/6404 pair.
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4765
4766
  	 */
  	if (rc == -ENOTSUPP)
5afe27811   Stephen M. Cameron   cciss: do soft re...
4767
  		return rc; /* just try to do the kdump anyhow. */
a6528d017   Stephen M. Cameron   cciss: fix hard r...
4768
4769
  	if (rc)
  		return -ENODEV;
83123cb11   Stephen M. Cameron   cciss: factor out...
4770
4771
  
  	/* Now try to get the controller to respond to a no-op */
59ec86bb9   Stephen M. Cameron   cciss: clarify me...
4772
4773
  	dev_warn(&pdev->dev, "Waiting for controller to respond to no-op
  ");
83123cb11   Stephen M. Cameron   cciss: factor out...
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
  	for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
  		if (cciss_noop(pdev) == 0)
  			break;
  		else
  			dev_warn(&pdev->dev, "no-op failed%s
  ",
  				(i < CCISS_POST_RESET_NOOP_RETRIES - 1 ?
  					"; re-trying" : ""));
  		msleep(CCISS_POST_RESET_NOOP_INTERVAL_MSECS);
  	}
82eb03cfd   Chip Coldwell   cciss: PCI power ...
4784
4785
  	return 0;
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4786
  static int cciss_allocate_cmd_pool(ctlr_info_t *h)
54dae3432   Stephen M. Cameron   cciss: factor out...
4787
  {
1f118bc47   Akinobu Mita   cciss: cleanup bi...
4788
  	h->cmd_pool_bits = kmalloc(BITS_TO_LONGS(h->nr_cmds) *
54dae3432   Stephen M. Cameron   cciss: factor out...
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
  		sizeof(unsigned long), GFP_KERNEL);
  	h->cmd_pool = pci_alloc_consistent(h->pdev,
  		h->nr_cmds * sizeof(CommandList_struct),
  		&(h->cmd_pool_dhandle));
  	h->errinfo_pool = pci_alloc_consistent(h->pdev,
  		h->nr_cmds * sizeof(ErrorInfo_struct),
  		&(h->errinfo_pool_dhandle));
  	if ((h->cmd_pool_bits == NULL)
  		|| (h->cmd_pool == NULL)
  		|| (h->errinfo_pool == NULL)) {
  		dev_err(&h->pdev->dev, "out of memory");
  		return -ENOMEM;
  	}
  	return 0;
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4804
  static int cciss_allocate_scatterlists(ctlr_info_t *h)
abf7966e6   Stephen M. Cameron   cciss: factor out...
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
  {
  	int i;
  
  	/* zero it, so that on free we need not know how many were alloc'ed */
  	h->scatter_list = kzalloc(h->max_commands *
  				sizeof(struct scatterlist *), GFP_KERNEL);
  	if (!h->scatter_list)
  		return -ENOMEM;
  
  	for (i = 0; i < h->nr_cmds; i++) {
  		h->scatter_list[i] = kmalloc(sizeof(struct scatterlist) *
  						h->maxsgentries, GFP_KERNEL);
  		if (h->scatter_list[i] == NULL) {
  			dev_err(&h->pdev->dev, "could not allocate "
  				"s/g lists
  ");
  			return -ENOMEM;
  		}
  	}
  	return 0;
  }
  
  static void cciss_free_scatterlists(ctlr_info_t *h)
  {
  	int i;
  
  	if (h->scatter_list) {
  		for (i = 0; i < h->nr_cmds; i++)
  			kfree(h->scatter_list[i]);
  		kfree(h->scatter_list);
  	}
  }
54dae3432   Stephen M. Cameron   cciss: factor out...
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
  static void cciss_free_cmd_pool(ctlr_info_t *h)
  {
  	kfree(h->cmd_pool_bits);
  	if (h->cmd_pool)
  		pci_free_consistent(h->pdev,
  			h->nr_cmds * sizeof(CommandList_struct),
  			h->cmd_pool, h->cmd_pool_dhandle);
  	if (h->errinfo_pool)
  		pci_free_consistent(h->pdev,
  			h->nr_cmds * sizeof(ErrorInfo_struct),
  			h->errinfo_pool, h->errinfo_pool_dhandle);
  }
2b48085f9   Stephen M. Cameron   cciss: factor out...
4849
4850
4851
4852
4853
  static int cciss_request_irq(ctlr_info_t *h,
  	irqreturn_t (*msixhandler)(int, void *),
  	irqreturn_t (*intxhandler)(int, void *))
  {
  	if (h->msix_vector || h->msi_vector) {
130495370   Joseph Handzik   cciss: Adds simpl...
4854
  		if (!request_irq(h->intr[h->intr_mode], msixhandler,
6225da481   Stephen M. Cameron   cciss: Add IRQF_S...
4855
  				0, h->devname, h))
2b48085f9   Stephen M. Cameron   cciss: factor out...
4856
4857
  			return 0;
  		dev_err(&h->pdev->dev, "Unable to get msi irq %d"
130495370   Joseph Handzik   cciss: Adds simpl...
4858
4859
  			" for %s
  ", h->intr[h->intr_mode],
2b48085f9   Stephen M. Cameron   cciss: factor out...
4860
4861
4862
  			h->devname);
  		return -1;
  	}
130495370   Joseph Handzik   cciss: Adds simpl...
4863
  	if (!request_irq(h->intr[h->intr_mode], intxhandler,
6225da481   Stephen M. Cameron   cciss: Add IRQF_S...
4864
  			IRQF_SHARED, h->devname, h))
2b48085f9   Stephen M. Cameron   cciss: factor out...
4865
4866
4867
  		return 0;
  	dev_err(&h->pdev->dev, "Unable to get irq %d for %s
  ",
130495370   Joseph Handzik   cciss: Adds simpl...
4868
  		h->intr[h->intr_mode], h->devname);
2b48085f9   Stephen M. Cameron   cciss: factor out...
4869
4870
  	return -1;
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4871
  static int cciss_kdump_soft_reset(ctlr_info_t *h)
5afe27811   Stephen M. Cameron   cciss: do soft re...
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
  {
  	if (cciss_send_reset(h, CTLR_LUNID, CCISS_RESET_TYPE_CONTROLLER)) {
  		dev_warn(&h->pdev->dev, "Resetting array controller failed.
  ");
  		return -EIO;
  	}
  
  	dev_info(&h->pdev->dev, "Waiting for board to soft reset.
  ");
  	if (cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) {
  		dev_warn(&h->pdev->dev, "Soft reset had no effect.
  ");
  		return -1;
  	}
  
  	dev_info(&h->pdev->dev, "Board reset, awaiting READY status.
  ");
  	if (cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY)) {
  		dev_warn(&h->pdev->dev, "Board failed to become ready "
  			"after soft reset.
  ");
  		return -1;
  	}
  
  	return 0;
  }
  
  static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h)
  {
  	int ctlr = h->ctlr;
130495370   Joseph Handzik   cciss: Adds simpl...
4902
  	free_irq(h->intr[h->intr_mode], h);
5afe27811   Stephen M. Cameron   cciss: do soft re...
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
  #ifdef CONFIG_PCI_MSI
  	if (h->msix_vector)
  		pci_disable_msix(h->pdev);
  	else if (h->msi_vector)
  		pci_disable_msi(h->pdev);
  #endif /* CONFIG_PCI_MSI */
  	cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
  	cciss_free_scatterlists(h);
  	cciss_free_cmd_pool(h);
  	kfree(h->blockFetchTable);
  	if (h->reply_pool)
  		pci_free_consistent(h->pdev, h->max_commands * sizeof(__u64),
  				h->reply_pool, h->reply_pool_dhandle);
  	if (h->transtable)
  		iounmap(h->transtable);
  	if (h->cfgtable)
  		iounmap(h->cfgtable);
  	if (h->vaddr)
  		iounmap(h->vaddr);
  	unregister_blkdev(h->major, h->devname);
  	cciss_destroy_hba_sysfs_entry(h);
  	pci_release_regions(h->pdev);
  	kfree(h);
  	hba[ctlr] = NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4928
4929
4930
4931
4932
  /*
   *  This is it.  Find all the controllers and register them.  I really hate
   *  stealing all these major device numbers.
   *  returns the number of block devices registered.
   */
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
4933
  static int cciss_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4934
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4935
  	int i;
799202cbd   Mike Miller   [PATCH] cciss: ad...
4936
  	int j = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4937
  	int rc;
5afe27811   Stephen M. Cameron   cciss: do soft re...
4938
  	int try_soft_reset = 0;
22bece00d   Mike Miller   cciss: fix regres...
4939
  	int dac, return_code;
212a50267   Eric Dumazet   cciss: memory lea...
4940
  	InquiryData_struct *inq_buff;
f70dba836   Stephen M. Cameron   cciss: use consis...
4941
  	ctlr_info_t *h;
5afe27811   Stephen M. Cameron   cciss: do soft re...
4942
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4943

0821e9040   Mike Miller   cciss: bug fix to...
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
  	/*
  	 * By default the cciss driver is used for all older HP Smart Array
  	 * controllers. There are module paramaters that allow a user to
  	 * override this behavior and instead use the hpsa SCSI driver. If
  	 * this is the case cciss may be loaded first from the kdump initrd
  	 * image and cause a kernel panic. So if reset_devices is true and
  	 * cciss_allow_hpsa is set just bail.
  	 */
  	if ((reset_devices) && (cciss_allow_hpsa == 1))
  		return -ENODEV;
83123cb11   Stephen M. Cameron   cciss: factor out...
4954
  	rc = cciss_init_reset_devices(pdev);
5afe27811   Stephen M. Cameron   cciss: do soft re...
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
  	if (rc) {
  		if (rc != -ENOTSUPP)
  			return rc;
  		/* If the reset fails in a particular way (it has no way to do
  		 * a proper hard reset, so returns -ENOTSUPP) we can try to do
  		 * a soft reset once we get the controller configured up to the
  		 * point that it can accept a command.
  		 */
  		try_soft_reset = 1;
  		rc = 0;
  	}
  
  reinit_after_soft_reset:
b2a4a43db   Stephen M. Cameron   cciss: change pri...
4968
  	i = alloc_cciss_hba(pdev);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
4969
  	if (i < 0)
4336548af   Andrew Morton   drivers/block/cci...
4970
  		return -ENOMEM;
1f8ef3806   Mike Miller   [PATCH] cciss: bu...
4971

f70dba836   Stephen M. Cameron   cciss: use consis...
4972
4973
4974
  	h = hba[i];
  	h->pdev = pdev;
  	h->busy_initializing = 1;
130495370   Joseph Handzik   cciss: Adds simpl...
4975
  	h->intr_mode = cciss_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT;
e6e1ee936   Jens Axboe   cciss: reinstate ...
4976
4977
  	INIT_LIST_HEAD(&h->cmpQ);
  	INIT_LIST_HEAD(&h->reqQ);
f70dba836   Stephen M. Cameron   cciss: use consis...
4978
  	mutex_init(&h->busy_shutting_down);
1f8ef3806   Mike Miller   [PATCH] cciss: bu...
4979

f70dba836   Stephen M. Cameron   cciss: use consis...
4980
  	if (cciss_pci_init(h) != 0)
2cfa948c9   Stephen M. Cameron   cciss: Fix multip...
4981
  		goto clean_no_release_regions;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4982

f70dba836   Stephen M. Cameron   cciss: use consis...
4983
4984
  	sprintf(h->devname, "cciss%d", i);
  	h->ctlr = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4985

8a4ec67bd   Stephen M. Cameron   cciss: add cciss_...
4986
4987
4988
4989
  	if (cciss_tape_cmds < 2)
  		cciss_tape_cmds = 2;
  	if (cciss_tape_cmds > 16)
  		cciss_tape_cmds = 16;
f70dba836   Stephen M. Cameron   cciss: use consis...
4990
  	init_completion(&h->scan_wait);
b368c9dd6   Andrew Patterson   cciss: Use one sc...
4991

f70dba836   Stephen M. Cameron   cciss: use consis...
4992
  	if (cciss_create_hba_sysfs_entry(h))
7fe063268   Andrew Patterson   cciss: add cciss ...
4993
  		goto clean0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4994
  	/* configure PCI DMA stuff */
6a35528a8   Yang Hongyang   dma-mapping: repl...
4995
  	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
40aabb581   Bjorn Helgaas   [PATCH] CCISS: an...
4996
  		dac = 1;
284901a90   Yang Hongyang   dma-mapping: repl...
4997
  	else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
40aabb581   Bjorn Helgaas   [PATCH] CCISS: an...
4998
  		dac = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4999
  	else {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
5000
5001
  		dev_err(&h->pdev->dev, "no suitable DMA available
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5002
5003
5004
5005
5006
5007
5008
5009
5010
  		goto clean1;
  	}
  
  	/*
  	 * register with the major number, or get a dynamic major number
  	 * by passing 0 as argument.  This is done for greater than
  	 * 8 controller support.
  	 */
  	if (i < MAX_CTLR_ORIG)
f70dba836   Stephen M. Cameron   cciss: use consis...
5011
5012
  		h->major = COMPAQ_CISS_MAJOR + i;
  	rc = register_blkdev(h->major, h->devname);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5013
  	if (rc == -EBUSY || rc == -EINVAL) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
5014
5015
  		dev_err(&h->pdev->dev,
  		       "Unable to get major number %d for %s "
f70dba836   Stephen M. Cameron   cciss: use consis...
5016
5017
  		       "on hba %d
  ", h->major, h->devname, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5018
  		goto clean1;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5019
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5020
  		if (i >= MAX_CTLR_ORIG)
f70dba836   Stephen M. Cameron   cciss: use consis...
5021
  			h->major = rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5022
5023
5024
  	}
  
  	/* make sure the board interrupts are off */
f70dba836   Stephen M. Cameron   cciss: use consis...
5025
  	h->access.set_intr_mask(h, CCISS_INTR_OFF);
2b48085f9   Stephen M. Cameron   cciss: factor out...
5026
5027
5028
  	rc = cciss_request_irq(h, do_cciss_msix_intr, do_cciss_intx);
  	if (rc)
  		goto clean2;
40aabb581   Bjorn Helgaas   [PATCH] CCISS: an...
5029

b2a4a43db   Stephen M. Cameron   cciss: change pri...
5030
5031
  	dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC
  ",
f70dba836   Stephen M. Cameron   cciss: use consis...
5032
  	       h->devname, pdev->device, pci_name(pdev),
130495370   Joseph Handzik   cciss: Adds simpl...
5033
  	       h->intr[h->intr_mode], dac ? "" : " not");
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5034

54dae3432   Stephen M. Cameron   cciss: factor out...
5035
  	if (cciss_allocate_cmd_pool(h))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5036
  		goto clean4;
5c07a311a   Don Brace   cciss: Add enhanc...
5037

abf7966e6   Stephen M. Cameron   cciss: factor out...
5038
  	if (cciss_allocate_scatterlists(h))
4ee69851c   Dan Carpenter   cciss: handle all...
5039
  		goto clean4;
f70dba836   Stephen M. Cameron   cciss: use consis...
5040
5041
5042
  	h->cmd_sg_list = cciss_allocate_sg_chain_blocks(h,
  		h->chainsize, h->nr_cmds);
  	if (!h->cmd_sg_list && h->chainsize > 0)
5c07a311a   Don Brace   cciss: Add enhanc...
5043
  		goto clean4;
5c07a311a   Don Brace   cciss: Add enhanc...
5044

f70dba836   Stephen M. Cameron   cciss: use consis...
5045
  	spin_lock_init(&h->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5046

7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5047
  	/* Initialize the pdev driver private data.
f70dba836   Stephen M. Cameron   cciss: use consis...
5048
5049
  	   have it point to h.  */
  	pci_set_drvdata(pdev, h);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5050
5051
  	/* command and error info recs zeroed out before
  	   they are used */
1f118bc47   Akinobu Mita   cciss: cleanup bi...
5052
  	bitmap_zero(h->cmd_pool_bits, h->nr_cmds);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5053

f70dba836   Stephen M. Cameron   cciss: use consis...
5054
5055
  	h->num_luns = 0;
  	h->highest_lun = -1;
6ae5ce8e8   Mike Miller   cciss: remove red...
5056
  	for (j = 0; j < CISS_MAX_LUN; j++) {
f70dba836   Stephen M. Cameron   cciss: use consis...
5057
5058
  		h->drv[j] = NULL;
  		h->gendisk[j] = NULL;
6ae5ce8e8   Mike Miller   cciss: remove red...
5059
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5060

5afe27811   Stephen M. Cameron   cciss: do soft re...
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
  	/* At this point, the controller is ready to take commands.
  	 * Now, if reset_devices and the hard reset didn't work, try
  	 * the soft reset and see if that works.
  	 */
  	if (try_soft_reset) {
  
  		/* This is kind of gross.  We may or may not get a completion
  		 * from the soft reset command, and if we do, then the value
  		 * from the fifo may or may not be valid.  So, we wait 10 secs
  		 * after the reset throwing away any completions we get during
  		 * that time.  Unregister the interrupt handler and register
  		 * fake ones to scoop up any residual completions.
  		 */
  		spin_lock_irqsave(&h->lock, flags);
  		h->access.set_intr_mask(h, CCISS_INTR_OFF);
  		spin_unlock_irqrestore(&h->lock, flags);
130495370   Joseph Handzik   cciss: Adds simpl...
5077
  		free_irq(h->intr[h->intr_mode], h);
5afe27811   Stephen M. Cameron   cciss: do soft re...
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
  		rc = cciss_request_irq(h, cciss_msix_discard_completions,
  					cciss_intx_discard_completions);
  		if (rc) {
  			dev_warn(&h->pdev->dev, "Failed to request_irq after "
  				"soft reset.
  ");
  			goto clean4;
  		}
  
  		rc = cciss_kdump_soft_reset(h);
  		if (rc) {
  			dev_warn(&h->pdev->dev, "Soft reset failed.
  ");
  			goto clean4;
  		}
  
  		dev_info(&h->pdev->dev, "Board READY.
  ");
  		dev_info(&h->pdev->dev,
  			"Waiting for stale completions to drain.
  ");
  		h->access.set_intr_mask(h, CCISS_INTR_ON);
  		msleep(10000);
  		h->access.set_intr_mask(h, CCISS_INTR_OFF);
  
  		rc = controller_reset_failed(h->cfgtable);
  		if (rc)
  			dev_info(&h->pdev->dev,
  				"Soft reset appears to have failed.
  ");
  
  		/* since the controller's reset, we have to go back and re-init
  		 * everything.  Easiest to just forget what we've done and do it
  		 * all over again.
  		 */
  		cciss_undo_allocations_after_kdump_soft_reset(h);
  		try_soft_reset = 0;
  		if (rc)
  			/* don't go to clean4, we already unallocated */
  			return -ENODEV;
  
  		goto reinit_after_soft_reset;
  	}
f70dba836   Stephen M. Cameron   cciss: use consis...
5121
  	cciss_scsi_setup(h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5122
5123
  
  	/* Turn the interrupts on so we can service requests */
f70dba836   Stephen M. Cameron   cciss: use consis...
5124
  	h->access.set_intr_mask(h, CCISS_INTR_ON);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5125

22bece00d   Mike Miller   cciss: fix regres...
5126
5127
5128
  	/* Get the firmware version */
  	inq_buff = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL);
  	if (inq_buff == NULL) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
5129
5130
  		dev_err(&h->pdev->dev, "out of memory
  ");
22bece00d   Mike Miller   cciss: fix regres...
5131
5132
  		goto clean4;
  	}
f70dba836   Stephen M. Cameron   cciss: use consis...
5133
  	return_code = sendcmd_withirq(h, CISS_INQUIRY, inq_buff,
b57695fe1   scameron@beardog.cca.cpqcorp.net   cciss: simplify i...
5134
  		sizeof(InquiryData_struct), 0, CTLR_LUNID, TYPE_CMD);
22bece00d   Mike Miller   cciss: fix regres...
5135
  	if (return_code == IO_OK) {
f70dba836   Stephen M. Cameron   cciss: use consis...
5136
5137
5138
5139
  		h->firm_ver[0] = inq_buff->data_byte[32];
  		h->firm_ver[1] = inq_buff->data_byte[33];
  		h->firm_ver[2] = inq_buff->data_byte[34];
  		h->firm_ver[3] = inq_buff->data_byte[35];
22bece00d   Mike Miller   cciss: fix regres...
5140
  	} else {	 /* send command failed */
b2a4a43db   Stephen M. Cameron   cciss: change pri...
5141
  		dev_warn(&h->pdev->dev, "unable to determine firmware"
22bece00d   Mike Miller   cciss: fix regres...
5142
5143
5144
  			" version of controller
  ");
  	}
212a50267   Eric Dumazet   cciss: memory lea...
5145
  	kfree(inq_buff);
22bece00d   Mike Miller   cciss: fix regres...
5146

f70dba836   Stephen M. Cameron   cciss: use consis...
5147
  	cciss_procinit(h);
92c4231ae   Mike Miller   [PATCH] cciss: se...
5148

f70dba836   Stephen M. Cameron   cciss: use consis...
5149
  	h->cciss_max_sectors = 8192;
92c4231ae   Mike Miller   [PATCH] cciss: se...
5150

f70dba836   Stephen M. Cameron   cciss: use consis...
5151
  	rebuild_lun_table(h, 1, 0);
0007a4c90   Stephen M. Cameron   cciss: auto engag...
5152
  	cciss_engage_scsi(h);
f70dba836   Stephen M. Cameron   cciss: use consis...
5153
  	h->busy_initializing = 0;
b88fac630   Stephen M. Cameron   cciss: return 0 f...
5154
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5155

6ae5ce8e8   Mike Miller   cciss: remove red...
5156
  clean4:
54dae3432   Stephen M. Cameron   cciss: factor out...
5157
  	cciss_free_cmd_pool(h);
abf7966e6   Stephen M. Cameron   cciss: factor out...
5158
  	cciss_free_scatterlists(h);
f70dba836   Stephen M. Cameron   cciss: use consis...
5159
  	cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
130495370   Joseph Handzik   cciss: Adds simpl...
5160
  	free_irq(h->intr[h->intr_mode], h);
6ae5ce8e8   Mike Miller   cciss: remove red...
5161
  clean2:
f70dba836   Stephen M. Cameron   cciss: use consis...
5162
  	unregister_blkdev(h->major, h->devname);
6ae5ce8e8   Mike Miller   cciss: remove red...
5163
  clean1:
f70dba836   Stephen M. Cameron   cciss: use consis...
5164
  	cciss_destroy_hba_sysfs_entry(h);
7fe063268   Andrew Patterson   cciss: add cciss ...
5165
  clean0:
2cfa948c9   Stephen M. Cameron   cciss: Fix multip...
5166
5167
  	pci_release_regions(pdev);
  clean_no_release_regions:
f70dba836   Stephen M. Cameron   cciss: use consis...
5168
  	h->busy_initializing = 0;
9cef0d2f4   Stephen M. Cameron   cciss: Dynamicall...
5169

872225ca7   Mike Miller   [PATCH] cciss: re...
5170
5171
5172
5173
  	/*
  	 * Deliberately omit pci_disable_device(): it does something nasty to
  	 * Smart Array controllers that pci_enable_device does not undo
  	 */
799202cbd   Mike Miller   [PATCH] cciss: ad...
5174
  	pci_set_drvdata(pdev, NULL);
f70dba836   Stephen M. Cameron   cciss: use consis...
5175
  	free_hba(h);
4336548af   Andrew Morton   drivers/block/cci...
5176
  	return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5177
  }
e9ca75b53   Gerald Britton   cciss: Fix pci_dr...
5178
  static void cciss_shutdown(struct pci_dev *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5179
  {
29009a036   Stephen M. Cameron   cciss: clean up c...
5180
5181
  	ctlr_info_t *h;
  	char *flush_buf;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5182
  	int return_code;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5183

29009a036   Stephen M. Cameron   cciss: clean up c...
5184
5185
5186
  	h = pci_get_drvdata(pdev);
  	flush_buf = kzalloc(4, GFP_KERNEL);
  	if (!flush_buf) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
5187
5188
  		dev_warn(&h->pdev->dev, "cache not flushed, out of memory.
  ");
e9ca75b53   Gerald Britton   cciss: Fix pci_dr...
5189
  		return;
e9ca75b53   Gerald Britton   cciss: Fix pci_dr...
5190
  	}
29009a036   Stephen M. Cameron   cciss: clean up c...
5191
  	/* write all data in the battery backed cache to disk */
f70dba836   Stephen M. Cameron   cciss: use consis...
5192
  	return_code = sendcmd_withirq(h, CCISS_CACHE_FLUSH, flush_buf,
29009a036   Stephen M. Cameron   cciss: clean up c...
5193
5194
5195
  		4, 0, CTLR_LUNID, TYPE_CMD);
  	kfree(flush_buf);
  	if (return_code != IO_OK)
b2a4a43db   Stephen M. Cameron   cciss: change pri...
5196
5197
  		dev_warn(&h->pdev->dev, "Error flushing cache
  ");
29009a036   Stephen M. Cameron   cciss: clean up c...
5198
  	h->access.set_intr_mask(h, CCISS_INTR_OFF);
130495370   Joseph Handzik   cciss: Adds simpl...
5199
  	free_irq(h->intr[h->intr_mode], h);
e9ca75b53   Gerald Britton   cciss: Fix pci_dr...
5200
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
5201
  static int cciss_enter_simple_mode(struct ctlr_info *h)
130495370   Joseph Handzik   cciss: Adds simpl...
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
  {
  	u32 trans_support;
  
  	trans_support = readl(&(h->cfgtable->TransportSupport));
  	if (!(trans_support & SIMPLE_MODE))
  		return -ENOTSUPP;
  
  	h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
  	writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
  	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
  	cciss_wait_for_mode_change_ack(h);
  	print_cfg_table(h);
  	if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
  		dev_warn(&h->pdev->dev, "unable to get board into simple mode
  ");
  		return -ENODEV;
  	}
  	h->transMethod = CFGTBL_Trans_Simple;
  	return 0;
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
5222
  static void cciss_remove_one(struct pci_dev *pdev)
e9ca75b53   Gerald Britton   cciss: Fix pci_dr...
5223
  {
f70dba836   Stephen M. Cameron   cciss: use consis...
5224
  	ctlr_info_t *h;
e9ca75b53   Gerald Britton   cciss: Fix pci_dr...
5225
  	int i, j;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5226
  	if (pci_get_drvdata(pdev) == NULL) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
5227
5228
  		dev_err(&pdev->dev, "Unable to remove device
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5229
5230
  		return;
  	}
0a9279cc7   Mike Miller   cciss: kernel sca...
5231

f70dba836   Stephen M. Cameron   cciss: use consis...
5232
5233
  	h = pci_get_drvdata(pdev);
  	i = h->ctlr;
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5234
  	if (hba[i] == NULL) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
5235
5236
  		dev_err(&pdev->dev, "device appears to already be removed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5237
5238
  		return;
  	}
b6550777a   Bjorn Helgaas   [PATCH] cciss: un...
5239

f70dba836   Stephen M. Cameron   cciss: use consis...
5240
  	mutex_lock(&h->busy_shutting_down);
0a9279cc7   Mike Miller   cciss: kernel sca...
5241

f70dba836   Stephen M. Cameron   cciss: use consis...
5242
5243
5244
  	remove_from_scan_list(h);
  	remove_proc_entry(h->devname, proc_cciss);
  	unregister_blkdev(h->major, h->devname);
b6550777a   Bjorn Helgaas   [PATCH] cciss: un...
5245
5246
5247
  
  	/* remove it from the disk list */
  	for (j = 0; j < CISS_MAX_LUN; j++) {
f70dba836   Stephen M. Cameron   cciss: use consis...
5248
  		struct gendisk *disk = h->gendisk[j];
b6550777a   Bjorn Helgaas   [PATCH] cciss: un...
5249
  		if (disk) {
165125e1e   Jens Axboe   [BLOCK] Get rid o...
5250
  			struct request_queue *q = disk->queue;
b6550777a   Bjorn Helgaas   [PATCH] cciss: un...
5251

097d02645   Stephen M. Cameron   cciss: Rearrange ...
5252
  			if (disk->flags & GENHD_FL_UP) {
f70dba836   Stephen M. Cameron   cciss: use consis...
5253
  				cciss_destroy_ld_sysfs_entry(h, j, 1);
b6550777a   Bjorn Helgaas   [PATCH] cciss: un...
5254
  				del_gendisk(disk);
097d02645   Stephen M. Cameron   cciss: Rearrange ...
5255
  			}
b6550777a   Bjorn Helgaas   [PATCH] cciss: un...
5256
5257
5258
5259
  			if (q)
  				blk_cleanup_queue(q);
  		}
  	}
ba198efb5   Mike Miller   cciss: fix bug if...
5260
  #ifdef CONFIG_CISS_SCSI_TAPE
f70dba836   Stephen M. Cameron   cciss: use consis...
5261
  	cciss_unregister_scsi(h);	/* unhook from SCSI subsystem */
ba198efb5   Mike Miller   cciss: fix bug if...
5262
  #endif
b6550777a   Bjorn Helgaas   [PATCH] cciss: un...
5263

e9ca75b53   Gerald Britton   cciss: Fix pci_dr...
5264
  	cciss_shutdown(pdev);
fb86a35b9   Mike Miller   [PATCH] cciss: ad...
5265
5266
  
  #ifdef CONFIG_PCI_MSI
f70dba836   Stephen M. Cameron   cciss: use consis...
5267
5268
5269
5270
  	if (h->msix_vector)
  		pci_disable_msix(h->pdev);
  	else if (h->msi_vector)
  		pci_disable_msi(h->pdev);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5271
  #endif				/* CONFIG_PCI_MSI */
fb86a35b9   Mike Miller   [PATCH] cciss: ad...
5272

f70dba836   Stephen M. Cameron   cciss: use consis...
5273
5274
5275
  	iounmap(h->transtable);
  	iounmap(h->cfgtable);
  	iounmap(h->vaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5276

54dae3432   Stephen M. Cameron   cciss: factor out...
5277
  	cciss_free_cmd_pool(h);
5c07a311a   Don Brace   cciss: Add enhanc...
5278
  	/* Free up sg elements */
f70dba836   Stephen M. Cameron   cciss: use consis...
5279
5280
5281
5282
  	for (j = 0; j < h->nr_cmds; j++)
  		kfree(h->scatter_list[j]);
  	kfree(h->scatter_list);
  	cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
e363e0143   Stephen M. Cameron   cciss: fix reply ...
5283
5284
5285
5286
  	kfree(h->blockFetchTable);
  	if (h->reply_pool)
  		pci_free_consistent(h->pdev, h->max_commands * sizeof(__u64),
  				h->reply_pool, h->reply_pool_dhandle);
872225ca7   Mike Miller   [PATCH] cciss: re...
5287
5288
5289
5290
  	/*
  	 * Deliberately omit pci_disable_device(): it does something nasty to
  	 * Smart Array controllers that pci_enable_device does not undo
  	 */
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5291
  	pci_release_regions(pdev);
4e570309e   Bjorn Helgaas   [PATCH] CCISS: re...
5292
  	pci_set_drvdata(pdev, NULL);
f70dba836   Stephen M. Cameron   cciss: use consis...
5293
5294
5295
  	cciss_destroy_hba_sysfs_entry(h);
  	mutex_unlock(&h->busy_shutting_down);
  	free_hba(h);
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5296
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5297
5298
  
  static struct pci_driver cciss_pci_driver = {
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5299
5300
  	.name = "cciss",
  	.probe = cciss_init_one,
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
5301
  	.remove = cciss_remove_one,
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5302
  	.id_table = cciss_pci_device_id,	/* id_table */
e9ca75b53   Gerald Britton   cciss: Fix pci_dr...
5303
  	.shutdown = cciss_shutdown,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5304
5305
5306
5307
  };
  
  /*
   *  This is it.  Register the PCI driver information for the cards we control
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5308
   *  the OS will call our registered routines when it finds one of our cards.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5309
5310
5311
   */
  static int __init cciss_init(void)
  {
7fe063268   Andrew Patterson   cciss: add cciss ...
5312
  	int err;
10cbda97e   Jens Axboe   cciss: add BUILD_...
5313
5314
5315
5316
5317
  	/*
  	 * The hardware requires that commands are aligned on a 64-bit
  	 * boundary. Given that we use pci_alloc_consistent() to allocate an
  	 * array of them, the size must be a multiple of 8 bytes.
  	 */
1b7d0d28a   Stephen M. Cameron   cciss: detect bad...
5318
  	BUILD_BUG_ON(sizeof(CommandList_struct) % COMMANDLIST_ALIGNMENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5319
5320
  	printk(KERN_INFO DRIVER_NAME "
  ");
7fe063268   Andrew Patterson   cciss: add cciss ...
5321
5322
5323
  	err = bus_register(&cciss_bus_type);
  	if (err)
  		return err;
b368c9dd6   Andrew Patterson   cciss: Use one sc...
5324
5325
5326
5327
5328
5329
  	/* Start the scan thread */
  	cciss_scan_thread = kthread_run(scan_thread, NULL, "cciss_scan");
  	if (IS_ERR(cciss_scan_thread)) {
  		err = PTR_ERR(cciss_scan_thread);
  		goto err_bus_unregister;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5330
  	/* Register for our PCI devices */
7fe063268   Andrew Patterson   cciss: add cciss ...
5331
5332
  	err = pci_register_driver(&cciss_pci_driver);
  	if (err)
b368c9dd6   Andrew Patterson   cciss: Use one sc...
5333
  		goto err_thread_stop;
7fe063268   Andrew Patterson   cciss: add cciss ...
5334

617e13442   Stephen M. Cameron   cciss: Dynamicall...
5335
  	return err;
7fe063268   Andrew Patterson   cciss: add cciss ...
5336

b368c9dd6   Andrew Patterson   cciss: Use one sc...
5337
5338
5339
  err_thread_stop:
  	kthread_stop(cciss_scan_thread);
  err_bus_unregister:
7fe063268   Andrew Patterson   cciss: add cciss ...
5340
  	bus_unregister(&cciss_bus_type);
b368c9dd6   Andrew Patterson   cciss: Use one sc...
5341

7fe063268   Andrew Patterson   cciss: add cciss ...
5342
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5343
5344
5345
5346
5347
5348
5349
5350
  }
  
  static void __exit cciss_cleanup(void)
  {
  	int i;
  
  	pci_unregister_driver(&cciss_pci_driver);
  	/* double check that all controller entrys have been removed */
7c8328355   Bjorn Helgaas   [PATCH] CCISS: ru...
5351
5352
  	for (i = 0; i < MAX_CTLR; i++) {
  		if (hba[i] != NULL) {
b2a4a43db   Stephen M. Cameron   cciss: change pri...
5353
5354
5355
  			dev_warn(&hba[i]->pdev->dev,
  				"had to remove controller
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5356
5357
5358
  			cciss_remove_one(hba[i]->pdev);
  		}
  	}
b368c9dd6   Andrew Patterson   cciss: Use one sc...
5359
  	kthread_stop(cciss_scan_thread);
90fdb0b98   Jens Axboe   cciss: fix proc w...
5360
5361
  	if (proc_cciss)
  		remove_proc_entry("driver/cciss", NULL);
7fe063268   Andrew Patterson   cciss: add cciss ...
5362
  	bus_unregister(&cciss_bus_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5363
5364
5365
5366
  }
  
  module_init(cciss_init);
  module_exit(cciss_cleanup);