Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cam/ata/ata_pmp.c
39482 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2009 Alexander Motin <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer,
12
* without modification, immediately at the beginning of the file.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
31
#ifdef _KERNEL
32
#include <sys/systm.h>
33
#include <sys/kernel.h>
34
#include <sys/bio.h>
35
#include <sys/sysctl.h>
36
#include <sys/taskqueue.h>
37
#include <sys/lock.h>
38
#include <sys/mutex.h>
39
#include <sys/conf.h>
40
#include <sys/devicestat.h>
41
#include <sys/eventhandler.h>
42
#include <sys/malloc.h>
43
#include <sys/cons.h>
44
#include <geom/geom_disk.h>
45
#endif /* _KERNEL */
46
47
#ifndef _KERNEL
48
#include <stdio.h>
49
#include <string.h>
50
#endif /* _KERNEL */
51
52
#include <cam/cam.h>
53
#include <cam/cam_ccb.h>
54
#include <cam/cam_periph.h>
55
#include <cam/cam_xpt_periph.h>
56
#include <cam/cam_xpt_internal.h>
57
#include <cam/cam_sim.h>
58
59
#include <cam/ata/ata_all.h>
60
61
#ifdef _KERNEL
62
63
typedef enum {
64
PMP_STATE_NORMAL,
65
PMP_STATE_PORTS,
66
PMP_STATE_PM_QUIRKS_1,
67
PMP_STATE_PM_QUIRKS_2,
68
PMP_STATE_PM_QUIRKS_3,
69
PMP_STATE_PRECONFIG,
70
PMP_STATE_RESET,
71
PMP_STATE_CONNECT,
72
PMP_STATE_CHECK,
73
PMP_STATE_CLEAR,
74
PMP_STATE_CONFIG,
75
PMP_STATE_SCAN
76
} pmp_state;
77
78
typedef enum {
79
PMP_FLAG_SCTX_INIT = 0x200
80
} pmp_flags;
81
82
typedef enum {
83
PMP_CCB_PROBE = 0x01,
84
} pmp_ccb_state;
85
86
/* Offsets into our private area for storing information */
87
#define ccb_state ppriv_field0
88
#define ccb_bp ppriv_ptr1
89
90
struct pmp_softc {
91
SLIST_ENTRY(pmp_softc) links;
92
pmp_state state;
93
pmp_flags flags;
94
uint32_t pm_pid;
95
uint32_t pm_prv;
96
int pm_ports;
97
int pm_step;
98
int pm_try;
99
int found;
100
int reset;
101
int frozen;
102
int restart;
103
int events;
104
#define PMP_EV_RESET 1
105
#define PMP_EV_RESCAN 2
106
u_int caps;
107
struct task sysctl_task;
108
struct sysctl_ctx_list sysctl_ctx;
109
struct sysctl_oid *sysctl_tree;
110
};
111
112
static periph_init_t pmpinit;
113
static void pmpasync(void *callback_arg, uint32_t code,
114
struct cam_path *path, void *arg);
115
static void pmpsysctlinit(void *context, int pending);
116
static periph_ctor_t pmpregister;
117
static periph_dtor_t pmpcleanup;
118
static periph_start_t pmpstart;
119
static periph_oninv_t pmponinvalidate;
120
static void pmpdone(struct cam_periph *periph,
121
union ccb *done_ccb);
122
123
#ifndef PMP_DEFAULT_TIMEOUT
124
#define PMP_DEFAULT_TIMEOUT 30 /* Timeout in seconds */
125
#endif
126
127
#ifndef PMP_DEFAULT_RETRY
128
#define PMP_DEFAULT_RETRY 1
129
#endif
130
131
#ifndef PMP_DEFAULT_HIDE_SPECIAL
132
#define PMP_DEFAULT_HIDE_SPECIAL 1
133
#endif
134
135
static int pmp_retry_count = PMP_DEFAULT_RETRY;
136
static int pmp_default_timeout = PMP_DEFAULT_TIMEOUT;
137
static int pmp_hide_special = PMP_DEFAULT_HIDE_SPECIAL;
138
139
static SYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
140
"CAM Direct Access Disk driver");
141
SYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RWTUN,
142
&pmp_retry_count, 0, "Normal I/O retry count");
143
SYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RWTUN,
144
&pmp_default_timeout, 0, "Normal I/O timeout (in seconds)");
145
SYSCTL_INT(_kern_cam_pmp, OID_AUTO, hide_special, CTLFLAG_RWTUN,
146
&pmp_hide_special, 0, "Hide extra ports");
147
148
static struct periph_driver pmpdriver =
149
{
150
pmpinit, "pmp",
151
TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0,
152
CAM_PERIPH_DRV_EARLY
153
};
154
155
PERIPHDRIVER_DECLARE(pmp, pmpdriver);
156
157
static void
158
pmpinit(void)
159
{
160
cam_status status;
161
162
/*
163
* Install a global async callback. This callback will
164
* receive async callbacks like "new device found".
165
*/
166
status = xpt_register_async(AC_FOUND_DEVICE, pmpasync, NULL, NULL);
167
168
if (status != CAM_REQ_CMP) {
169
printf("pmp: Failed to attach master async callback "
170
"due to status 0x%x!\n", status);
171
}
172
}
173
174
static void
175
pmpfreeze(struct cam_periph *periph, int mask)
176
{
177
struct pmp_softc *softc = (struct pmp_softc *)periph->softc;
178
struct cam_path *dpath;
179
int i;
180
181
mask &= ~softc->frozen;
182
for (i = 0; i < 15; i++) {
183
if ((mask & (1 << i)) == 0)
184
continue;
185
if (xpt_create_path(&dpath, periph,
186
xpt_path_path_id(periph->path),
187
i, 0) == CAM_REQ_CMP) {
188
softc->frozen |= (1 << i);
189
xpt_acquire_device(dpath->device);
190
cam_freeze_devq(dpath);
191
xpt_free_path(dpath);
192
}
193
}
194
}
195
196
static void
197
pmprelease(struct cam_periph *periph, int mask)
198
{
199
struct pmp_softc *softc = (struct pmp_softc *)periph->softc;
200
struct cam_path *dpath;
201
int i;
202
203
mask &= softc->frozen;
204
for (i = 0; i < 15; i++) {
205
if ((mask & (1 << i)) == 0)
206
continue;
207
if (xpt_create_path(&dpath, periph,
208
xpt_path_path_id(periph->path),
209
i, 0) == CAM_REQ_CMP) {
210
softc->frozen &= ~(1 << i);
211
cam_release_devq(dpath, 0, 0, 0, FALSE);
212
xpt_release_device(dpath->device);
213
xpt_free_path(dpath);
214
}
215
}
216
}
217
218
static void
219
pmponinvalidate(struct cam_periph *periph)
220
{
221
struct cam_path *dpath;
222
int i;
223
224
/*
225
* De-register any async callbacks.
226
*/
227
xpt_register_async(0, pmpasync, periph, periph->path);
228
229
for (i = 0; i < 15; i++) {
230
if (xpt_create_path(&dpath, periph,
231
xpt_path_path_id(periph->path),
232
i, 0) == CAM_REQ_CMP) {
233
xpt_async(AC_LOST_DEVICE, dpath, NULL);
234
xpt_free_path(dpath);
235
}
236
}
237
pmprelease(periph, -1);
238
}
239
240
static void
241
pmpcleanup(struct cam_periph *periph)
242
{
243
struct pmp_softc *softc;
244
245
softc = (struct pmp_softc *)periph->softc;
246
247
cam_periph_unlock(periph);
248
249
/*
250
* If we can't free the sysctl tree, oh well...
251
*/
252
if ((softc->flags & PMP_FLAG_SCTX_INIT) != 0
253
&& sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
254
xpt_print(periph->path, "can't remove sysctl context\n");
255
}
256
257
free(softc, M_DEVBUF);
258
cam_periph_lock(periph);
259
}
260
261
static void
262
pmpasync(void *callback_arg, uint32_t code,
263
struct cam_path *path, void *arg)
264
{
265
struct cam_periph *periph;
266
struct pmp_softc *softc;
267
268
periph = (struct cam_periph *)callback_arg;
269
switch (code) {
270
case AC_FOUND_DEVICE:
271
{
272
struct ccb_getdev *cgd;
273
cam_status status;
274
275
cgd = (struct ccb_getdev *)arg;
276
if (cgd == NULL)
277
break;
278
279
if (cgd->protocol != PROTO_SATAPM)
280
break;
281
282
/*
283
* Allocate a peripheral instance for
284
* this device and start the probe
285
* process.
286
*/
287
status = cam_periph_alloc(pmpregister, pmponinvalidate,
288
pmpcleanup, pmpstart,
289
"pmp", CAM_PERIPH_BIO,
290
path, pmpasync,
291
AC_FOUND_DEVICE, cgd);
292
293
if (status != CAM_REQ_CMP
294
&& status != CAM_REQ_INPROG)
295
printf("pmpasync: Unable to attach to new device "
296
"due to status 0x%x\n", status);
297
break;
298
}
299
case AC_SCSI_AEN:
300
case AC_SENT_BDR:
301
case AC_BUS_RESET:
302
softc = (struct pmp_softc *)periph->softc;
303
cam_periph_async(periph, code, path, arg);
304
if (code == AC_SCSI_AEN)
305
softc->events |= PMP_EV_RESCAN;
306
else
307
softc->events |= PMP_EV_RESET;
308
if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL)
309
break;
310
xpt_hold_boot();
311
pmpfreeze(periph, softc->found);
312
if (code == AC_SENT_BDR || code == AC_BUS_RESET)
313
softc->found = 0; /* We have to reset everything. */
314
if (softc->state == PMP_STATE_NORMAL) {
315
if (cam_periph_acquire(periph) == 0) {
316
if (softc->pm_pid == 0x37261095 ||
317
softc->pm_pid == 0x38261095)
318
softc->state = PMP_STATE_PM_QUIRKS_1;
319
else
320
softc->state = PMP_STATE_PRECONFIG;
321
xpt_schedule(periph, CAM_PRIORITY_DEV);
322
} else {
323
pmprelease(periph, softc->found);
324
xpt_release_boot();
325
}
326
} else
327
softc->restart = 1;
328
break;
329
default:
330
cam_periph_async(periph, code, path, arg);
331
break;
332
}
333
}
334
335
static void
336
pmpsysctlinit(void *context, int pending)
337
{
338
struct cam_periph *periph;
339
struct pmp_softc *softc;
340
char tmpstr[32], tmpstr2[16];
341
342
periph = (struct cam_periph *)context;
343
if (cam_periph_acquire(periph) != 0)
344
return;
345
346
softc = (struct pmp_softc *)periph->softc;
347
snprintf(tmpstr, sizeof(tmpstr), "CAM PMP unit %d", periph->unit_number);
348
snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
349
350
sysctl_ctx_init(&softc->sysctl_ctx);
351
softc->flags |= PMP_FLAG_SCTX_INIT;
352
softc->sysctl_tree = SYSCTL_ADD_NODE_WITH_LABEL(&softc->sysctl_ctx,
353
SYSCTL_STATIC_CHILDREN(_kern_cam_pmp), OID_AUTO, tmpstr2,
354
CTLFLAG_RD | CTLFLAG_MPSAFE, 0, tmpstr, "device_index");
355
if (softc->sysctl_tree == NULL) {
356
printf("pmpsysctlinit: unable to allocate sysctl tree\n");
357
cam_periph_release(periph);
358
return;
359
}
360
361
cam_periph_release(periph);
362
}
363
364
static cam_status
365
pmpregister(struct cam_periph *periph, void *arg)
366
{
367
struct pmp_softc *softc;
368
struct ccb_getdev *cgd;
369
370
cgd = (struct ccb_getdev *)arg;
371
if (cgd == NULL) {
372
printf("pmpregister: no getdev CCB, can't register device\n");
373
return(CAM_REQ_CMP_ERR);
374
}
375
376
softc = (struct pmp_softc *)malloc(sizeof(*softc), M_DEVBUF,
377
M_NOWAIT|M_ZERO);
378
379
if (softc == NULL) {
380
printf("pmpregister: Unable to probe new device. "
381
"Unable to allocate softc\n");
382
return(CAM_REQ_CMP_ERR);
383
}
384
periph->softc = softc;
385
386
softc->pm_pid = ((uint32_t *)&cgd->ident_data)[0];
387
softc->pm_prv = ((uint32_t *)&cgd->ident_data)[1];
388
TASK_INIT(&softc->sysctl_task, 0, pmpsysctlinit, periph);
389
390
xpt_announce_periph(periph, NULL);
391
392
/*
393
* Add async callbacks for bus reset and
394
* bus device reset calls. I don't bother
395
* checking if this fails as, in most cases,
396
* the system will function just fine without
397
* them and the only alternative would be to
398
* not attach the device on failure.
399
*/
400
xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE |
401
AC_SCSI_AEN, pmpasync, periph, periph->path);
402
403
/*
404
* Take an exclusive refcount on the periph while pmpstart is called
405
* to finish the probe. The reference will be dropped in pmpdone at
406
* the end of probe.
407
*/
408
(void)cam_periph_acquire(periph);
409
xpt_hold_boot();
410
softc->state = PMP_STATE_PORTS;
411
softc->events = PMP_EV_RESCAN;
412
xpt_schedule(periph, CAM_PRIORITY_DEV);
413
414
return(CAM_REQ_CMP);
415
}
416
417
static void
418
pmpstart(struct cam_periph *periph, union ccb *start_ccb)
419
{
420
struct ccb_trans_settings cts;
421
struct ccb_ataio *ataio;
422
struct pmp_softc *softc;
423
struct cam_path *dpath;
424
int revision = 0;
425
426
softc = (struct pmp_softc *)periph->softc;
427
ataio = &start_ccb->ataio;
428
429
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("pmpstart\n"));
430
431
if (softc->restart) {
432
softc->restart = 0;
433
if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095)
434
softc->state = min(softc->state, PMP_STATE_PM_QUIRKS_1);
435
else
436
softc->state = min(softc->state, PMP_STATE_PRECONFIG);
437
}
438
/* Fetch user wanted device speed. */
439
if (softc->state == PMP_STATE_RESET ||
440
softc->state == PMP_STATE_CONNECT) {
441
if (xpt_create_path(&dpath, periph,
442
xpt_path_path_id(periph->path),
443
softc->pm_step, 0) == CAM_REQ_CMP) {
444
bzero(&cts, sizeof(cts));
445
xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE);
446
cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
447
cts.type = CTS_TYPE_USER_SETTINGS;
448
xpt_action((union ccb *)&cts);
449
if (cts.xport_specific.sata.valid & CTS_SATA_VALID_REVISION)
450
revision = cts.xport_specific.sata.revision;
451
xpt_free_path(dpath);
452
}
453
}
454
switch (softc->state) {
455
case PMP_STATE_PORTS:
456
cam_fill_ataio(ataio,
457
pmp_retry_count,
458
pmpdone,
459
/*flags*/CAM_DIR_NONE,
460
0,
461
/*data_ptr*/NULL,
462
/*dxfer_len*/0,
463
pmp_default_timeout * 1000);
464
ata_pm_read_cmd(ataio, 2, 15);
465
break;
466
467
case PMP_STATE_PM_QUIRKS_1:
468
case PMP_STATE_PM_QUIRKS_3:
469
cam_fill_ataio(ataio,
470
pmp_retry_count,
471
pmpdone,
472
/*flags*/CAM_DIR_NONE,
473
0,
474
/*data_ptr*/NULL,
475
/*dxfer_len*/0,
476
pmp_default_timeout * 1000);
477
ata_pm_read_cmd(ataio, 129, 15);
478
break;
479
480
case PMP_STATE_PM_QUIRKS_2:
481
cam_fill_ataio(ataio,
482
pmp_retry_count,
483
pmpdone,
484
/*flags*/CAM_DIR_NONE,
485
0,
486
/*data_ptr*/NULL,
487
/*dxfer_len*/0,
488
pmp_default_timeout * 1000);
489
ata_pm_write_cmd(ataio, 129, 15, softc->caps & ~0x1);
490
break;
491
492
case PMP_STATE_PRECONFIG:
493
/* Get/update host SATA capabilities. */
494
bzero(&cts, sizeof(cts));
495
xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
496
cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
497
cts.type = CTS_TYPE_CURRENT_SETTINGS;
498
xpt_action((union ccb *)&cts);
499
if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
500
softc->caps = cts.xport_specific.sata.caps;
501
else
502
softc->caps = 0;
503
cam_fill_ataio(ataio,
504
pmp_retry_count,
505
pmpdone,
506
/*flags*/CAM_DIR_NONE,
507
0,
508
/*data_ptr*/NULL,
509
/*dxfer_len*/0,
510
pmp_default_timeout * 1000);
511
ata_pm_write_cmd(ataio, 0x60, 15, 0x0);
512
break;
513
case PMP_STATE_RESET:
514
cam_fill_ataio(ataio,
515
pmp_retry_count,
516
pmpdone,
517
/*flags*/CAM_DIR_NONE,
518
0,
519
/*data_ptr*/NULL,
520
/*dxfer_len*/0,
521
pmp_default_timeout * 1000);
522
ata_pm_write_cmd(ataio, 2, softc->pm_step,
523
(revision << 4) |
524
((softc->found & (1 << softc->pm_step)) ? 0 : 1));
525
break;
526
case PMP_STATE_CONNECT:
527
cam_fill_ataio(ataio,
528
pmp_retry_count,
529
pmpdone,
530
/*flags*/CAM_DIR_NONE,
531
0,
532
/*data_ptr*/NULL,
533
/*dxfer_len*/0,
534
pmp_default_timeout * 1000);
535
ata_pm_write_cmd(ataio, 2, softc->pm_step,
536
(revision << 4));
537
break;
538
case PMP_STATE_CHECK:
539
cam_fill_ataio(ataio,
540
pmp_retry_count,
541
pmpdone,
542
/*flags*/CAM_DIR_NONE,
543
0,
544
/*data_ptr*/NULL,
545
/*dxfer_len*/0,
546
pmp_default_timeout * 1000);
547
ata_pm_read_cmd(ataio, 0, softc->pm_step);
548
break;
549
case PMP_STATE_CLEAR:
550
softc->reset = 0;
551
cam_fill_ataio(ataio,
552
pmp_retry_count,
553
pmpdone,
554
/*flags*/CAM_DIR_NONE,
555
0,
556
/*data_ptr*/NULL,
557
/*dxfer_len*/0,
558
pmp_default_timeout * 1000);
559
ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF);
560
break;
561
case PMP_STATE_CONFIG:
562
cam_fill_ataio(ataio,
563
pmp_retry_count,
564
pmpdone,
565
/*flags*/CAM_DIR_NONE,
566
0,
567
/*data_ptr*/NULL,
568
/*dxfer_len*/0,
569
pmp_default_timeout * 1000);
570
ata_pm_write_cmd(ataio, 0x60, 15, 0x07 |
571
((softc->caps & CTS_SATA_CAPS_H_AN) ? 0x08 : 0));
572
break;
573
default:
574
break;
575
}
576
xpt_action(start_ccb);
577
}
578
579
static void
580
pmpdone(struct cam_periph *periph, union ccb *done_ccb)
581
{
582
struct ccb_trans_settings cts;
583
struct pmp_softc *softc;
584
struct ccb_ataio *ataio;
585
struct cam_path *dpath;
586
uint32_t priority, res;
587
int i;
588
589
softc = (struct pmp_softc *)periph->softc;
590
ataio = &done_ccb->ataio;
591
592
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("pmpdone\n"));
593
594
priority = done_ccb->ccb_h.pinfo.priority;
595
596
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
597
if (cam_periph_error(done_ccb, 0, 0) == ERESTART) {
598
return;
599
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
600
cam_release_devq(done_ccb->ccb_h.path,
601
/*relsim_flags*/0,
602
/*reduction*/0,
603
/*timeout*/0,
604
/*getcount_only*/0);
605
}
606
goto done;
607
}
608
609
if (softc->restart) {
610
softc->restart = 0;
611
xpt_release_ccb(done_ccb);
612
if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095)
613
softc->state = min(softc->state, PMP_STATE_PM_QUIRKS_1);
614
else
615
softc->state = min(softc->state, PMP_STATE_PRECONFIG);
616
xpt_schedule(periph, priority);
617
return;
618
}
619
620
switch (softc->state) {
621
case PMP_STATE_PORTS:
622
softc->pm_ports = (ataio->res.lba_high << 24) +
623
(ataio->res.lba_mid << 16) +
624
(ataio->res.lba_low << 8) +
625
ataio->res.sector_count;
626
if (pmp_hide_special) {
627
/*
628
* This PMP declares 6 ports, while only 5 of them
629
* are real. Port 5 is a SEMB port, probing which
630
* causes timeouts if external SEP is not connected
631
* to PMP over I2C.
632
*/
633
if ((softc->pm_pid == 0x37261095 ||
634
softc->pm_pid == 0x38261095) &&
635
softc->pm_ports == 6)
636
softc->pm_ports = 5;
637
638
/*
639
* This PMP declares 7 ports, while only 5 of them
640
* are real. Port 5 is a fake "Config Disk" with
641
* 640 sectors size. Port 6 is a SEMB port.
642
*/
643
if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7)
644
softc->pm_ports = 5;
645
646
/*
647
* These PMPs have extra configuration port.
648
*/
649
if (softc->pm_pid == 0x57231095 ||
650
softc->pm_pid == 0x57331095 ||
651
softc->pm_pid == 0x57341095 ||
652
softc->pm_pid == 0x57441095)
653
softc->pm_ports--;
654
}
655
printf("%s%d: %d fan-out ports\n",
656
periph->periph_name, periph->unit_number,
657
softc->pm_ports);
658
if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095)
659
softc->state = PMP_STATE_PM_QUIRKS_1;
660
else
661
softc->state = PMP_STATE_PRECONFIG;
662
xpt_release_ccb(done_ccb);
663
xpt_schedule(periph, priority);
664
return;
665
666
case PMP_STATE_PM_QUIRKS_1:
667
softc->caps = (ataio->res.lba_high << 24) +
668
(ataio->res.lba_mid << 16) +
669
(ataio->res.lba_low << 8) +
670
ataio->res.sector_count;
671
if (softc->caps & 0x1)
672
softc->state = PMP_STATE_PM_QUIRKS_2;
673
else
674
softc->state = PMP_STATE_PRECONFIG;
675
xpt_release_ccb(done_ccb);
676
xpt_schedule(periph, priority);
677
return;
678
679
case PMP_STATE_PM_QUIRKS_2:
680
if (bootverbose)
681
softc->state = PMP_STATE_PM_QUIRKS_3;
682
else
683
softc->state = PMP_STATE_PRECONFIG;
684
xpt_release_ccb(done_ccb);
685
xpt_schedule(periph, priority);
686
return;
687
688
case PMP_STATE_PM_QUIRKS_3:
689
res = (ataio->res.lba_high << 24) +
690
(ataio->res.lba_mid << 16) +
691
(ataio->res.lba_low << 8) +
692
ataio->res.sector_count;
693
printf("%s%d: Disabling SiI3x26 R_OK in GSCR_POLL: %x->%x\n",
694
periph->periph_name, periph->unit_number, softc->caps, res);
695
softc->state = PMP_STATE_PRECONFIG;
696
xpt_release_ccb(done_ccb);
697
xpt_schedule(periph, priority);
698
return;
699
700
case PMP_STATE_PRECONFIG:
701
softc->pm_step = 0;
702
softc->state = PMP_STATE_RESET;
703
softc->reset |= ~softc->found;
704
xpt_release_ccb(done_ccb);
705
xpt_schedule(periph, priority);
706
return;
707
case PMP_STATE_RESET:
708
softc->pm_step++;
709
if (softc->pm_step >= softc->pm_ports) {
710
softc->pm_step = 0;
711
cam_freeze_devq(periph->path);
712
cam_release_devq(periph->path,
713
RELSIM_RELEASE_AFTER_TIMEOUT,
714
/*reduction*/0,
715
/*timeout*/5,
716
/*getcount_only*/0);
717
softc->state = PMP_STATE_CONNECT;
718
}
719
xpt_release_ccb(done_ccb);
720
xpt_schedule(periph, priority);
721
return;
722
case PMP_STATE_CONNECT:
723
softc->pm_step++;
724
if (softc->pm_step >= softc->pm_ports) {
725
softc->pm_step = 0;
726
softc->pm_try = 0;
727
cam_freeze_devq(periph->path);
728
cam_release_devq(periph->path,
729
RELSIM_RELEASE_AFTER_TIMEOUT,
730
/*reduction*/0,
731
/*timeout*/10,
732
/*getcount_only*/0);
733
softc->state = PMP_STATE_CHECK;
734
}
735
xpt_release_ccb(done_ccb);
736
xpt_schedule(periph, priority);
737
return;
738
case PMP_STATE_CHECK:
739
res = (ataio->res.lba_high << 24) +
740
(ataio->res.lba_mid << 16) +
741
(ataio->res.lba_low << 8) +
742
ataio->res.sector_count;
743
if (((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) ||
744
(res & 0x600) != 0) {
745
if (bootverbose) {
746
printf("%s%d: port %d status: %08x\n",
747
periph->periph_name, periph->unit_number,
748
softc->pm_step, res);
749
}
750
/* Report device speed if it is online. */
751
if ((res & 0xf0f) == 0x103 &&
752
xpt_create_path(&dpath, periph,
753
xpt_path_path_id(periph->path),
754
softc->pm_step, 0) == CAM_REQ_CMP) {
755
bzero(&cts, sizeof(cts));
756
xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE);
757
cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
758
cts.type = CTS_TYPE_CURRENT_SETTINGS;
759
cts.xport_specific.sata.revision = (res & 0x0f0) >> 4;
760
cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION;
761
cts.xport_specific.sata.caps = softc->caps &
762
(CTS_SATA_CAPS_H_PMREQ |
763
CTS_SATA_CAPS_H_DMAAA |
764
CTS_SATA_CAPS_H_AN);
765
cts.xport_specific.sata.valid |= CTS_SATA_VALID_CAPS;
766
xpt_action((union ccb *)&cts);
767
xpt_free_path(dpath);
768
}
769
softc->found |= (1 << softc->pm_step);
770
softc->pm_step++;
771
} else {
772
if (softc->pm_try < 10) {
773
cam_freeze_devq(periph->path);
774
cam_release_devq(periph->path,
775
RELSIM_RELEASE_AFTER_TIMEOUT,
776
/*reduction*/0,
777
/*timeout*/10,
778
/*getcount_only*/0);
779
softc->pm_try++;
780
} else {
781
if (bootverbose) {
782
printf("%s%d: port %d status: %08x\n",
783
periph->periph_name, periph->unit_number,
784
softc->pm_step, res);
785
}
786
softc->found &= ~(1 << softc->pm_step);
787
if (xpt_create_path(&dpath, periph,
788
done_ccb->ccb_h.path_id,
789
softc->pm_step, 0) == CAM_REQ_CMP) {
790
xpt_async(AC_LOST_DEVICE, dpath, NULL);
791
xpt_free_path(dpath);
792
}
793
softc->pm_step++;
794
}
795
}
796
if (softc->pm_step >= softc->pm_ports) {
797
if (softc->reset & softc->found) {
798
cam_freeze_devq(periph->path);
799
cam_release_devq(periph->path,
800
RELSIM_RELEASE_AFTER_TIMEOUT,
801
/*reduction*/0,
802
/*timeout*/1000,
803
/*getcount_only*/0);
804
}
805
softc->state = PMP_STATE_CLEAR;
806
softc->pm_step = 0;
807
}
808
xpt_release_ccb(done_ccb);
809
xpt_schedule(periph, priority);
810
return;
811
case PMP_STATE_CLEAR:
812
softc->pm_step++;
813
if (softc->pm_step >= softc->pm_ports) {
814
softc->state = PMP_STATE_CONFIG;
815
softc->pm_step = 0;
816
}
817
xpt_release_ccb(done_ccb);
818
xpt_schedule(periph, priority);
819
return;
820
case PMP_STATE_CONFIG:
821
for (i = 0; i < softc->pm_ports; i++) {
822
union ccb *ccb;
823
824
if ((softc->found & (1 << i)) == 0)
825
continue;
826
if (xpt_create_path(&dpath, periph,
827
xpt_path_path_id(periph->path),
828
i, 0) != CAM_REQ_CMP) {
829
printf("pmpdone: xpt_create_path failed\n");
830
continue;
831
}
832
/* If we did hard reset to this device, inform XPT. */
833
if ((softc->reset & softc->found & (1 << i)) != 0)
834
xpt_async(AC_SENT_BDR, dpath, NULL);
835
/* If rescan requested, scan this device. */
836
if (softc->events & PMP_EV_RESCAN) {
837
ccb = xpt_alloc_ccb_nowait();
838
if (ccb == NULL) {
839
xpt_free_path(dpath);
840
goto done;
841
}
842
xpt_setup_ccb(&ccb->ccb_h, dpath, CAM_PRIORITY_XPT);
843
xpt_rescan(ccb);
844
} else
845
xpt_free_path(dpath);
846
}
847
break;
848
default:
849
break;
850
}
851
done:
852
xpt_release_ccb(done_ccb);
853
softc->state = PMP_STATE_NORMAL;
854
softc->events = 0;
855
xpt_release_boot();
856
pmprelease(periph, -1);
857
cam_periph_release_locked(periph);
858
}
859
860
#endif /* _KERNEL */
861
862