1 // MegaRAID SAS boot support.
3 // Copyright (C) 2012 Hannes Reinecke, SUSE Linux Products GmbH
6 // Hannes Reinecke <hare@suse.de>
8 // based on virtio-scsi.c which is written by:
9 // Paolo Bonzini <pbonzini@redhat.com>
11 // This file may be distributed under the terms of the GNU LGPLv3 license.
13 #include "biosvar.h" // GET_GLOBALFLAT
14 #include "block.h" // struct drive_s
15 #include "blockcmd.h" // scsi_drive_setup
16 #include "config.h" // CONFIG_*
17 #include "malloc.h" // free
18 #include "output.h" // dprintf
19 #include "pci.h" // foreachpci
20 #include "pci_ids.h" // PCI_DEVICE_ID_XXX
21 #include "pci_regs.h" // PCI_VENDOR_ID
22 #include "stacks.h" // yield
23 #include "std/disk.h" // DISK_RET_SUCCESS
24 #include "string.h" // memset
25 #include "util.h" // timer_calc
27 #define MFI_DB 0x0 // Doorbell
28 #define MFI_OMSG0 0x18 // Outbound message 0
29 #define MFI_IDB 0x20 // Inbound doorbell
30 #define MFI_ODB 0x2c // Outbound doorbell
31 #define MFI_IQP 0x40 // Inbound queue port
32 #define MFI_OSP0 0xb0 // Outbound scratch pad0
33 #define MFI_IQPL 0xc0 // Inbound queue port (low bytes)
34 #define MFI_IQPH 0xc4 // Inbound queue port (high bytes)
36 #define MFI_STATE_MASK 0xf0000000
37 #define MFI_STATE_WAIT_HANDSHAKE 0x60000000
38 #define MFI_STATE_BOOT_MESSAGE_PENDING 0x90000000
39 #define MFI_STATE_READY 0xb0000000
40 #define MFI_STATE_OPERATIONAL 0xc0000000
41 #define MFI_STATE_FAULT 0xf0000000
56 struct megasas_cmd_frame {
58 u8 sense_len; /*01h */
59 u8 cmd_status; /*02h */
60 u8 scsi_status; /*03h */
62 u8 target_id; /*04h */
65 u8 sge_count; /*07h */
68 u32 context_64; /*0Ch */
72 u32 data_xfer_len; /*14h */
78 u32 sgl_addr; /*28h */
83 u32 sense_buf_lo; /*18h */
84 u32 sense_buf_hi; /*1Ch */
86 u32 sgl_addr; /*30h */
93 } __attribute__ ((packed));
95 struct mfi_ld_list_s {
106 } __attribute__ ((packed));
108 #define MEGASAS_POLL_TIMEOUT 60000 // 60 seconds polling timeout
110 struct megasas_lun_s {
111 struct drive_s drive;
112 struct megasas_cmd_frame *frame;
119 static int megasas_fire_cmd(u16 pci_id, u32 ioaddr,
120 struct megasas_cmd_frame *frame)
122 u32 frame_addr = (u32)frame;
126 dprintf(2, "Frame 0x%x\n", frame_addr);
127 if (pci_id == PCI_DEVICE_ID_LSI_SAS2004 ||
128 pci_id == PCI_DEVICE_ID_LSI_SAS2008) {
129 outl(0, ioaddr + MFI_IQPH);
130 outl(frame_addr | frame_count << 1 | 1, ioaddr + MFI_IQPL);
131 } else if (pci_id == PCI_DEVICE_ID_DELL_PERC5 ||
132 pci_id == PCI_DEVICE_ID_LSI_SAS1064R ||
133 pci_id == PCI_DEVICE_ID_LSI_VERDE_ZCR) {
134 outl(frame_addr >> 3 | frame_count, ioaddr + MFI_IQP);
136 outl(frame_addr | frame_count << 1 | 1, ioaddr + MFI_IQP);
139 u32 end = timer_calc(MEGASAS_POLL_TIMEOUT);
142 cmd_state = GET_LOWFLAT(frame->cmd_status);
143 if (cmd_state != 0xff)
145 if (timer_check(end)) {
151 } while (cmd_state == 0xff);
153 if (cmd_state == 0 || cmd_state == 0x2d)
155 dprintf(1, "ERROR: Frame 0x%x, status 0x%x\n", frame_addr, cmd_state);
160 megasas_process_op(struct disk_op_s *op)
163 return DISK_RET_EBADTRACK;
165 int blocksize = scsi_fill_cmd(op, cdb, sizeof(cdb));
167 return default_process_op(op);
168 struct megasas_lun_s *mlun_gf =
169 container_of(op->drive_gf, struct megasas_lun_s, drive);
170 struct megasas_cmd_frame *frame = GET_GLOBALFLAT(mlun_gf->frame);
171 u16 pci_id = GET_GLOBALFLAT(mlun_gf->pci_id);
174 memset_fl(frame, 0, sizeof(*frame));
175 SET_LOWFLAT(frame->cmd, MFI_CMD_LD_SCSI_IO);
176 SET_LOWFLAT(frame->cmd_status, 0xFF);
177 SET_LOWFLAT(frame->target_id, GET_GLOBALFLAT(mlun_gf->target));
178 SET_LOWFLAT(frame->lun, GET_GLOBALFLAT(mlun_gf->lun));
179 SET_LOWFLAT(frame->flags, 0x0001);
180 SET_LOWFLAT(frame->data_xfer_len, op->count * blocksize);
181 SET_LOWFLAT(frame->cdb_len, 16);
183 for (i = 0; i < 16; i++) {
184 SET_LOWFLAT(frame->pthru.cdb[i], cdb[i]);
186 dprintf(2, "pthru cmd 0x%x count %d bs %d\n",
187 cdb[0], op->count, blocksize);
190 SET_LOWFLAT(frame->pthru.sgl_addr, (u32)op->buf_fl);
191 SET_LOWFLAT(frame->pthru.sgl_len, op->count * blocksize);
192 SET_LOWFLAT(frame->sge_count, 1);
194 SET_LOWFLAT(frame->context, (u32)frame);
196 if (megasas_fire_cmd(pci_id, GET_GLOBALFLAT(mlun_gf->iobase), frame) == 0)
197 return DISK_RET_SUCCESS;
199 dprintf(2, "pthru cmd 0x%x failed\n", cdb[0]);
200 return DISK_RET_EBADTRACK;
204 megasas_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun)
206 struct megasas_lun_s *mlun = malloc_fseg(sizeof(*mlun));
214 memset(mlun, 0, sizeof(*mlun));
215 mlun->drive.type = DTYPE_MEGASAS;
216 mlun->drive.cntl_id = pci->bdf;
217 mlun->pci_id = pci->device;
218 mlun->target = target;
220 mlun->iobase = iobase;
221 mlun->frame = memalign_low(256, sizeof(struct megasas_cmd_frame));
227 name = znprintf(36, "MegaRAID SAS (PCI %02x:%02x.%x) LD %d:%d",
228 pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
229 pci_bdf_to_fn(pci->bdf), target, lun);
230 prio = bootprio_find_scsi_device(pci, target, lun);
231 ret = scsi_drive_setup(&mlun->drive, name, prio);
242 static void megasas_scan_target(struct pci_device *pci, u32 iobase)
244 struct mfi_ld_list_s ld_list;
245 struct megasas_cmd_frame *frame = memalign_tmp(256, sizeof(*frame));
251 memset(&ld_list, 0, sizeof(ld_list));
252 memset_fl(frame, 0, sizeof(*frame));
254 frame->cmd = MFI_CMD_DCMD;
255 frame->cmd_status = 0xFF;
256 frame->sge_count = 1;
257 frame->flags = 0x0011;
258 frame->data_xfer_len = sizeof(ld_list);
259 frame->dcmd.opcode = 0x03010000;
260 frame->dcmd.sgl_addr = (u32)MAKE_FLATPTR(GET_SEG(SS), &ld_list);
261 frame->dcmd.sgl_len = sizeof(ld_list);
262 frame->context = (u32)frame;
264 if (megasas_fire_cmd(pci->device, iobase, frame) == 0) {
265 dprintf(2, "%d LD found\n", ld_list.count);
267 for (i = 0; i < ld_list.count; i++) {
268 dprintf(2, "LD %d:%d state 0x%x\n",
269 ld_list.lds[i].target, ld_list.lds[i].lun,
270 ld_list.lds[i].state);
271 if (ld_list.lds[i].state != 0) {
272 megasas_add_lun(pci, iobase,
273 ld_list.lds[i].target, ld_list.lds[i].lun);
279 static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr)
281 u32 fw_state = 0, new_state, mfi_flags = 0;
283 if (pci->device == PCI_DEVICE_ID_LSI_SAS1064R ||
284 pci->device == PCI_DEVICE_ID_DELL_PERC5)
285 new_state = inl(ioaddr + MFI_OMSG0) & MFI_STATE_MASK;
287 new_state = inl(ioaddr + MFI_OSP0) & MFI_STATE_MASK;
289 while (fw_state != new_state) {
291 case MFI_STATE_FAULT:
292 dprintf(1, "ERROR: fw in fault state\n");
295 case MFI_STATE_WAIT_HANDSHAKE:
298 case MFI_STATE_BOOT_MESSAGE_PENDING:
300 if (pci->device == PCI_DEVICE_ID_LSI_SAS2004 ||
301 pci->device == PCI_DEVICE_ID_LSI_SAS2008 ||
302 pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
303 pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
304 outl(mfi_flags, ioaddr + MFI_DB);
306 outl(mfi_flags, ioaddr + MFI_IDB);
309 case MFI_STATE_OPERATIONAL:
311 if (pci->device == PCI_DEVICE_ID_LSI_SAS2004 ||
312 pci->device == PCI_DEVICE_ID_LSI_SAS2008 ||
313 pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
314 pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
315 outl(mfi_flags, ioaddr + MFI_DB);
316 if (pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
317 pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
321 while (j < MEGASAS_POLL_TIMEOUT) {
322 doorbell = inl(ioaddr + MFI_DB) & 1;
330 outl(mfi_flags, ioaddr + MFI_IDB);
333 case MFI_STATE_READY:
334 dprintf(2, "MegaRAID SAS fw ready\n");
337 // The current state should not last longer than poll timeout
338 u32 end = timer_calc(MEGASAS_POLL_TIMEOUT);
340 if (timer_check(end)) {
344 fw_state = new_state;
345 if (pci->device == PCI_DEVICE_ID_LSI_SAS1064R ||
346 pci->device == PCI_DEVICE_ID_DELL_PERC5)
347 new_state = inl(ioaddr + MFI_OMSG0) & MFI_STATE_MASK;
349 new_state = inl(ioaddr + MFI_OSP0) & MFI_STATE_MASK;
350 if (new_state != fw_state) {
355 dprintf(1, "ERROR: fw in state %x\n", new_state & MFI_STATE_MASK);
360 init_megasas(struct pci_device *pci)
363 u32 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_2)
364 & PCI_BASE_ADDRESS_IO_MASK;
367 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
368 & PCI_BASE_ADDRESS_IO_MASK;
370 dprintf(1, "found MegaRAID SAS at %02x:%02x.%x, io @ %x\n",
371 pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
372 pci_bdf_to_fn(bdf), iobase);
374 pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
375 PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
377 if (megasas_transition_to_ready(pci, iobase) == 0)
378 megasas_scan_target(pci, iobase);
390 dprintf(3, "init megasas\n");
392 struct pci_device *pci;
394 if (pci->vendor != PCI_VENDOR_ID_LSI_LOGIC &&
395 pci->vendor != PCI_VENDOR_ID_DELL)
397 if (pci->device == PCI_DEVICE_ID_LSI_SAS1064R ||
398 pci->device == PCI_DEVICE_ID_LSI_SAS1078 ||
399 pci->device == PCI_DEVICE_ID_LSI_SAS1078DE ||
400 pci->device == PCI_DEVICE_ID_LSI_SAS2108 ||
401 pci->device == PCI_DEVICE_ID_LSI_SAS2108E ||
402 pci->device == PCI_DEVICE_ID_LSI_SAS2004 ||
403 pci->device == PCI_DEVICE_ID_LSI_SAS2008 ||
404 pci->device == PCI_DEVICE_ID_LSI_VERDE_ZCR ||
405 pci->device == PCI_DEVICE_ID_DELL_PERC5 ||
406 pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
407 pci->device == PCI_DEVICE_ID_LSI_SAS3108)