1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
14 */
15
16 #include <sys/sdt.h>
17 #include "cpqary3.h"
18
19 /*
20 * Local Functions Definitions
21 */
22
23 int cpqary3_target_geometry(struct scsi_address *);
24 int8_t cpqary3_detect_target_geometry(cpqary3_t *);
25
26 /*
27 * Function : cpqary3_read_conf_file
28 * Description : This routine reads the driver configuration file.
29 * Called By : cpqary3_attach()
30 * Parameters : device-information pointer, per_controller
31 * Calls : None
32 * Return Values: None
33 */
34 void
cpqary3_read_conf_file(dev_info_t * dip,cpqary3_t * cpqary3p)35 cpqary3_read_conf_file(dev_info_t *dip, cpqary3_t *cpqary3p)
36 {
37 char *ptr;
38
39 cpqary3p->noe_support = 0;
40
41 /*
42 * Plugin the code necessary to read from driver's conf file.
43 * As of now, we are not interested in reading the onf file
44 * for any purpose.
45 *
46 * eg. :
47 *
48 * retvalue = ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
49 * "cpqary3_online_debug", -1);
50 */
51
52 /*
53 * We are calling ddi_prop_lookup_string
54 * which gets the property value, which is passed at
55 * the grub menu. If the user wants to use the older
56 * target mapping algorithm,(prior to 1.80)at the grub menu
57 * "cpqary3_tgtmap=off" should be entered. if this
58 * string is entered, then we will set the
59 * value of the variable legacy_mapping to one, which
60 * will be used in
61 * cpqary3_detect_target_geometry()
62 * and cpqary3_probe4LVs(), to decide on the
63 * mapping algorithm
64 */
65
66 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
67 "cpqary3_tgtmap", &ptr) == DDI_PROP_SUCCESS) {
68 if (strcmp("off", ptr) == 0) {
69 cpqary3p->legacy_mapping = 1;
70 }
71 ddi_prop_free(ptr);
72 }
73
74 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
75 "cpqary3_noesupport", &ptr) == DDI_PROP_SUCCESS) {
76 if (strcmp("on", ptr) == 0) {
77 cpqary3p->noe_support = 1;
78 }
79 if (strcmp("off", ptr) == 0) {
80 cpqary3p->noe_support = 0;
81 }
82 ddi_prop_free(ptr);
83 }
84 }
85
86 /*
87 * Function : cpqary3_tick_hdlr
88 * Description : This routine is called once in 60 seconds to detect any
89 * command that is pending with the controller and has
90 * timed out.
91 * Once invoked, it re-initializes itself such that it is
92 * invoked after an interval of 60 seconds.
93 * Called By : kernel
94 * Parameters : per_controller
95 * Calls : None
96 * Return Values: None
97 */
98 void
cpqary3_tick_hdlr(void * arg)99 cpqary3_tick_hdlr(void *arg)
100 {
101 clock_t cpqary3_lbolt;
102 clock_t cpqary3_ticks;
103 cpqary3_t *ctlr;
104 cpqary3_pkt_t *pktp;
105 struct scsi_pkt *scsi_pktp;
106 cpqary3_cmdpvt_t *local;
107 volatile CfgTable_t *ctp;
108 uint32_t i;
109 uint32_t no_cmds = 0;
110
111 /*
112 * The per-controller shall be passed as argument.
113 * Read the HeartBeat of the controller.
114 * if the current heartbeat is the same as the one recorded earlier,
115 * the f/w has locked up!!!
116 */
117
118 if (NULL == (ctlr = (cpqary3_t *)arg))
119 return;
120
121 ctp = (CfgTable_t *)ctlr->ct;
122
123 /* CONTROLLER_LOCKUP */
124 if (ctlr->heartbeat == DDI_GET32(ctlr, &ctp->HeartBeat)) {
125 if (ctlr->lockup_logged == CPQARY3_FALSE) {
126 cmn_err(CE_WARN, "CPQary3 : "
127 "%s HBA firmware Locked !!!", ctlr->hba_name);
128 cmn_err(CE_WARN, "CPQary3 : "
129 "Please reboot the system");
130 cpqary3_intr_onoff(ctlr, CPQARY3_INTR_DISABLE);
131 if (ctlr->host_support & 0x4)
132 cpqary3_lockup_intr_onoff(ctlr,
133 CPQARY3_LOCKUP_INTR_DISABLE);
134 ctlr->controller_lockup = CPQARY3_TRUE;
135 ctlr->lockup_logged = CPQARY3_TRUE;
136 }
137 }
138 /* CONTROLLER_LOCKUP */
139 no_cmds = (uint32_t)((ctlr->ctlr_maxcmds / 3) *
140 NO_OF_CMDLIST_IN_A_BLK);
141 mutex_enter(&ctlr->sw_mutex);
142
143 for (i = 0; i < no_cmds; i++) {
144 local = &ctlr->cmdmemlistp->pool[i];
145 ASSERT(local != NULL);
146 pktp = MEM2PVTPKT(local);
147
148 if (!pktp)
149 continue;
150
151 if ((local->cmdpvt_flag == CPQARY3_TIMEOUT) ||
152 (local->cmdpvt_flag == CPQARY3_RESET)) {
153 continue;
154 }
155
156 if (local->occupied == CPQARY3_OCCUPIED) {
157 scsi_pktp = pktp->scsi_cmd_pkt;
158 cpqary3_lbolt = ddi_get_lbolt();
159 if ((scsi_pktp) && (scsi_pktp->pkt_time)) {
160 cpqary3_ticks = cpqary3_lbolt -
161 pktp->cmd_start_time;
162
163 if ((drv_hztousec(cpqary3_ticks)/1000000) >
164 scsi_pktp->pkt_time) {
165 scsi_pktp->pkt_reason = CMD_TIMEOUT;
166 scsi_pktp->pkt_statistics =
167 STAT_TIMEOUT;
168 scsi_pktp->pkt_state = STATE_GOT_BUS |
169 STATE_GOT_TARGET | STATE_SENT_CMD;
170 local->cmdpvt_flag = CPQARY3_TIMEOUT;
171
172 /* This should always be the case */
173 if (scsi_pktp->pkt_comp) {
174 mutex_exit(&ctlr->sw_mutex);
175 (*scsi_pktp->pkt_comp)
176 (scsi_pktp);
177 mutex_enter(&ctlr->sw_mutex);
178 continue;
179 }
180 }
181 }
182 }
183 }
184
185 ctlr->heartbeat = DDI_GET32(ctlr, &ctp->HeartBeat);
186 mutex_exit(&ctlr->sw_mutex);
187 ctlr->tick_tmout_id = timeout(cpqary3_tick_hdlr,
188 (caddr_t)ctlr, drv_usectohz(CPQARY3_TICKTMOUT_VALUE));
189 }
190
191 /*
192 * Function : cpqary3_init_ctlr_resource
193 * Description : This routine initializes the command list, initializes
194 * the controller, enables the interrupt.
195 * Called By : cpqary3_attach()
196 * Parameters : per_controller
197 * Calls : cpqary3_init_ctlr(), cpqary3_meminit(),
198 * cpqary3_intr_onoff(),
199 * Return Values: SUCCESS / FAILURE
200 * [ Shall return failure if any of the mandatory
201 * initializations / setup of resources fail ]
202 */
203 uint16_t
cpqary3_init_ctlr_resource(cpqary3_t * ctlr)204 cpqary3_init_ctlr_resource(cpqary3_t *ctlr)
205 {
206 #ifdef CPQARY3_DEBUG_MEM
207 int8_t i = 0;
208 #endif
209
210 /*
211 * Initialize the Controller
212 * Alocate Memory Pool for driver supported number of Commands
213 * return if not successful
214 * Allocate target structure for controller and initialize the same
215 * Detect all existing targets and allocate target structure for each
216 * Determine geometry for all existing targets
217 * Initialize the condition variables
218 */
219
220 RETURN_FAILURE_IF_NULL(ctlr);
221
222 if (CPQARY3_FAILURE == cpqary3_init_ctlr(ctlr))
223 return ((CPQARY3_FAILURE));
224
225 if (CPQARY3_FAILURE == cpqary3_meminit(ctlr))
226 return ((CPQARY3_FAILURE));
227
228
229 #ifdef CPQARY3_DEBUG_MEM
230 /*
231 * This code is in place to test the memory management of this driver.
232 * This block of code allocates and de-allocates memory as many number
233 * of times as given in the for loop.
234 * After the for loop is executed, it returns a failure, which in turn
235 * would result in attach being failed.
236 */
237 cmn_err(CE_CONT, "CPQary3 : _init_ctlr_resource : Testing memory \n");
238 for (i = 0; i < 15; i++) {
239 if (CPQARY3_SUCCESS != cpqary3_meminit(ctlr)) {
240 cmn_err(CE_CONT, "CPQary3 : meminit failed : "
241 "attempt %d \n", i);
242 return (CPQARY3_FAILURE);
243 }
244 cmn_err(CE_CONT,
245 "CPQary3 : INIT successful : attempt %d \n", i);
246 cpqary3_memfini(ctlr, CPQARY3_MEMLIST_DONE |
247 CPQARY3_PHYCTGS_DONE | CPQARY3_CMDMEM_DONE);
248 cmn_err(CE_CONT,
249 "CPQary3 : FINI successful : attempt %d \n", i);
250 }
251 return (CPQARY3_FAILURE);
252 #endif
253
254 ctlr->cpqary3_tgtp[CTLR_SCSI_ID] = MEM_ZALLOC(sizeof (cpqary3_tgt_t));
255 if (!(ctlr->cpqary3_tgtp[CTLR_SCSI_ID])) {
256 cmn_err(CE_WARN, "CPQary3: Target Initialization Failed");
257 cpqary3_memfini(ctlr, CPQARY3_MEMLIST_DONE |
258 CPQARY3_PHYCTGS_DONE | CPQARY3_CMDMEM_DONE);
259 return (CPQARY3_FAILURE);
260 }
261 ctlr->cpqary3_tgtp[CTLR_SCSI_ID]->type = CPQARY3_TARGET_CTLR;
262
263 cpqary3_intr_onoff(ctlr, CPQARY3_INTR_DISABLE);
264
265 /*
266 * Initialize all condition variables :
267 * for the immediate call back
268 * for the disable noe
269 * for fulsh cache
270 * for probe device
271 */
272
273 cv_init(&ctlr->cv_immediate_wait, NULL, CV_DRIVER, NULL);
274 cv_init(&ctlr->cv_noe_wait, NULL, CV_DRIVER, NULL);
275 cv_init(&ctlr->cv_flushcache_wait, NULL, CV_DRIVER, NULL);
276 cv_init(&ctlr->cv_abort_wait, NULL, CV_DRIVER, NULL);
277 cv_init(&ctlr->cv_ioctl_wait, NULL, CV_DRIVER, NULL);
278
279 return (CPQARY3_SUCCESS);
280 }
281
282 /*
283 * Function : cpqary3_target_geometry
284 * Description : This function returns the geometry for the target.
285 * Called By : cpqary3_getcap()
286 * Parameters : Target SCSI address
287 * Calls : None
288 * Return Values: Device Geometry
289 */
290 int
cpqary3_target_geometry(struct scsi_address * sa)291 cpqary3_target_geometry(struct scsi_address *sa)
292 {
293 cpqary3_t *ctlr = SA2CTLR(sa);
294 cpqary3_tgt_t *tgtp = ctlr->cpqary3_tgtp[SA2TGT(sa)];
295
296 /*
297 * The target CHS are stored in the per-target structure
298 * during attach time. Use these values
299 */
300 return ((tgtp->properties.drive.heads << 16) |
301 tgtp->properties.drive.sectors);
302 }
303
304 /*
305 * Function : cpqary3_synccmd_alloc
306 * Description : This function allocates the DMA buffer for the commands
307 * Called By : cpqary3_ioctl_send_bmiccmd(),
308 * cpqary3_ioctl_send_scsicmd()
309 * cpqary3_send_abortcmd(), cpqary3_flush_cache(),
310 * cpqary3_probe4LVs(), cpqary3_probe4Tapes(),
311 * cpqary3_detect_target_geometry()
312 * Parameters : per_controller, buffer size
313 * Calls : cpqary3_alloc_phyctgs_mem(), cpqary3_cmdlist_occupy()
314 * Return Values: memp
315 */
316 cpqary3_cmdpvt_t *
cpqary3_synccmd_alloc(cpqary3_t * cpqary3p,size_t bufsz)317 cpqary3_synccmd_alloc(cpqary3_t *cpqary3p, size_t bufsz)
318 {
319 cpqary3_private_t *cmddmah = NULL;
320 uint32_t dmabufpa = 0; /* XXX 32-bit pa? */
321 cpqary3_cmdpvt_t *memp = NULL;
322
323 /* first, allocate any necessary dma buffers */
324 if (bufsz > 0) {
325 cpqary3_phyctg_t *dmah = NULL;
326 caddr_t dmabufva = NULL;
327
328 /* first, allocate the command's dma handle */
329 cmddmah = (cpqary3_private_t *)MEM_ZALLOC(sizeof (*cmddmah));
330 if (cmddmah == NULL) {
331 cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
332 "no memory for cmddmah");
333 return (NULL);
334 }
335
336 /* next, allocate dma handle */
337 dmah = (cpqary3_phyctg_t *)MEM_ZALLOC(sizeof (*dmah));
338 if (dmah == NULL) {
339 MEM_SFREE(cmddmah, sizeof (*cmddmah));
340 cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
341 "no memory for dmah");
342 return (NULL);
343 }
344 /* now, allocate dma buffer */
345 dmabufva = cpqary3_alloc_phyctgs_mem(cpqary3p, bufsz,
346 &dmabufpa, dmah);
347 if (dmabufva == NULL) {
348 MEM_SFREE(cmddmah, sizeof (*cmddmah));
349 cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
350 "no memory for dma buf");
351 return (NULL);
352 }
353 bzero(dmabufva, bufsz);
354
355 /* attach dma buffer to command dma handle */
356 cmddmah->sg = dmabufva;
357 cmddmah->phyctgp = dmah;
358 }
359
360 /* next, allocate a command packet */
361 memp = cpqary3_cmdlist_occupy(cpqary3p);
362 if (memp == NULL) {
363 if (cmddmah != NULL) {
364 cpqary3_free_phyctgs_mem(cmddmah->phyctgp,
365 CPQARY3_FREE_PHYCTG_MEM);
366 MEM_SFREE(cmddmah, sizeof (*cmddmah));
367 }
368 cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
369 "cannot get free command");
370 return (NULL);
371 }
372 memp->cmdpvt_flag = 0;
373 memp->cmdlist_memaddr->Header.Tag.drvinfo_n_err =
374 CPQARY3_SYNCCMD_SUCCESS;
375
376 /* attach dma resources to command */
377 memp->driverdata = cmddmah;
378 memp->cmdlist_memaddr->SG[0].Addr = dmabufpa;
379 memp->cmdlist_memaddr->SG[0].Len = (uint32_t)bufsz;
380
381 /* done */
382 return (memp);
383 }
384
385 /*
386 * Function : cpqary3_synccmd_cleanup
387 * Description : This routine cleans up the command
388 * Called By : cpqary3_process_pkt(), cpqary3_synccmd_free()
389 * Parameters : per_command_memory
390 * Calls : cpqary3_free_phyctgs_mem(), cpqary3_cmdlist_release()
391 * Return Values: none
392 */
393 void
cpqary3_synccmd_cleanup(cpqary3_cmdpvt_t * memp)394 cpqary3_synccmd_cleanup(cpqary3_cmdpvt_t *memp)
395 {
396 /*
397 * ordinary users should not call this routine
398 * (use cpqary3_synccmd_free() instead). this is
399 * for use ONLY by cpqary3_synccmd_free() and
400 * cpqary3_process_pkt().
401 */
402
403 if (memp->driverdata != NULL) {
404 /* free dma resources */
405 cpqary3_free_phyctgs_mem(memp->driverdata->phyctgp,
406 CPQARY3_FREE_PHYCTG_MEM);
407 MEM_SFREE(memp->driverdata, sizeof (cpqary3_private_t));
408 memp->driverdata = NULL;
409 }
410 /* release command */
411 memp->cmdpvt_flag = 0;
412 cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX);
413 }
414
415 /*
416 * Function : cpqary3_synccmd_free
417 * Description : This routine frees the command and the
418 * associated resources.
419 * Called By : cpqary3_ioctl_send_bmiccmd(),
420 * cpqary3_ioctl_send_scsicmd()
421 * cpqary3_send_abortcmd(), cpqary3_flush_cache(),
422 * cpqary3_probe4LVs(), cpqary3_probe4Tapes(),
423 * cpqary3_detect_target_geometry()
424 * Parameters : per_controller, per_command_memory
425 * Calls : cpqary3_synccmd_cleanup()
426 * Return Values: NONE
427 */
428 void
cpqary3_synccmd_free(cpqary3_t * cpqary3p,cpqary3_cmdpvt_t * memp)429 cpqary3_synccmd_free(cpqary3_t *cpqary3p, cpqary3_cmdpvt_t *memp)
430 {
431 /*
432 * so, the user is done with this command packet.
433 * we have three possible scenarios here:
434 *
435 * 1) the command was never submitted to the controller
436 *
437 * or
438 *
439 * 2) the command has completed at the controller and has
440 * been fully processed by the interrupt processing
441 * mechanism and is no longer on the submitted or
442 * retrieve queues.
443 *
444 * or
445 *
446 * 3) the command is not yet complete at the controller,
447 * and/or hasn't made it through cpqary3_process_pkt()
448 * yet.
449 *
450 * For cases (1) and (2), we can go ahead and free the
451 * command and the associated resources. For case (3), we
452 * must mark the command as no longer needed, and let
453 * cpqary3_process_pkt() clean it up instead.
454 */
455
456 mutex_enter(&(cpqary3p->sw_mutex));
457 if (memp->cmdpvt_flag == CPQARY3_SYNC_SUBMITTED) {
458 /*
459 * command is still pending (case #3 above).
460 * mark the command as abandoned and let
461 * cpqary3_process_pkt() clean it up.
462 */
463 memp->cmdpvt_flag = CPQARY3_SYNC_TIMEOUT;
464 mutex_exit(&(cpqary3p->sw_mutex));
465 return;
466 }
467 memp->cmdpvt_flag = 0;
468 mutex_exit(&(cpqary3p->sw_mutex));
469
470 /*
471 * command was either never submitted or has completed
472 * (cases #1 and #2 above). so, clean it up.
473 */
474 cpqary3_synccmd_cleanup(memp);
475
476 /* done */
477 return;
478
479 } /* cpqary3_synccmd_free() */
480
481 /*
482 * Function : cpqary3_synccmd_send
483 * Description : This routine sends the command to the controller
484 * Called By : cpqary3_ioctl_send_bmiccmd(),
485 * cpqary3_ioctl_send_scsicmd()
486 * cpqary3_send_abortcmd(), cpqary3_flush_cache(),
487 * cpqary3_probe4LVs(), cpqary3_probe4Tapes(),
488 * cpqary3_detect_target_geometry()
489 * Parameters : per_controller, per_command_memory, timeout value,
490 * flag(wait for reply)
491 * Calls : cpqary3_submit(), cpqary3_add2submitted_cmdq()
492 * Return Values: SUCCESS / FAILURE
493 */
494 int
cpqary3_synccmd_send(cpqary3_t * cpqary3p,cpqary3_cmdpvt_t * memp,clock_t timeoutms,int flags)495 cpqary3_synccmd_send(cpqary3_t *cpqary3p, cpqary3_cmdpvt_t *memp,
496 clock_t timeoutms, int flags)
497 {
498 clock_t absto = 0; /* absolute timeout */
499 int waitsig = 0;
500 int rc = 0;
501 kcondvar_t *cv = 0;
502
503 /* compute absolute timeout, if necessary */
504 if (timeoutms > 0)
505 absto = ddi_get_lbolt() + drv_usectohz(timeoutms * 1000);
506
507 /* heed signals during wait? */
508 if (flags & CPQARY3_SYNCCMD_SEND_WAITSIG)
509 waitsig = 1;
510
511 /* acquire the sw mutex for our wait */
512 mutex_enter(&(cpqary3p->sw_mutex));
513
514 /* submit command to controller */
515 mutex_enter(&(cpqary3p->hw_mutex));
516
517 memp->cmdpvt_flag = CPQARY3_SYNC_SUBMITTED;
518 memp->cmdlist_memaddr->Header.Tag.drvinfo_n_err =
519 CPQARY3_SYNCCMD_SUCCESS;
520 if (EIO == cpqary3_submit(cpqary3p, memp->cmdlist_phyaddr)) {
521 mutex_exit(&(cpqary3p->hw_mutex));
522 mutex_exit(&(cpqary3p->sw_mutex));
523 rc = -1;
524 return (rc);
525 }
526 mutex_exit(&(cpqary3p->hw_mutex));
527
528 /* wait for command completion, timeout, or signal */
529 while (memp->cmdpvt_flag == CPQARY3_SYNC_SUBMITTED) {
530 kmutex_t *mt = &(cpqary3p->sw_mutex);
531
532 cv = &(cpqary3p->cv_ioctl_wait);
533 /* wait with the request behavior */
534 if (absto) {
535 clock_t crc;
536 if (waitsig) {
537 crc = cv_timedwait_sig(cv, mt, absto);
538 } else {
539 crc = cv_timedwait(cv, mt, absto);
540 }
541 if (crc > 0)
542 rc = 0;
543 else
544 rc = (-1);
545 } else {
546 if (waitsig) {
547 rc = cv_wait_sig(cv, mt);
548 if (rc > 0)
549 rc = 0;
550 else
551 rc = (-1);
552 } else {
553 cv_wait(cv, mt);
554 rc = 0;
555 }
556 }
557
558
559 /*
560 * if our wait was interrupted (timeout),
561 * then break here
562 */
563 if (rc) {
564 break;
565 }
566 }
567
568 /* our wait is done, so release the sw mutex */
569 mutex_exit(&(cpqary3p->sw_mutex));
570
571 /* return the results */
572 return (rc);
573 }
574
575 /*
576 * Function : cpqary3_detect_target_geometry
577 * Description : This function determines the geometry for all
578 * the existing targets for the controller.
579 * Called By : cpqary3_tgt_init()
580 * Parameters : per controller
581 * Calls : cpqary3_synccmd_alloc(), cpqary3_synccmd_send()
582 * cpqary3_synccmd_free()
583 * Return Values: SUCCESS / FAILURE
584 * [ Shall return failure only if Memory constraints exist
585 * or controller does not respond ]
586 */
587 int8_t
cpqary3_detect_target_geometry(cpqary3_t * ctlr)588 cpqary3_detect_target_geometry(cpqary3_t *ctlr)
589 {
590 int i;
591 int8_t ld_count = 0;
592 int8_t loop_cnt = 0;
593 IdLogDrive *idlogdrive;
594 CommandList_t *cmdlistp;
595 cpqary3_cmdpvt_t *cpqary3_cmdpvtp;
596
597 RETURN_FAILURE_IF_NULL(ctlr);
598
599 /*
600 * Occupy a Command List
601 * Allocate Memory for return data
602 * If error, RETURN 0.
603 * get the Request Block from the CommandList
604 * Fill in the Request Packet with the corresponding values
605 * Submit the Command and Poll for its completion
606 * If success, continue else RETURN 0
607 */
608
609 /* Sync Changes */
610 cpqary3_cmdpvtp = cpqary3_synccmd_alloc(ctlr, sizeof (IdLogDrive));
611 if (cpqary3_cmdpvtp == NULL)
612 return (CPQARY3_FAILURE);
613
614 cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
615 idlogdrive = (IdLogDrive *)cpqary3_cmdpvtp->driverdata->sg;
616 /* Sync Changes */
617
618
619 /* Update Cmd Header */
620 cmdlistp->Header.SGList = 1;
621 cmdlistp->Header.SGTotal = 1;
622 cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS;
623
624 /* Cmd Reques */
625 cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16;
626 cmdlistp->Request.CDB[0] = 0x26;
627 cmdlistp->Request.CDB[6] = BMIC_IDENTIFY_LOGICAL_DRIVE;
628 cmdlistp->Request.CDB[7] = (sizeof (IdLogDrive) >> 8) & 0xff;
629 cmdlistp->Request.CDB[8] = sizeof (IdLogDrive) & 0xff;
630 cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
631 cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
632 cmdlistp->Request.Type.Direction = CISS_XFER_READ;
633
634 /*
635 * For all the Targets that exist, issue an IDENTIFY LOGICAL DRIVE.
636 * That returns values which includes the dsired Geometry also.
637 * Update the Geometry in the per-target structure.
638 * NOTE : When the loop is executed for i=controller's SCSI ID, just
639 * increament by one so that we are talking to the next logical
640 * drive in our per-target structure.
641 */
642
643 /*
644 * Depending upon the value of the variable legacy_mapping
645 * set in cpqary3_attach(),
646 * the target mapping algorithm to be used by the driver is decided.
647 */
648
649 if (ctlr->legacy_mapping == 1) {
650 loop_cnt = ((ctlr->num_of_targets > CTLR_SCSI_ID) ?
651 (ctlr->num_of_targets + 1) : (ctlr->num_of_targets));
652
653 for (i = 0; i < loop_cnt; i++) {
654 if (i == CTLR_SCSI_ID) /* Go to Next logical target */
655 i++;
656
657 bzero(idlogdrive, sizeof (IdLogDrive));
658 cmdlistp->Request.CDB[1] =
659 ctlr->cpqary3_tgtp[i]->logical_id;
660
661 /* Always zero */
662 cmdlistp->Header.LUN.PhysDev.TargetId = 0;
663
664 /*
665 * Logical volume Id numbering scheme is as follows
666 * 0x00000, 0x00001, ... - for Direct Attached
667 * 0x10000, 0x10001, ... - If 1st Port of HBA is
668 * connected to MSA20 / MSA500
669 * 0x20000, 0x20001, ... - If 2nd Port of HBA is
670 * connected to MSA20 / MSA500
671 */
672 cmdlistp->Header.LUN.PhysDev.Bus =
673 (ctlr->cpqary3_tgtp[i]->logical_id) >> 16;
674 cmdlistp->Header.LUN.PhysDev.Mode =
675 (cmdlistp->Header.LUN.PhysDev.Bus > 0) ?
676 MASK_PERIPHERIAL_DEV_ADDR : PERIPHERIAL_DEV_ADDR;
677
678 /*
679 * Submit the command
680 * Poll for its completion
681 * If polling is not successful, something is wrong
682 * with the controler
683 * Return FAILURE (No point in continuing if h/w is
684 * faulty !!!)
685 */
686
687 /* PERF */
688 cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
689 /* PERF */
690
691 /* Sync Changes */
692 if (cpqary3_synccmd_send(ctlr, cpqary3_cmdpvtp, 90000,
693 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
694 /* Timed out */
695 cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
696 return (CPQARY3_FAILURE);
697 }
698 if ((cpqary3_cmdpvtp->
699 cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
700 CPQARY3_SYNCCMD_FAILURE) &&
701 (cpqary3_cmdpvtp->errorinfop->CommandStatus != 2)) {
702 DTRACE_PROBE1(id_logdrv_fail,
703 ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop);
704 cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
705 return (CPQARY3_FAILURE);
706 }
707 /* Sync Changes */
708
709 ctlr->cpqary3_tgtp[i]->properties.drive.heads =
710 idlogdrive->heads;
711 ctlr->cpqary3_tgtp[i]->properties.drive.sectors =
712 idlogdrive->sectors;
713
714 DTRACE_PROBE2(tgt_geometry_detect,
715 int, i, IdLogDrive *, idlogdrive);
716 }
717 } else {
718
719 /*
720 * Fix for QXCR1000446657: Logical drives are re numbered
721 * after deleting a Logical drive.
722 * introduced, new variable ld_count, which gets
723 * incremented when the Target ID is found.
724 * And for i=controller's SCSI ID and LDs with holes are found,
725 * we continue talking to
726 * the next logical drive in the per-target structure
727 */
728
729 for (i = 0; ld_count < ctlr->num_of_targets; i++) {
730 if (i == CTLR_SCSI_ID ||
731 ctlr->cpqary3_tgtp[i] == NULL)
732 /* Go to the Next logical target */
733 continue;
734 bzero(idlogdrive, sizeof (IdLogDrive));
735 cmdlistp->Request.CDB[1] =
736 ctlr->cpqary3_tgtp[i]->logical_id;
737 /* Always zero */
738 cmdlistp->Header.LUN.PhysDev.TargetId = 0;
739 /*
740 * Logical volume Id numbering scheme is as follows
741 * 0x00000, 0x00001, ... - for Direct Attached
742 * 0x10000, 0x10001, ... - If 1st Port of HBA is
743 * connected to MSA20 / MSA500
744 * 0x20000, 0x20001, ... - If 2nd Port of HBA is
745 * connected to MSA20 / MSA500
746 */
747 cmdlistp->Header.LUN.PhysDev.Bus =
748 (ctlr->cpqary3_tgtp[i]->logical_id) >> 16;
749 cmdlistp->Header.LUN.PhysDev.Mode =
750 (cmdlistp->Header.LUN.PhysDev.Bus > 0) ?
751 MASK_PERIPHERIAL_DEV_ADDR : PERIPHERIAL_DEV_ADDR;
752 /* PERF */
753 cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
754 /* PERF */
755
756 /*
757 * Submit the command
758 * Poll for its completion
759 * If polling is not successful, something is wrong
760 * with the controler
761 * Return FAILURE (No point in continuing if h/w is
762 * faulty !!!)
763 */
764
765 /* Sync Changes */
766 if (cpqary3_synccmd_send(ctlr, cpqary3_cmdpvtp, 90000,
767 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
768 /* Timed out */
769 cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
770 return (CPQARY3_FAILURE);
771 }
772 if ((cpqary3_cmdpvtp->
773 cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
774 CPQARY3_SYNCCMD_FAILURE) &&
775 (cpqary3_cmdpvtp->errorinfop->CommandStatus != 2)) {
776 DTRACE_PROBE1(id_logdrv_fail,
777 ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop);
778 cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
779 return (CPQARY3_FAILURE);
780 }
781 /* Sync Changes */
782
783 ctlr->cpqary3_tgtp[i]->properties.drive.heads =
784 idlogdrive->heads;
785 ctlr->cpqary3_tgtp[i]->properties.drive.sectors =
786 idlogdrive->sectors;
787
788 DTRACE_PROBE2(tgt_geometry_detect,
789 int, i, IdLogDrive *, idlogdrive);
790
791 ld_count++;
792 }
793 }
794
795 /* Sync Changes */
796 cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
797 /* Sync Changes */
798
799 return (CPQARY3_SUCCESS);
800 }
801